| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813 | // Copyright 2020 The Gogs Authors. All rights reserved.// Use of this source code is governed by a MIT-style// license that can be found in the LICENSE file.package dbimport (	"context"	"fmt"	"os"	"path/filepath"	"strings"	"testing"	"time"	"github.com/stretchr/testify/assert"	"github.com/stretchr/testify/require"	"gorm.io/gorm"	"gogs.io/gogs/internal/auth"	"gogs.io/gogs/internal/conf"	"gogs.io/gogs/internal/dbtest"	"gogs.io/gogs/internal/dbutil"	"gogs.io/gogs/internal/errutil"	"gogs.io/gogs/internal/osutil"	"gogs.io/gogs/internal/repoutil"	"gogs.io/gogs/internal/userutil"	"gogs.io/gogs/public")func TestUser_BeforeCreate(t *testing.T) {	now := time.Now()	db := &gorm.DB{		Config: &gorm.Config{			SkipDefaultTransaction: true,			NowFunc: func() time.Time {				return now			},		},	}	t.Run("CreatedUnix has been set", func(t *testing.T) {		user := &User{			CreatedUnix: 1,		}		_ = user.BeforeCreate(db)		assert.Equal(t, int64(1), user.CreatedUnix)		assert.Equal(t, int64(0), user.UpdatedUnix)	})	t.Run("CreatedUnix has not been set", func(t *testing.T) {		user := &User{}		_ = user.BeforeCreate(db)		assert.Equal(t, db.NowFunc().Unix(), user.CreatedUnix)		assert.Equal(t, db.NowFunc().Unix(), user.UpdatedUnix)	})}func TestUser_AfterFind(t *testing.T) {	now := time.Now()	db := &gorm.DB{		Config: &gorm.Config{			SkipDefaultTransaction: true,			NowFunc: func() time.Time {				return now			},		},	}	user := &User{		CreatedUnix: now.Unix(),		UpdatedUnix: now.Unix(),	}	_ = user.AfterFind(db)	assert.Equal(t, user.CreatedUnix, user.Created.Unix())	assert.Equal(t, user.UpdatedUnix, user.Updated.Unix())}func TestUsers(t *testing.T) {	if testing.Short() {		t.Skip()	}	t.Parallel()	tables := []interface{}{new(User), new(EmailAddress), new(Repository), new(Follow), new(PullRequest)}	db := &users{		DB: dbtest.NewDB(t, "users", tables...),	}	for _, tc := range []struct {		name string		test func(t *testing.T, db *users)	}{		{"Authenticate", usersAuthenticate},		{"ChangeUsername", usersChangeUsername},		{"Count", usersCount},		{"Create", usersCreate},		{"DeleteCustomAvatar", usersDeleteCustomAvatar},		{"GetByEmail", usersGetByEmail},		{"GetByID", usersGetByID},		{"GetByUsername", usersGetByUsername},		{"HasForkedRepository", usersHasForkedRepository},		{"IsUsernameUsed", usersIsUsernameUsed},		{"List", usersList},		{"ListFollowers", usersListFollowers},		{"ListFollowings", usersListFollowings},		{"Update", usersUpdate},		{"UseCustomAvatar", usersUseCustomAvatar},	} {		t.Run(tc.name, func(t *testing.T) {			t.Cleanup(func() {				err := clearTables(t, db.DB, tables...)				require.NoError(t, err)			})			tc.test(t, db)		})		if t.Failed() {			break		}	}}func usersAuthenticate(t *testing.T, db *users) {	ctx := context.Background()	password := "pa$$word"	alice, err := db.Create(ctx, "alice", "[email protected]",		CreateUserOptions{			Password: password,		},	)	require.NoError(t, err)	t.Run("user not found", func(t *testing.T) {		_, err := db.Authenticate(ctx, "bob", password, -1)		wantErr := auth.ErrBadCredentials{Args: map[string]interface{}{"login": "bob"}}		assert.Equal(t, wantErr, err)	})	t.Run("invalid password", func(t *testing.T) {		_, err := db.Authenticate(ctx, alice.Name, "bad_password", -1)		wantErr := auth.ErrBadCredentials{Args: map[string]interface{}{"login": alice.Name, "userID": alice.ID}}		assert.Equal(t, wantErr, err)	})	t.Run("via email and password", func(t *testing.T) {		user, err := db.Authenticate(ctx, alice.Email, password, -1)		require.NoError(t, err)		assert.Equal(t, alice.Name, user.Name)	})	t.Run("via username and password", func(t *testing.T) {		user, err := db.Authenticate(ctx, alice.Name, password, -1)		require.NoError(t, err)		assert.Equal(t, alice.Name, user.Name)	})	t.Run("login source mismatch", func(t *testing.T) {		_, err := db.Authenticate(ctx, alice.Email, password, 1)		gotErr := fmt.Sprintf("%v", err)		wantErr := ErrLoginSourceMismatch{args: map[string]interface{}{"actual": 0, "expect": 1}}.Error()		assert.Equal(t, wantErr, gotErr)	})	t.Run("via login source", func(t *testing.T) {		mockLoginSources := NewMockLoginSourcesStore()		mockLoginSources.GetByIDFunc.SetDefaultHook(func(ctx context.Context, id int64) (*LoginSource, error) {			mockProvider := NewMockProvider()			mockProvider.AuthenticateFunc.SetDefaultReturn(&auth.ExternalAccount{}, nil)			s := &LoginSource{				IsActived: true,				Provider:  mockProvider,			}			return s, nil		})		setMockLoginSourcesStore(t, mockLoginSources)		bob, err := db.Create(ctx, "bob", "[email protected]",			CreateUserOptions{				Password:    password,				LoginSource: 1,			},		)		require.NoError(t, err)		user, err := db.Authenticate(ctx, bob.Email, password, 1)		require.NoError(t, err)		assert.Equal(t, bob.Name, user.Name)	})	t.Run("new user via login source", func(t *testing.T) {		mockLoginSources := NewMockLoginSourcesStore()		mockLoginSources.GetByIDFunc.SetDefaultHook(func(ctx context.Context, id int64) (*LoginSource, error) {			mockProvider := NewMockProvider()			mockProvider.AuthenticateFunc.SetDefaultReturn(				&auth.ExternalAccount{					Name:  "cindy",					Email: "[email protected]",				},				nil,			)			s := &LoginSource{				IsActived: true,				Provider:  mockProvider,			}			return s, nil		})		setMockLoginSourcesStore(t, mockLoginSources)		user, err := db.Authenticate(ctx, "cindy", password, 1)		require.NoError(t, err)		assert.Equal(t, "cindy", user.Name)		user, err = db.GetByUsername(ctx, "cindy")		require.NoError(t, err)		assert.Equal(t, "[email protected]", user.Email)	})}func usersChangeUsername(t *testing.T, db *users) {	ctx := context.Background()	alice, err := db.Create(		ctx,		"alice",		"[email protected]",		CreateUserOptions{			Activated: true,		},	)	require.NoError(t, err)	t.Run("name not allowed", func(t *testing.T) {		err := db.ChangeUsername(ctx, alice.ID, "-")		wantErr := ErrNameNotAllowed{			args: errutil.Args{				"reason": "reserved",				"name":   "-",			},		}		assert.Equal(t, wantErr, err)	})	t.Run("name already exists", func(t *testing.T) {		bob, err := db.Create(			ctx,			"bob",			"[email protected]",			CreateUserOptions{				Activated: true,			},		)		require.NoError(t, err)		err = db.ChangeUsername(ctx, alice.ID, bob.Name)		wantErr := ErrUserAlreadyExist{			args: errutil.Args{				"name": bob.Name,			},		}		assert.Equal(t, wantErr, err)	})	tempRepositoryRoot := filepath.Join(os.TempDir(), "usersChangeUsername-tempRepositoryRoot")	conf.SetMockRepository(		t,		conf.RepositoryOpts{			Root: tempRepositoryRoot,		},	)	err = os.RemoveAll(tempRepositoryRoot)	require.NoError(t, err)	defer func() { _ = os.RemoveAll(tempRepositoryRoot) }()	tempServerAppDataPath := filepath.Join(os.TempDir(), "usersChangeUsername-tempServerAppDataPath")	conf.SetMockServer(		t,		conf.ServerOpts{			AppDataPath: tempServerAppDataPath,		},	)	err = os.RemoveAll(tempServerAppDataPath)	require.NoError(t, err)	defer func() { _ = os.RemoveAll(tempServerAppDataPath) }()	repo, err := NewReposStore(db.DB).Create(		ctx,		alice.ID,		CreateRepoOptions{			Name: "test-repo-1",		},	)	require.NoError(t, err)	// TODO: Use PullRequests.Create to replace SQL hack when the method is available.	err = db.Exec(`INSERT INTO pull_request (head_user_name) VALUES (?)`, alice.Name).Error	require.NoError(t, err)	err = db.Model(&User{}).Where("id = ?", alice.ID).Update("updated_unix", 0).Error	require.NoError(t, err)	err = os.MkdirAll(repoutil.UserPath(alice.Name), os.ModePerm)	require.NoError(t, err)	err = os.MkdirAll(repoutil.RepositoryLocalPath(repo.ID), os.ModePerm)	require.NoError(t, err)	err = os.MkdirAll(repoutil.RepositoryLocalWikiPath(repo.ID), os.ModePerm)	require.NoError(t, err)	// Make sure mock data is set up correctly	// TODO: Use PullRequests.GetByID to replace SQL hack when the method is available.	var headUserName string	err = db.Model(&PullRequest{}).Select("head_user_name").Row().Scan(&headUserName)	require.NoError(t, err)	assert.Equal(t, headUserName, alice.Name)	var updatedUnix int64	err = db.Model(&User{}).Select("updated_unix").Where("id = ?", alice.ID).Row().Scan(&updatedUnix)	require.NoError(t, err)	assert.Equal(t, int64(0), updatedUnix)	assert.True(t, osutil.IsExist(repoutil.UserPath(alice.Name)))	assert.True(t, osutil.IsExist(repoutil.RepositoryLocalPath(repo.ID)))	assert.True(t, osutil.IsExist(repoutil.RepositoryLocalWikiPath(repo.ID)))	const newUsername = "alice-new"	err = db.ChangeUsername(ctx, alice.ID, newUsername)	require.NoError(t, err)	// TODO: Use PullRequests.GetByID to replace SQL hack when the method is available.	err = db.Model(&PullRequest{}).Select("head_user_name").Row().Scan(&headUserName)	require.NoError(t, err)	assert.Equal(t, headUserName, newUsername)	assert.True(t, osutil.IsExist(repoutil.UserPath(newUsername)))	assert.False(t, osutil.IsExist(repoutil.UserPath(alice.Name)))	assert.False(t, osutil.IsExist(repoutil.RepositoryLocalPath(repo.ID)))	assert.False(t, osutil.IsExist(repoutil.RepositoryLocalWikiPath(repo.ID)))	alice, err = db.GetByID(ctx, alice.ID)	require.NoError(t, err)	assert.Equal(t, newUsername, alice.Name)	assert.Equal(t, db.NowFunc().Unix(), alice.UpdatedUnix)	// Change the cases of the username should just be fine	err = db.ChangeUsername(ctx, alice.ID, strings.ToUpper(newUsername))	require.NoError(t, err)	alice, err = db.GetByID(ctx, alice.ID)	require.NoError(t, err)	assert.Equal(t, strings.ToUpper(newUsername), alice.Name)}func usersCount(t *testing.T, db *users) {	ctx := context.Background()	// Has no user initially	got := db.Count(ctx)	assert.Equal(t, int64(0), got)	_, err := db.Create(ctx, "alice", "[email protected]", CreateUserOptions{})	require.NoError(t, err)	got = db.Count(ctx)	assert.Equal(t, int64(1), got)	// Create an organization shouldn't count	// TODO: Use Orgs.Create to replace SQL hack when the method is available.	org1, err := db.Create(ctx, "org1", "[email protected]", CreateUserOptions{})	require.NoError(t, err)	err = db.Exec(		dbutil.Quote("UPDATE %s SET type = ? WHERE id = ?", "user"),		UserTypeOrganization, org1.ID,	).Error	require.NoError(t, err)	got = db.Count(ctx)	assert.Equal(t, int64(1), got)}func usersCreate(t *testing.T, db *users) {	ctx := context.Background()	alice, err := db.Create(		ctx,		"alice",		"[email protected]",		CreateUserOptions{			Activated: true,		},	)	require.NoError(t, err)	t.Run("name not allowed", func(t *testing.T) {		_, err := db.Create(ctx, "-", "", CreateUserOptions{})		wantErr := ErrNameNotAllowed{			args: errutil.Args{				"reason": "reserved",				"name":   "-",			},		}		assert.Equal(t, wantErr, err)	})	t.Run("name already exists", func(t *testing.T) {		_, err := db.Create(ctx, alice.Name, "", CreateUserOptions{})		wantErr := ErrUserAlreadyExist{			args: errutil.Args{				"name": alice.Name,			},		}		assert.Equal(t, wantErr, err)	})	t.Run("email already exists", func(t *testing.T) {		_, err := db.Create(ctx, "bob", alice.Email, CreateUserOptions{})		wantErr := ErrEmailAlreadyUsed{			args: errutil.Args{				"email": alice.Email,			},		}		assert.Equal(t, wantErr, err)	})	user, err := db.GetByUsername(ctx, alice.Name)	require.NoError(t, err)	assert.Equal(t, db.NowFunc().Format(time.RFC3339), user.Created.UTC().Format(time.RFC3339))	assert.Equal(t, db.NowFunc().Format(time.RFC3339), user.Updated.UTC().Format(time.RFC3339))}func usersDeleteCustomAvatar(t *testing.T, db *users) {	ctx := context.Background()	alice, err := db.Create(ctx, "alice", "[email protected]", CreateUserOptions{})	require.NoError(t, err)	avatar, err := public.Files.ReadFile("img/avatar_default.png")	require.NoError(t, err)	avatarPath := userutil.CustomAvatarPath(alice.ID)	_ = os.Remove(avatarPath)	defer func() { _ = os.Remove(avatarPath) }()	err = db.UseCustomAvatar(ctx, alice.ID, avatar)	require.NoError(t, err)	// Make sure avatar is saved and the user flag is updated.	got := osutil.IsFile(avatarPath)	assert.True(t, got)	alice, err = db.GetByID(ctx, alice.ID)	require.NoError(t, err)	assert.True(t, alice.UseCustomAvatar)	// Delete avatar should remove the file and revert the user flag.	err = db.DeleteCustomAvatar(ctx, alice.ID)	require.NoError(t, err)	got = osutil.IsFile(avatarPath)	assert.False(t, got)	alice, err = db.GetByID(ctx, alice.ID)	require.NoError(t, err)	assert.False(t, alice.UseCustomAvatar)}func usersGetByEmail(t *testing.T, db *users) {	ctx := context.Background()	t.Run("empty email", func(t *testing.T) {		_, err := db.GetByEmail(ctx, "")		wantErr := ErrUserNotExist{args: errutil.Args{"email": ""}}		assert.Equal(t, wantErr, err)	})	t.Run("ignore organization", func(t *testing.T) {		// TODO: Use Orgs.Create to replace SQL hack when the method is available.		org, err := db.Create(ctx, "gogs", "[email protected]", CreateUserOptions{})		require.NoError(t, err)		err = db.Model(&User{}).Where("id", org.ID).UpdateColumn("type", UserTypeOrganization).Error		require.NoError(t, err)		_, err = db.GetByEmail(ctx, org.Email)		wantErr := ErrUserNotExist{args: errutil.Args{"email": org.Email}}		assert.Equal(t, wantErr, err)	})	t.Run("by primary email", func(t *testing.T) {		alice, err := db.Create(ctx, "alice", "[email protected]", CreateUserOptions{})		require.NoError(t, err)		_, err = db.GetByEmail(ctx, alice.Email)		wantErr := ErrUserNotExist{args: errutil.Args{"email": alice.Email}}		assert.Equal(t, wantErr, err)		// Mark user as activated		// TODO: Use UserEmails.Verify to replace SQL hack when the method is available.		err = db.Model(&User{}).Where("id", alice.ID).UpdateColumn("is_active", true).Error		require.NoError(t, err)		user, err := db.GetByEmail(ctx, alice.Email)		require.NoError(t, err)		assert.Equal(t, alice.Name, user.Name)	})	t.Run("by secondary email", func(t *testing.T) {		bob, err := db.Create(ctx, "bob", "[email protected]", CreateUserOptions{})		require.NoError(t, err)		// TODO: Use UserEmails.Create to replace SQL hack when the method is available.		email2 := "[email protected]"		err = db.Exec(`INSERT INTO email_address (uid, email) VALUES (?, ?)`, bob.ID, email2).Error		require.NoError(t, err)		_, err = db.GetByEmail(ctx, email2)		wantErr := ErrUserNotExist{args: errutil.Args{"email": email2}}		assert.Equal(t, wantErr, err)		// TODO: Use UserEmails.Verify to replace SQL hack when the method is available.		err = db.Exec(`UPDATE email_address SET is_activated = ? WHERE email = ?`, true, email2).Error		require.NoError(t, err)		user, err := db.GetByEmail(ctx, email2)		require.NoError(t, err)		assert.Equal(t, bob.Name, user.Name)	})}func usersGetByID(t *testing.T, db *users) {	ctx := context.Background()	alice, err := db.Create(ctx, "alice", "[email protected]", CreateUserOptions{})	require.NoError(t, err)	user, err := db.GetByID(ctx, alice.ID)	require.NoError(t, err)	assert.Equal(t, alice.Name, user.Name)	_, err = db.GetByID(ctx, 404)	wantErr := ErrUserNotExist{args: errutil.Args{"userID": int64(404)}}	assert.Equal(t, wantErr, err)}func usersGetByUsername(t *testing.T, db *users) {	ctx := context.Background()	alice, err := db.Create(ctx, "alice", "[email protected]", CreateUserOptions{})	require.NoError(t, err)	user, err := db.GetByUsername(ctx, alice.Name)	require.NoError(t, err)	assert.Equal(t, alice.Name, user.Name)	_, err = db.GetByUsername(ctx, "bad_username")	wantErr := ErrUserNotExist{args: errutil.Args{"name": "bad_username"}}	assert.Equal(t, wantErr, err)}func usersHasForkedRepository(t *testing.T, db *users) {	ctx := context.Background()	has := db.HasForkedRepository(ctx, 1, 1)	assert.False(t, has)	_, err := NewReposStore(db.DB).Create(		ctx,		1,		CreateRepoOptions{			Name:   "repo1",			ForkID: 1,		},	)	require.NoError(t, err)	has = db.HasForkedRepository(ctx, 1, 1)	assert.True(t, has)}func usersIsUsernameUsed(t *testing.T, db *users) {	ctx := context.Background()	alice, err := db.Create(ctx, "alice", "[email protected]", CreateUserOptions{})	require.NoError(t, err)	tests := []struct {		name          string		username      string		excludeUserID int64		want          bool	}{		{			name:          "no change",			username:      alice.Name,			excludeUserID: alice.ID,			want:          false,		},		{			name:          "change case",			username:      strings.ToUpper(alice.Name),			excludeUserID: alice.ID,			want:          false,		},		{			name:          "not used",			username:      "bob",			excludeUserID: alice.ID,			want:          false,		},		{			name:          "not used when not excluded",			username:      "bob",			excludeUserID: 0,			want:          false,		},		{			name:          "used when not excluded",			username:      alice.Name,			excludeUserID: 0,			want:          true,		},	}	for _, test := range tests {		t.Run(test.name, func(t *testing.T) {			got := db.IsUsernameUsed(ctx, test.username, test.excludeUserID)			assert.Equal(t, test.want, got)		})	}}func usersList(t *testing.T, db *users) {	ctx := context.Background()	alice, err := db.Create(ctx, "alice", "[email protected]", CreateUserOptions{})	require.NoError(t, err)	bob, err := db.Create(ctx, "bob", "[email protected]", CreateUserOptions{})	require.NoError(t, err)	// Create an organization shouldn't count	// TODO: Use Orgs.Create to replace SQL hack when the method is available.	org1, err := db.Create(ctx, "org1", "[email protected]", CreateUserOptions{})	require.NoError(t, err)	err = db.Exec(		dbutil.Quote("UPDATE %s SET type = ? WHERE id = ?", "user"),		UserTypeOrganization, org1.ID,	).Error	require.NoError(t, err)	got, err := db.List(ctx, 1, 1)	require.NoError(t, err)	require.Len(t, got, 1)	assert.Equal(t, alice.ID, got[0].ID)	got, err = db.List(ctx, 2, 1)	require.NoError(t, err)	require.Len(t, got, 1)	assert.Equal(t, bob.ID, got[0].ID)	got, err = db.List(ctx, 1, 3)	require.NoError(t, err)	require.Len(t, got, 2)	assert.Equal(t, alice.ID, got[0].ID)	assert.Equal(t, bob.ID, got[1].ID)}func usersListFollowers(t *testing.T, db *users) {	ctx := context.Background()	john, err := db.Create(ctx, "john", "[email protected]", CreateUserOptions{})	require.NoError(t, err)	got, err := db.ListFollowers(ctx, john.ID, 1, 1)	require.NoError(t, err)	assert.Empty(t, got)	alice, err := db.Create(ctx, "alice", "[email protected]", CreateUserOptions{})	require.NoError(t, err)	bob, err := db.Create(ctx, "bob", "[email protected]", CreateUserOptions{})	require.NoError(t, err)	followsStore := NewFollowsStore(db.DB)	err = followsStore.Follow(ctx, alice.ID, john.ID)	require.NoError(t, err)	err = followsStore.Follow(ctx, bob.ID, john.ID)	require.NoError(t, err)	// First page only has bob	got, err = db.ListFollowers(ctx, john.ID, 1, 1)	require.NoError(t, err)	require.Len(t, got, 1)	assert.Equal(t, bob.ID, got[0].ID)	// Second page only has alice	got, err = db.ListFollowers(ctx, john.ID, 2, 1)	require.NoError(t, err)	require.Len(t, got, 1)	assert.Equal(t, alice.ID, got[0].ID)}func usersListFollowings(t *testing.T, db *users) {	ctx := context.Background()	john, err := db.Create(ctx, "john", "[email protected]", CreateUserOptions{})	require.NoError(t, err)	got, err := db.ListFollowers(ctx, john.ID, 1, 1)	require.NoError(t, err)	assert.Empty(t, got)	alice, err := db.Create(ctx, "alice", "[email protected]", CreateUserOptions{})	require.NoError(t, err)	bob, err := db.Create(ctx, "bob", "[email protected]", CreateUserOptions{})	require.NoError(t, err)	followsStore := NewFollowsStore(db.DB)	err = followsStore.Follow(ctx, john.ID, alice.ID)	require.NoError(t, err)	err = followsStore.Follow(ctx, john.ID, bob.ID)	require.NoError(t, err)	// First page only has bob	got, err = db.ListFollowings(ctx, john.ID, 1, 1)	require.NoError(t, err)	require.Len(t, got, 1)	assert.Equal(t, bob.ID, got[0].ID)	// Second page only has alice	got, err = db.ListFollowings(ctx, john.ID, 2, 1)	require.NoError(t, err)	require.Len(t, got, 1)	assert.Equal(t, alice.ID, got[0].ID)}func usersUpdate(t *testing.T, db *users) {	ctx := context.Background()	alice, err := db.Create(ctx, "alice", "[email protected]", CreateUserOptions{})	require.NoError(t, err)	overLimitStr := strings.Repeat("a", 300)	opts := UpdateUserOptions{		FullName:        overLimitStr,		Website:         overLimitStr,		Location:        overLimitStr,		Description:     overLimitStr,		MaxRepoCreation: 1,	}	err = db.Update(ctx, alice.ID, opts)	require.NoError(t, err)	alice, err = db.GetByID(ctx, alice.ID)	require.NoError(t, err)	wantStr := strings.Repeat("a", 255)	assert.Equal(t, wantStr, alice.FullName)	assert.Equal(t, wantStr, alice.Website)	assert.Equal(t, wantStr, alice.Location)	assert.Equal(t, wantStr, alice.Description)	assert.Equal(t, 1, alice.MaxRepoCreation)	// Test empty values	opts = UpdateUserOptions{		FullName: "Alice John",		Website:  "https://gogs.io",	}	err = db.Update(ctx, alice.ID, opts)	require.NoError(t, err)	alice, err = db.GetByID(ctx, alice.ID)	require.NoError(t, err)	assert.Equal(t, opts.FullName, alice.FullName)	assert.Equal(t, opts.Website, alice.Website)	assert.Empty(t, alice.Location)	assert.Empty(t, alice.Description)	assert.Empty(t, alice.MaxRepoCreation)}func usersUseCustomAvatar(t *testing.T, db *users) {	ctx := context.Background()	alice, err := db.Create(ctx, "alice", "[email protected]", CreateUserOptions{})	require.NoError(t, err)	avatar, err := public.Files.ReadFile("img/avatar_default.png")	require.NoError(t, err)	avatarPath := userutil.CustomAvatarPath(alice.ID)	_ = os.Remove(avatarPath)	defer func() { _ = os.Remove(avatarPath) }()	err = db.UseCustomAvatar(ctx, alice.ID, avatar)	require.NoError(t, err)	// Make sure avatar is saved and the user flag is updated.	got := osutil.IsFile(avatarPath)	assert.True(t, got)	alice, err = db.GetByID(ctx, alice.ID)	require.NoError(t, err)	assert.True(t, alice.UseCustomAvatar)}func TestIsUsernameAllowed(t *testing.T) {	for name := range reservedUsernames {		t.Run(name, func(t *testing.T) {			assert.True(t, IsErrNameNotAllowed(isUsernameAllowed(name)))		})	}	for _, pattern := range reservedUsernamePatterns {		t.Run(pattern, func(t *testing.T) {			username := strings.ReplaceAll(pattern, "*", "alice")			assert.True(t, IsErrNameNotAllowed(isUsernameAllowed(username)))		})	}}
 |