package adapter_test import ( "cmp" "context" "fmt" "slices" "testing" "time" "gitea.dwysokinski.me/twhelp/corev3/internal/domain" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func testPlayerSnapshotRepository(t *testing.T, newRepos func(t *testing.T) repositories) { t.Helper() ctx := context.Background() t.Run("Create", func(t *testing.T) { t.Parallel() const dateFormat = "2006-01-02" repos := newRepos(t) assertCreated := func(t *testing.T, params []domain.CreatePlayerSnapshotParams) { t.Helper() require.NotEmpty(t, params) res, err := repos.playerSnapshot.List(ctx, domain.NewListPlayerSnapshotsParams()) playerSnapshots := res.PlayerSnapshots() require.NoError(t, err) for i, p := range params { date := p.Date().Format(dateFormat) idx := slices.IndexFunc(playerSnapshots, func(ps domain.PlayerSnapshot) bool { return ps.ServerKey() == p.ServerKey() && ps.PlayerID() == p.PlayerID() && ps.Date().Format(dateFormat) == date }) require.GreaterOrEqualf(t, idx, 0, "params[%d] not found", i) playerSnapshot := playerSnapshots[idx] assert.Equalf(t, p.PlayerID(), playerSnapshot.PlayerID(), "params[%d]", i) assert.Equalf(t, p.ServerKey(), playerSnapshot.ServerKey(), "params[%d]", i) assert.Equalf(t, p.NumVillages(), playerSnapshot.NumVillages(), "params[%d]", i) assert.Equalf(t, p.Points(), playerSnapshot.Points(), "params[%d]", i) assert.Equalf(t, p.Rank(), playerSnapshot.Rank(), "params[%d]", i) assert.Equalf(t, p.TribeID(), playerSnapshot.TribeID(), "params[%d]", i) assert.Equalf(t, p.OD(), playerSnapshot.OD(), "params[%d]", i) assert.Equalf(t, date, playerSnapshot.Date().Format(dateFormat), "params[%d]", i) assert.WithinDurationf(t, time.Now(), playerSnapshot.CreatedAt(), time.Minute, "params[%d]", i) } } assertNoDuplicates := func(t *testing.T, params []domain.CreatePlayerSnapshotParams) { t.Helper() require.NotEmpty(t, params) res, err := repos.playerSnapshot.List(ctx, domain.NewListPlayerSnapshotsParams()) require.NoError(t, err) playerSnapshots := res.PlayerSnapshots() m := make(map[string][]int) for _, p := range params { key := fmt.Sprintf("%s-%d-%s", p.ServerKey(), p.PlayerID(), p.Date().Format(dateFormat)) for i, ps := range playerSnapshots { if ps.ServerKey() == p.ServerKey() && ps.PlayerID() == p.PlayerID() && ps.Date().Equal(p.Date()) { m[key] = append(m[key], i) } } } for key, indexes := range m { assert.Len(t, indexes, 1, key) } } t.Run("OK", func(t *testing.T) { t.Parallel() listPlayersParams := domain.NewListPlayersParams() require.NoError(t, listPlayersParams.SetDeleted(domain.NullBool{ V: false, Valid: true, })) require.NoError(t, listPlayersParams.SetLimit(domain.PlayerSnapshotListMaxLimit/2)) res, err := repos.player.List(ctx, listPlayersParams) require.NoError(t, err) players := res.Players() require.NotEmpty(t, players) date := time.Now() createParams, err := domain.NewCreatePlayerSnapshotParams(players, date) require.NoError(t, err) require.NoError(t, repos.playerSnapshot.Create(ctx, createParams...)) assertCreated(t, createParams) require.NoError(t, repos.playerSnapshot.Create(ctx, createParams...)) assertNoDuplicates(t, createParams) }) t.Run("OK: len(params) == 0", func(t *testing.T) { t.Parallel() require.NoError(t, repos.playerSnapshot.Create(ctx)) }) }) t.Run("List & ListWithRelations", func(t *testing.T) { t.Parallel() repos := newRepos(t) tests := []struct { name string params func(t *testing.T) domain.ListPlayerSnapshotsParams assertResult func( t *testing.T, params domain.ListPlayerSnapshotsParams, res domain.ListPlayerSnapshotsResult, ) assertError func(t *testing.T, err error) }{ { name: "OK: default params", params: func(t *testing.T) domain.ListPlayerSnapshotsParams { t.Helper() return domain.NewListPlayerSnapshotsParams() }, assertResult: func( t *testing.T, _ domain.ListPlayerSnapshotsParams, res domain.ListPlayerSnapshotsResult, ) { t.Helper() playerSnapshots := res.PlayerSnapshots() assert.NotEmpty(t, len(playerSnapshots)) assert.True(t, slices.IsSortedFunc(playerSnapshots, func(a, b domain.PlayerSnapshot) int { return cmp.Or( cmp.Compare(a.ServerKey(), b.ServerKey()), a.Date().Compare(b.Date()), cmp.Compare(a.ID(), b.ID()), ) })) assert.False(t, res.Self().IsZero()) assert.True(t, res.Next().IsZero()) }, }, { name: "OK: sort=[serverKey DESC, date DESC]", params: func(t *testing.T) domain.ListPlayerSnapshotsParams { t.Helper() params := domain.NewListPlayerSnapshotsParams() require.NoError(t, params.SetSort([]domain.PlayerSnapshotSort{ domain.PlayerSnapshotSortServerKeyDESC, domain.PlayerSnapshotSortDateDESC, })) return params }, assertResult: func( t *testing.T, _ domain.ListPlayerSnapshotsParams, res domain.ListPlayerSnapshotsResult, ) { t.Helper() playerSnapshots := res.PlayerSnapshots() assert.NotEmpty(t, len(playerSnapshots)) assert.True(t, slices.IsSortedFunc(playerSnapshots, func(a, b domain.PlayerSnapshot) int { return cmp.Or( cmp.Compare(a.ServerKey(), b.ServerKey()), a.Date().Compare(b.Date()), ) * -1 })) }, }, { name: "OK: sort=[id ASC]", params: func(t *testing.T) domain.ListPlayerSnapshotsParams { t.Helper() params := domain.NewListPlayerSnapshotsParams() require.NoError(t, params.SetSort([]domain.PlayerSnapshotSort{ domain.PlayerSnapshotSortIDASC, })) return params }, assertResult: func( t *testing.T, _ domain.ListPlayerSnapshotsParams, res domain.ListPlayerSnapshotsResult, ) { t.Helper() playerSnapshots := res.PlayerSnapshots() assert.NotEmpty(t, len(playerSnapshots)) assert.True(t, slices.IsSortedFunc(playerSnapshots, func(a, b domain.PlayerSnapshot) int { return cmp.Compare(a.ID(), b.ID()) })) }, }, { name: "OK: sort=[id DESC]", params: func(t *testing.T) domain.ListPlayerSnapshotsParams { t.Helper() params := domain.NewListPlayerSnapshotsParams() require.NoError(t, params.SetSort([]domain.PlayerSnapshotSort{ domain.PlayerSnapshotSortIDDESC, })) return params }, assertResult: func( t *testing.T, _ domain.ListPlayerSnapshotsParams, res domain.ListPlayerSnapshotsResult, ) { t.Helper() playerSnapshots := res.PlayerSnapshots() assert.NotEmpty(t, len(playerSnapshots)) assert.True(t, slices.IsSortedFunc(playerSnapshots, func(a, b domain.PlayerSnapshot) int { return cmp.Compare(a.ID(), b.ID()) * -1 })) }, }, { name: "OK: serverKeys", params: func(t *testing.T) domain.ListPlayerSnapshotsParams { t.Helper() params := domain.NewListPlayerSnapshotsParams() res, err := repos.playerSnapshot.List(ctx, params) require.NoError(t, err) require.NotEmpty(t, res.PlayerSnapshots()) randPlayerSnapshot := res.PlayerSnapshots()[0] require.NoError(t, params.SetServerKeys([]string{randPlayerSnapshot.ServerKey()})) return params }, assertResult: func( t *testing.T, params domain.ListPlayerSnapshotsParams, res domain.ListPlayerSnapshotsResult, ) { t.Helper() serverKeys := params.ServerKeys() playerSnapshots := res.PlayerSnapshots() assert.NotZero(t, playerSnapshots) for _, ps := range playerSnapshots { assert.True(t, slices.Contains(serverKeys, ps.ServerKey())) } }, }, { name: "OK: playerIDs serverKeys", params: func(t *testing.T) domain.ListPlayerSnapshotsParams { t.Helper() params := domain.NewListPlayerSnapshotsParams() res, err := repos.playerSnapshot.List(ctx, params) require.NoError(t, err) require.NotEmpty(t, res.PlayerSnapshots()) randPlayerSnapshot := res.PlayerSnapshots()[0] require.NoError(t, params.SetServerKeys([]string{randPlayerSnapshot.ServerKey()})) require.NoError(t, params.SetPlayerIDs([]int{randPlayerSnapshot.PlayerID()})) return params }, assertResult: func( t *testing.T, params domain.ListPlayerSnapshotsParams, res domain.ListPlayerSnapshotsResult, ) { t.Helper() serverKeys := params.ServerKeys() playerIDs := params.PlayerIDs() playerSnapshots := res.PlayerSnapshots() assert.NotZero(t, playerSnapshots) for _, ps := range playerSnapshots { assert.True(t, slices.Contains(serverKeys, ps.ServerKey())) assert.True(t, slices.Contains(playerIDs, ps.PlayerID())) } }, }, { name: "OK: cursor serverKeys sort=[id ASC]", params: func(t *testing.T) domain.ListPlayerSnapshotsParams { t.Helper() params := domain.NewListPlayerSnapshotsParams() res, err := repos.playerSnapshot.List(ctx, params) require.NoError(t, err) require.Greater(t, len(res.PlayerSnapshots()), 2) require.NoError(t, params.SetSort([]domain.PlayerSnapshotSort{domain.PlayerSnapshotSortIDASC})) require.NoError(t, params.SetServerKeys([]string{res.PlayerSnapshots()[1].ServerKey()})) cursor, err := res.PlayerSnapshots()[1].ToCursor() require.NoError(t, err) require.NoError(t, params.SetCursor(cursor)) return params }, assertResult: func(t *testing.T, params domain.ListPlayerSnapshotsParams, res domain.ListPlayerSnapshotsResult) { t.Helper() serverKeys := params.ServerKeys() playerSnapshots := res.PlayerSnapshots() assert.NotEmpty(t, len(playerSnapshots)) for _, ps := range playerSnapshots { assert.GreaterOrEqual(t, ps.ID(), params.Cursor().ID()) assert.True(t, slices.Contains(serverKeys, ps.ServerKey())) } assert.True(t, slices.IsSortedFunc(playerSnapshots, func(a, b domain.PlayerSnapshot) int { return cmp.Compare(a.ID(), b.ID()) })) }, }, { name: "OK: cursor sort=[serverKey ASC, id ASC]", params: func(t *testing.T) domain.ListPlayerSnapshotsParams { t.Helper() params := domain.NewListPlayerSnapshotsParams() require.NoError(t, params.SetSort([]domain.PlayerSnapshotSort{ domain.PlayerSnapshotSortServerKeyASC, domain.PlayerSnapshotSortIDASC, })) res, err := repos.playerSnapshot.List(ctx, params) require.NoError(t, err) require.Greater(t, len(res.PlayerSnapshots()), 2) cursor, err := res.PlayerSnapshots()[1].ToCursor() require.NoError(t, err) require.NoError(t, params.SetCursor(cursor)) return params }, assertResult: func(t *testing.T, params domain.ListPlayerSnapshotsParams, res domain.ListPlayerSnapshotsResult) { t.Helper() playerSnapshots := res.PlayerSnapshots() assert.NotEmpty(t, len(playerSnapshots)) assert.True(t, slices.IsSortedFunc(playerSnapshots, func(a, b domain.PlayerSnapshot) int { return cmp.Or( cmp.Compare(a.ServerKey(), b.ServerKey()), cmp.Compare(a.ID(), b.ID()), ) })) assert.GreaterOrEqual(t, playerSnapshots[0].ID(), params.Cursor().ID()) for _, ps := range playerSnapshots { assert.GreaterOrEqual(t, ps.ServerKey(), params.Cursor().ServerKey()) } }, }, { name: "OK: cursor sort=[serverKey DESC, id DESC]", params: func(t *testing.T) domain.ListPlayerSnapshotsParams { t.Helper() params := domain.NewListPlayerSnapshotsParams() require.NoError(t, params.SetSort([]domain.PlayerSnapshotSort{ domain.PlayerSnapshotSortServerKeyDESC, domain.PlayerSnapshotSortIDDESC, })) res, err := repos.playerSnapshot.List(ctx, params) require.NoError(t, err) require.Greater(t, len(res.PlayerSnapshots()), 2) cursor, err := res.PlayerSnapshots()[1].ToCursor() require.NoError(t, err) require.NoError(t, params.SetCursor(cursor)) return params }, assertResult: func(t *testing.T, params domain.ListPlayerSnapshotsParams, res domain.ListPlayerSnapshotsResult) { t.Helper() playerSnapshots := res.PlayerSnapshots() assert.NotEmpty(t, len(playerSnapshots)) assert.True(t, slices.IsSortedFunc(playerSnapshots, func(a, b domain.PlayerSnapshot) int { return cmp.Or( cmp.Compare(a.ServerKey(), b.ServerKey()), cmp.Compare(a.ID(), b.ID()), ) * -1 })) assert.LessOrEqual(t, playerSnapshots[0].ID(), params.Cursor().ID()) for _, ps := range playerSnapshots { assert.LessOrEqual(t, ps.ServerKey(), params.Cursor().ServerKey()) } }, }, { name: "OK: limit=2", params: func(t *testing.T) domain.ListPlayerSnapshotsParams { t.Helper() params := domain.NewListPlayerSnapshotsParams() require.NoError(t, params.SetLimit(2)) return params }, assertResult: func( t *testing.T, params domain.ListPlayerSnapshotsParams, res domain.ListPlayerSnapshotsResult, ) { t.Helper() assert.Len(t, res.PlayerSnapshots(), params.Limit()) assert.False(t, res.Self().IsZero()) assert.False(t, res.Next().IsZero()) }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() assertError := tt.assertError if assertError == nil { assertError = func(t *testing.T, err error) { t.Helper() require.NoError(t, err) } } params := tt.params(t) res, err := repos.playerSnapshot.List(ctx, params) assertError(t, err) tt.assertResult(t, params, res) resWithRelations, err := repos.playerSnapshot.ListWithRelations(ctx, params) assertError(t, err) require.Len(t, resWithRelations.PlayerSnapshots(), len(res.PlayerSnapshots())) for i, ps := range resWithRelations.PlayerSnapshots() { assert.Equal(t, res.PlayerSnapshots()[i], ps.PlayerSnapshot()) assert.Equal(t, ps.PlayerSnapshot().PlayerID(), ps.Player().ID()) assert.Equal(t, ps.PlayerSnapshot().TribeID(), ps.Tribe().V.ID()) assert.Equal(t, ps.PlayerSnapshot().TribeID() != 0, ps.Tribe().Valid) } }) } }) }