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 testTribeSnapshotRepository(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.CreateTribeSnapshotParams) { t.Helper() require.NotEmpty(t, params) tribeSnapshots, err := repos.tribeSnapshot.List(ctx, domain.NewListTribeSnapshotsParams()) require.NoError(t, err) for i, p := range params { date := p.Date().Format(dateFormat) idx := slices.IndexFunc(tribeSnapshots, func(ts domain.TribeSnapshot) bool { return ts.ServerKey() == p.ServerKey() && ts.TribeID() == p.TribeID() && ts.Date().Format(dateFormat) == date }) require.GreaterOrEqualf(t, idx, 0, "params[%d] not found", i) tribeSnapshot := tribeSnapshots[idx] assert.Equalf(t, p.TribeID(), tribeSnapshot.TribeID(), "params[%d]", i) assert.Equalf(t, p.ServerKey(), tribeSnapshot.ServerKey(), "params[%d]", i) assert.Equalf(t, p.NumMembers(), tribeSnapshot.NumMembers(), "params[%d]", i) assert.Equalf(t, p.NumVillages(), tribeSnapshot.NumVillages(), "params[%d]", i) assert.Equalf(t, p.Points(), tribeSnapshot.Points(), "params[%d]", i) assert.Equalf(t, p.AllPoints(), tribeSnapshot.AllPoints(), "params[%d]", i) assert.Equalf(t, p.Rank(), tribeSnapshot.Rank(), "params[%d]", i) assert.Equalf(t, p.OD(), tribeSnapshot.OD(), "params[%d]", i) assert.InDeltaf(t, p.Dominance(), tribeSnapshot.Dominance(), 0.001, "params[%d]", i) assert.Equalf(t, date, tribeSnapshot.Date().Format(dateFormat), "params[%d]", i) assert.WithinDurationf(t, time.Now(), tribeSnapshot.CreatedAt(), time.Minute, "params[%d]", i) } } assertNoDuplicates := func(t *testing.T, params []domain.CreateTribeSnapshotParams) { t.Helper() require.NotEmpty(t, params) tribeSnapshots, err := repos.tribeSnapshot.List(ctx, domain.NewListTribeSnapshotsParams()) require.NoError(t, err) m := make(map[string][]int) for _, p := range params { key := fmt.Sprintf("%s-%d-%s", p.ServerKey(), p.TribeID(), p.Date().Format(dateFormat)) for i, ts := range tribeSnapshots { if ts.ServerKey() == p.ServerKey() && ts.TribeID() == p.TribeID() && ts.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() listTribesParams := domain.NewListTribesParams() require.NoError(t, listTribesParams.SetDeleted(domain.NullBool{ Value: false, Valid: true, })) tribes, err := repos.tribe.List(ctx, listTribesParams) require.NoError(t, err) require.NotEmpty(t, tribes) date := time.Now() createParams, err := domain.NewCreateTribeSnapshotParams(tribes, date) require.NoError(t, err) require.NoError(t, repos.tribeSnapshot.Create(ctx, createParams...)) assertCreated(t, createParams) require.NoError(t, repos.tribeSnapshot.Create(ctx, createParams...)) assertNoDuplicates(t, createParams) }) t.Run("OK: len(params) == 0", func(t *testing.T) { t.Parallel() require.NoError(t, repos.tribeSnapshot.Create(ctx)) }) }) t.Run("List & ListCount", func(t *testing.T) { t.Parallel() repos := newRepos(t) tribeSnapshots, listTribeSnapshotsErr := repos.tribeSnapshot.List(ctx, domain.NewListTribeSnapshotsParams()) require.NoError(t, listTribeSnapshotsErr) require.NotEmpty(t, tribeSnapshots) randTribeSnapshot := tribeSnapshots[0] tests := []struct { name string params func(t *testing.T) domain.ListTribeSnapshotsParams assertTribeSnapshots func(t *testing.T, params domain.ListTribeSnapshotsParams, tribeSnapshots domain.TribeSnapshots) assertError func(t *testing.T, err error) assertTotal func(t *testing.T, params domain.ListTribeSnapshotsParams, total int) }{ { name: "OK: default params", params: func(t *testing.T) domain.ListTribeSnapshotsParams { t.Helper() return domain.NewListTribeSnapshotsParams() }, assertTribeSnapshots: func( t *testing.T, _ domain.ListTribeSnapshotsParams, tribeSnapshots domain.TribeSnapshots, ) { t.Helper() assert.NotEmpty(t, len(tribeSnapshots)) assert.True(t, slices.IsSortedFunc(tribeSnapshots, func(a, b domain.TribeSnapshot) 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.ListTribeSnapshotsParams, total int) { t.Helper() assert.NotEmpty(t, total) }, }, { name: "OK: sort=[serverKey DESC, date DESC]", params: func(t *testing.T) domain.ListTribeSnapshotsParams { t.Helper() params := domain.NewListTribeSnapshotsParams() require.NoError(t, params.SetSort([]domain.TribeSnapshotSort{ domain.TribeSnapshotSortServerKeyDESC, domain.TribeSnapshotSortDateDESC, })) return params }, assertTribeSnapshots: func( t *testing.T, _ domain.ListTribeSnapshotsParams, tribeSnapshots domain.TribeSnapshots, ) { t.Helper() assert.NotEmpty(t, len(tribeSnapshots)) assert.True(t, slices.IsSortedFunc(tribeSnapshots, func(a, b domain.TribeSnapshot) 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.ListTribeSnapshotsParams, total int) { t.Helper() assert.NotEmpty(t, total) }, }, { name: "OK: sort=[id ASC]", params: func(t *testing.T) domain.ListTribeSnapshotsParams { t.Helper() params := domain.NewListTribeSnapshotsParams() require.NoError(t, params.SetSort([]domain.TribeSnapshotSort{ domain.TribeSnapshotSortIDASC, })) return params }, assertTribeSnapshots: func( t *testing.T, _ domain.ListTribeSnapshotsParams, tribeSnapshots domain.TribeSnapshots, ) { t.Helper() assert.NotEmpty(t, len(tribeSnapshots)) assert.True(t, slices.IsSortedFunc(tribeSnapshots, func(a, b domain.TribeSnapshot) 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.ListTribeSnapshotsParams, total int) { t.Helper() assert.NotEmpty(t, total) }, }, { name: "OK: sort=[id DESC]", params: func(t *testing.T) domain.ListTribeSnapshotsParams { t.Helper() params := domain.NewListTribeSnapshotsParams() require.NoError(t, params.SetSort([]domain.TribeSnapshotSort{ domain.TribeSnapshotSortIDDESC, })) return params }, assertTribeSnapshots: func( t *testing.T, _ domain.ListTribeSnapshotsParams, tribeSnapshots domain.TribeSnapshots, ) { t.Helper() assert.NotEmpty(t, len(tribeSnapshots)) assert.True(t, slices.IsSortedFunc(tribeSnapshots, func(a, b domain.TribeSnapshot) 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.ListTribeSnapshotsParams, total int) { t.Helper() assert.NotEmpty(t, total) }, }, { name: fmt.Sprintf("OK: serverKeys=[%s]", randTribeSnapshot.ServerKey()), params: func(t *testing.T) domain.ListTribeSnapshotsParams { t.Helper() params := domain.NewListTribeSnapshotsParams() require.NoError(t, params.SetServerKeys([]string{randTribeSnapshot.ServerKey()})) return params }, assertTribeSnapshots: func( t *testing.T, params domain.ListTribeSnapshotsParams, tribeSnapshots domain.TribeSnapshots, ) { t.Helper() serverKeys := params.ServerKeys() for _, ts := range tribeSnapshots { assert.True(t, slices.Contains(serverKeys, ts.ServerKey())) } }, assertError: func(t *testing.T, err error) { t.Helper() require.NoError(t, err) }, assertTotal: func(t *testing.T, _ domain.ListTribeSnapshotsParams, total int) { t.Helper() assert.NotEmpty(t, total) }, }, { name: "OK: offset=1 limit=2", params: func(t *testing.T) domain.ListTribeSnapshotsParams { t.Helper() params := domain.NewListTribeSnapshotsParams() require.NoError(t, params.SetOffset(1)) require.NoError(t, params.SetLimit(2)) return params }, assertTribeSnapshots: func( t *testing.T, params domain.ListTribeSnapshotsParams, tribeSnapshots domain.TribeSnapshots, ) { t.Helper() assert.Len(t, tribeSnapshots, params.Limit()) }, assertError: func(t *testing.T, err error) { t.Helper() require.NoError(t, err) }, assertTotal: func(t *testing.T, _ domain.ListTribeSnapshotsParams, total int) { t.Helper() assert.NotEmpty(t, total) }, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() params := tt.params(t) res, err := repos.tribeSnapshot.List(ctx, params) tt.assertError(t, err) tt.assertTribeSnapshots(t, params, res) }) } }) }