| // Copyright 2024 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package reviews |
| |
| import ( |
| "reflect" |
| "slices" |
| "sync" |
| "testing" |
| "time" |
| |
| "golang.org/x/oscar/internal/gerrit" |
| "golang.org/x/oscar/internal/secret" |
| "golang.org/x/oscar/internal/storage" |
| "golang.org/x/oscar/internal/testutil" |
| ) |
| |
| // testGerritClient returns a [*gerrit.Client] for testing. |
| func testGerritClient(t *testing.T) *gerrit.Client { |
| lg := testutil.Slogger(t) |
| db := storage.MemDB() |
| sdb := secret.Empty() |
| return gerrit.New("reviews-test", lg, db, sdb, nil) |
| } |
| |
| // loadTestChange loads a txtar file as a [Change]. |
| func loadTestChange(t *testing.T, gc *gerrit.Client, filename string, num int) Change { |
| tc := gc.Testing() |
| testutil.Check(t, tc.LoadTxtar(filename)) |
| gch := gc.Change("test", num) |
| grc := &GerritReviewClient{ |
| GClient: gc, |
| Accounts: testAccounts(), |
| } |
| change := &GerritChange{ |
| Client: grc, |
| Change: gch, |
| } |
| return change |
| } |
| |
| func TestGerritChange(t *testing.T) { |
| gc := testGerritClient(t) |
| change := loadTestChange(t, gc, "testdata/gerritchange.txt", 1) |
| |
| toEmail := func(fn func() []Account) func() []string { |
| return func() []string { |
| var ret []string |
| for _, r := range fn() { |
| ret = append(ret, r.Name()) |
| } |
| slices.Sort(ret) |
| return ret |
| } |
| } |
| |
| tests := []struct { |
| name string |
| method func() any |
| want any |
| }{ |
| { |
| "ID", |
| wm(change.ID), |
| "1", |
| }, |
| { |
| "Status", |
| wm(change.Status), |
| StatusReady, |
| }, |
| { |
| "Author", |
| wm(change.Author().Name), |
| "gopher@golang.org", |
| }, |
| { |
| "Created", |
| wm(change.Created), |
| time.Date(2024, 10, 1, 10, 10, 10, 0, time.UTC), |
| }, |
| { |
| "Updated", |
| wm(change.Updated), |
| time.Date(2024, 10, 3, 10, 10, 10, 0, time.UTC), |
| }, |
| { |
| "UpdatedByAuthor", |
| wm(change.UpdatedByAuthor), |
| time.Date(2024, 10, 2, 10, 10, 10, 0, time.UTC), |
| }, |
| { |
| "Subject", |
| wm(change.Subject), |
| "my new change", |
| }, |
| { |
| "Description", |
| wm(change.Description), |
| "initial change", |
| }, |
| { |
| "Reviewers", |
| wm(toEmail(change.Reviewers)), |
| []string{ |
| "maintainer@golang.org", |
| }, |
| }, |
| { |
| "Reviewed", |
| wm(toEmail(change.Reviewed)), |
| []string{ |
| "commenter@golang.org", |
| "maintainer@golang.org", |
| }, |
| }, |
| { |
| "Needs", |
| wm(change.Needs), |
| Needs(0), |
| }, |
| } |
| |
| for _, test := range tests { |
| got := test.method() |
| if !reflect.DeepEqual(got, test.want) { |
| t.Errorf("%s got %v, want %v", test.name, got, test.want) |
| } |
| } |
| |
| gerritChanges := func(yield func(*gerrit.Change) bool) { |
| for _, changeFn := range gc.ChangeNumbers("test") { |
| if !yield(changeFn()) { |
| return |
| } |
| } |
| } |
| |
| it := GerritChanges(gc, testAccounts(), gerritChanges) |
| got := slices.Collect(it) |
| var gotIDs []string |
| for _, g := range got { |
| gotIDs = append(gotIDs, g.ID()) |
| } |
| slices.Sort(gotIDs) |
| wantIDs := []string{"1", "2"} |
| if !slices.Equal(gotIDs, wantIDs) { |
| t.Errorf("GerritChanges returned IDs %v, want %v", gotIDs, wantIDs) |
| } |
| } |
| |
| // changeMethod is one of the methods used to retrieve Change values. |
| type changeMethod[T any] func() T |
| |
| // wm wraps a changeMethod in a function that we can put in a table. |
| func wm[T any](fn changeMethod[T]) func() any { |
| return func() any { |
| return fn() |
| } |
| } |
| |
| // gerritTestAccount implements [Account]. |
| type gerritTestAccount struct { |
| name string |
| displayName string |
| authority Authority |
| commits int |
| } |
| |
| // Name implements Account.Name. |
| func (gta *gerritTestAccount) Name() string { |
| return gta.name |
| } |
| |
| // DisplayName implements Account.DisplayName. |
| func (gta *gerritTestAccount) DisplayName() string { |
| return gta.displayName |
| } |
| |
| // Authority implements Account.Authority |
| func (gta *gerritTestAccount) Authority() Authority { |
| return gta.authority |
| } |
| |
| // Commits implements Account.Commits. |
| func (gta *gerritTestAccount) Commits() int { |
| return gta.commits |
| } |
| |
| // gerritTestAccountLookup implements [AccountLookup]. |
| type gerritTestAccountLookup map[string]Account |
| |
| func (gtal gerritTestAccountLookup) Lookup(name string) Account { |
| return gtal[name] |
| } |
| |
| // testAccounts returns an implementation of [AccountLookup] for testing. |
| var testAccounts = sync.OnceValue(func() AccountLookup { |
| return gerritTestAccountLookup{ |
| "gopher@golang.org": &gerritTestAccount{ |
| name: "gopher@golang.org", |
| displayName: "gopher", |
| authority: AuthorityReviewer, |
| commits: 10, |
| }, |
| "maintainer@golang.org": &gerritTestAccount{ |
| name: "maintainer@golang.org", |
| displayName: "maintainer", |
| authority: AuthorityMaintainer, |
| commits: 10, |
| }, |
| "commenter@golang.org": &gerritTestAccount{ |
| name: "commenter@golang.org", |
| displayName: "commenter", |
| authority: AuthorityContributor, |
| commits: 10, |
| }, |
| } |
| }) |