package adapter_test import ( "cmp" "context" "fmt" "slices" "testing" "time" "gitea.dwysokinski.me/twhelp/corev3/internal/domain" "gitea.dwysokinski.me/twhelp/corev3/internal/domain/domaintest" gocmp "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func testEnnoblementRepository(t *testing.T, newRepos func(t *testing.T) repositories) { t.Helper() ctx := context.Background() t.Run("Create", func(t *testing.T) { t.Parallel() repos := newRepos(t) assertCreated := func(t *testing.T, params []domain.CreateEnnoblementParams) { t.Helper() require.NotEmpty(t, params) listParams := domain.NewListEnnoblementsParams() require.NoError(t, listParams.SetServerKeys([]string{params[0].ServerKey()})) ennoblements, err := repos.ennoblement.List(ctx, listParams) require.NoError(t, err) for i, p := range params { idx := slices.IndexFunc(ennoblements, func(ennoblement domain.Ennoblement) bool { return ennoblement.VillageID() == p.Base().VillageID() && ennoblement.ServerKey() == p.ServerKey() }) require.GreaterOrEqualf(t, idx, 0, "params[%d] not found", i) ennoblement := ennoblements[idx] assert.Emptyf(t, gocmp.Diff( p.Base(), ennoblement.Base(), cmpopts.EquateApproxTime(time.Minute), gocmp.AllowUnexported(domain.BaseEnnoblement{}), ), "params[%d]", i) assert.Equalf(t, p.ServerKey(), ennoblement.ServerKey(), "params[%d]", i) } } assertNoDuplicates := func(t *testing.T, params []domain.CreateEnnoblementParams) { t.Helper() require.NotEmpty(t, params) listParams := domain.NewListEnnoblementsParams() require.NoError(t, listParams.SetServerKeys([]string{params[0].ServerKey()})) ennoblements, err := repos.ennoblement.List(ctx, listParams) require.NoError(t, err) res := make(map[string][]int) for _, p := range params { key := fmt.Sprintf("%s-%d", p.ServerKey(), p.Base().VillageID()) for i, e := range ennoblements { if e.ServerKey() == p.ServerKey() && gocmp.Equal( p.Base(), e.Base(), cmpopts.EquateApproxTime(time.Minute), gocmp.AllowUnexported(domain.BaseEnnoblement{}), ) { res[key] = append(res[key], i) } } } for key, indexes := range res { assert.Len(t, indexes, 1, key) } } t.Run("OK", func(t *testing.T) { t.Parallel() servers, err := repos.server.List(ctx, domain.NewListServersParams()) require.NoError(t, err) require.NotEmpty(t, servers) server := servers[0] ennoblementsToCreate := domain.BaseEnnoblements{ domaintest.NewBaseEnnoblement(t), domaintest.NewBaseEnnoblement(t), } createParams, err := domain.NewCreateEnnoblementParams(server.Key(), ennoblementsToCreate) require.NoError(t, err) require.NoError(t, repos.ennoblement.Create(ctx, createParams...)) assertCreated(t, createParams) require.NoError(t, repos.ennoblement.Create(ctx, createParams...)) assertNoDuplicates(t, createParams) }) t.Run("OK: len(params) == 0", func(t *testing.T) { t.Parallel() require.NoError(t, repos.ennoblement.Create(ctx)) }) }) t.Run("List & ListCount", func(t *testing.T) { t.Parallel() repos := newRepos(t) ennoblements, listEnnoblementsErr := repos.ennoblement.List(ctx, domain.NewListEnnoblementsParams()) require.NoError(t, listEnnoblementsErr) require.NotEmpty(t, ennoblements) randEnnoblement := ennoblements[0] tests := []struct { name string params func(t *testing.T) domain.ListEnnoblementsParams assertEnnoblements func(t *testing.T, params domain.ListEnnoblementsParams, ennoblements domain.Ennoblements) assertError func(t *testing.T, err error) assertTotal func(t *testing.T, params domain.ListEnnoblementsParams, total int) }{ { name: "OK: default params", params: func(t *testing.T) domain.ListEnnoblementsParams { t.Helper() return domain.NewListEnnoblementsParams() }, assertEnnoblements: func(t *testing.T, params domain.ListEnnoblementsParams, ennoblements domain.Ennoblements) { t.Helper() assert.NotEmpty(t, len(ennoblements)) assert.True(t, slices.IsSortedFunc(ennoblements, func(a, b domain.Ennoblement) int { if x := cmp.Compare(a.ServerKey(), b.ServerKey()); x != 0 { return x } return a.CreatedAt().Compare(b.CreatedAt()) })) }, assertError: func(t *testing.T, err error) { t.Helper() require.NoError(t, err) }, assertTotal: func(t *testing.T, params domain.ListEnnoblementsParams, total int) { t.Helper() assert.NotEmpty(t, total) }, }, { name: "OK: sort=[serverKey DESC, createdAt DESC]", params: func(t *testing.T) domain.ListEnnoblementsParams { t.Helper() params := domain.NewListEnnoblementsParams() require.NoError(t, params.SetSort([]domain.EnnoblementSort{ domain.EnnoblementSortServerKeyDESC, domain.EnnoblementSortCreatedAtDESC, })) return params }, assertEnnoblements: func(t *testing.T, params domain.ListEnnoblementsParams, ennoblements domain.Ennoblements) { t.Helper() assert.NotEmpty(t, len(ennoblements)) assert.True(t, slices.IsSortedFunc(ennoblements, func(a, b domain.Ennoblement) int { if x := cmp.Compare(a.ServerKey(), b.ServerKey()) * -1; x != 0 { return x } return a.CreatedAt().Compare(b.CreatedAt()) * -1 })) }, assertError: func(t *testing.T, err error) { t.Helper() require.NoError(t, err) }, assertTotal: func(t *testing.T, params domain.ListEnnoblementsParams, total int) { t.Helper() assert.NotEmpty(t, total) }, }, { name: fmt.Sprintf("OK: serverKeys=[%s]", randEnnoblement.ServerKey()), params: func(t *testing.T) domain.ListEnnoblementsParams { t.Helper() params := domain.NewListEnnoblementsParams() require.NoError(t, params.SetServerKeys([]string{randEnnoblement.ServerKey()})) return params }, assertEnnoblements: func(t *testing.T, params domain.ListEnnoblementsParams, ennoblements domain.Ennoblements) { t.Helper() serverKeys := params.ServerKeys() for _, v := range ennoblements { assert.True(t, slices.Contains(serverKeys, v.ServerKey())) } }, assertError: func(t *testing.T, err error) { t.Helper() require.NoError(t, err) }, assertTotal: func(t *testing.T, params domain.ListEnnoblementsParams, total int) { t.Helper() assert.NotEmpty(t, total) }, }, { name: "OK: offset=1 limit=2", params: func(t *testing.T) domain.ListEnnoblementsParams { t.Helper() params := domain.NewListEnnoblementsParams() require.NoError(t, params.SetOffset(1)) require.NoError(t, params.SetLimit(2)) return params }, assertEnnoblements: func(t *testing.T, params domain.ListEnnoblementsParams, ennoblements domain.Ennoblements) { t.Helper() assert.Len(t, ennoblements, params.Limit()) }, assertError: func(t *testing.T, err error) { t.Helper() require.NoError(t, err) }, assertTotal: func(t *testing.T, params domain.ListEnnoblementsParams, 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.ennoblement.List(ctx, params) tt.assertError(t, err) tt.assertEnnoblements(t, params, res) }) } }) }