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) playerSnapshots, err := repos.playerSnapshot.List(ctx, domain.NewListPlayerSnapshotsParams()) 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) playerSnapshots, err := repos.playerSnapshot.List(ctx, domain.NewListPlayerSnapshotsParams()) require.NoError(t, err) 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", func(t *testing.T) { t.Parallel() repos := newRepos(t) playerSnapshots, listPlayerSnapshotsErr := repos.playerSnapshot.List(ctx, domain.NewListPlayerSnapshotsParams()) require.NoError(t, listPlayerSnapshotsErr) require.NotEmpty(t, playerSnapshots) randPlayerSnapshot := playerSnapshots[0] tests := []struct { name string params func(t *testing.T) domain.ListPlayerSnapshotsParams assertPlayerSnapshots func( t *testing.T, params domain.ListPlayerSnapshotsParams, playerSnapshots domain.PlayerSnapshots, ) assertError func(t *testing.T, err error) assertTotal func(t *testing.T, params domain.ListPlayerSnapshotsParams, total int) }{ { name: "OK: default params", params: func(t *testing.T) domain.ListPlayerSnapshotsParams { t.Helper() return domain.NewListPlayerSnapshotsParams() }, assertPlayerSnapshots: func( t *testing.T, _ domain.ListPlayerSnapshotsParams, playerSnapshots domain.PlayerSnapshots, ) { t.Helper() 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()), ) })) }, assertError: func(t *testing.T, err error) { t.Helper() require.NoError(t, err) }, assertTotal: func(t *testing.T, _ domain.ListPlayerSnapshotsParams, total int) { t.Helper() assert.NotEmpty(t, total) }, }, { 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 }, assertPlayerSnapshots: func( t *testing.T, _ domain.ListPlayerSnapshotsParams, playerSnapshots domain.PlayerSnapshots, ) { t.Helper() 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 })) }, assertError: func(t *testing.T, err error) { t.Helper() require.NoError(t, err) }, assertTotal: func(t *testing.T, _ domain.ListPlayerSnapshotsParams, total int) { t.Helper() assert.NotEmpty(t, total) }, }, { 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 }, assertPlayerSnapshots: func( t *testing.T, _ domain.ListPlayerSnapshotsParams, playerSnapshots domain.PlayerSnapshots, ) { t.Helper() assert.NotEmpty(t, len(playerSnapshots)) assert.True(t, slices.IsSortedFunc(playerSnapshots, func(a, b domain.PlayerSnapshot) int { return cmp.Compare(a.ID(), b.ID()) })) }, assertError: func(t *testing.T, err error) { t.Helper() require.NoError(t, err) }, assertTotal: func(t *testing.T, _ domain.ListPlayerSnapshotsParams, total int) { t.Helper() assert.NotEmpty(t, total) }, }, { 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 }, assertPlayerSnapshots: func( t *testing.T, _ domain.ListPlayerSnapshotsParams, playerSnapshots domain.PlayerSnapshots, ) { t.Helper() 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 })) }, assertError: func(t *testing.T, err error) { t.Helper() require.NoError(t, err) }, assertTotal: func(t *testing.T, _ domain.ListPlayerSnapshotsParams, total int) { t.Helper() assert.NotEmpty(t, total) }, }, { name: fmt.Sprintf("OK: serverKeys=[%s]", randPlayerSnapshot.ServerKey()), params: func(t *testing.T) domain.ListPlayerSnapshotsParams { t.Helper() params := domain.NewListPlayerSnapshotsParams() require.NoError(t, params.SetServerKeys([]string{randPlayerSnapshot.ServerKey()})) return params }, assertPlayerSnapshots: func( t *testing.T, params domain.ListPlayerSnapshotsParams, playerSnapshots domain.PlayerSnapshots, ) { t.Helper() serverKeys := params.ServerKeys() for _, ps := range playerSnapshots { assert.True(t, slices.Contains(serverKeys, ps.ServerKey())) } }, assertError: func(t *testing.T, err error) { t.Helper() require.NoError(t, err) }, assertTotal: func(t *testing.T, _ domain.ListPlayerSnapshotsParams, total int) { t.Helper() assert.NotEmpty(t, total) }, }, { name: "OK: offset=1 limit=2", params: func(t *testing.T) domain.ListPlayerSnapshotsParams { t.Helper() params := domain.NewListPlayerSnapshotsParams() require.NoError(t, params.SetOffset(1)) require.NoError(t, params.SetLimit(2)) return params }, assertPlayerSnapshots: func( t *testing.T, params domain.ListPlayerSnapshotsParams, playerSnapshots domain.PlayerSnapshots, ) { t.Helper() assert.Len(t, playerSnapshots, params.Limit()) }, assertError: func(t *testing.T, err error) { t.Helper() require.NoError(t, err) }, assertTotal: func(t *testing.T, _ domain.ListPlayerSnapshotsParams, total int) { t.Helper() assert.NotEmpty(t, total) }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() params := tt.params(t) res, err := repos.playerSnapshot.List(ctx, params) tt.assertError(t, err) tt.assertPlayerSnapshots(t, params, res) }) } }) }