diff --git a/internal/cmd/calendar_raw_test.go b/internal/cmd/calendar_raw_test.go index 60f6615..f267937 100644 --- a/internal/cmd/calendar_raw_test.go +++ b/internal/cmd/calendar_raw_test.go @@ -1,7 +1,6 @@ package cmd import ( - "context" "encoding/json" "net/http" "net/http/httptest" @@ -9,7 +8,6 @@ import ( "testing" "google.golang.org/api/calendar/v3" - "google.golang.org/api/option" ) func newCalendarRawTestServer(t *testing.T, status int, body map[string]any) *httptest.Server { @@ -42,18 +40,8 @@ func newCalendarRawTestServer(t *testing.T, status int, body map[string]any) *ht func installMockCalendarService(t *testing.T, srv *httptest.Server) { t.Helper() - orig := newCalendarService - t.Cleanup(func() { newCalendarService = orig }) - - svc, err := calendar.NewService(context.Background(), - option.WithoutAuthentication(), - option.WithHTTPClient(srv.Client()), - option.WithEndpoint(srv.URL+"/"), - ) - if err != nil { - t.Fatalf("NewService: %v", err) - } - newCalendarService = func(context.Context, string) (*calendar.Service, error) { return svc, nil } + svc := newGoogleTestServiceWithEndpoint(t, srv.Client(), srv.URL+"/", calendar.NewService) + stubGoogleTestService(t, &newCalendarService, svc) } func fullCalendarEventResponse(id string) map[string]any { diff --git a/internal/cmd/calendar_testutil_test.go b/internal/cmd/calendar_testutil_test.go index eeb2bce..6176f32 100644 --- a/internal/cmd/calendar_testutil_test.go +++ b/internal/cmd/calendar_testutil_test.go @@ -4,11 +4,9 @@ import ( "context" "io" "net/http" - "net/http/httptest" "testing" "google.golang.org/api/calendar/v3" - "google.golang.org/api/option" "github.com/steipete/gogcli/internal/outfmt" "github.com/steipete/gogcli/internal/ui" @@ -17,17 +15,7 @@ import ( func newCalendarServiceForTest(t *testing.T, h http.Handler) (*calendar.Service, func()) { t.Helper() - srv := httptest.NewServer(h) - svc, err := calendar.NewService(context.Background(), - option.WithoutAuthentication(), - option.WithHTTPClient(srv.Client()), - option.WithEndpoint(srv.URL+"/"), - ) - if err != nil { - srv.Close() - t.Fatalf("NewService: %v", err) - } - return svc, srv.Close + return newGoogleTestService(t, h, calendar.NewService) } func newTestCalendarService(t *testing.T, h http.Handler) (*calendar.Service, func()) { @@ -37,9 +25,7 @@ func newTestCalendarService(t *testing.T, h http.Handler) (*calendar.Service, fu func stubCalendarServiceForTest(t *testing.T, svc *calendar.Service) { t.Helper() - origNew := newCalendarService - t.Cleanup(func() { newCalendarService = origNew }) - newCalendarService = func(context.Context, string) (*calendar.Service, error) { return svc, nil } + stubGoogleTestService(t, &newCalendarService, svc) } func newCalendarOutputContext(t *testing.T, stdout, stderr io.Writer) context.Context { diff --git a/internal/cmd/drive_raw_test.go b/internal/cmd/drive_raw_test.go index 319688d..91850ab 100644 --- a/internal/cmd/drive_raw_test.go +++ b/internal/cmd/drive_raw_test.go @@ -1,7 +1,6 @@ package cmd import ( - "context" "encoding/json" "net/http" "net/http/httptest" @@ -10,7 +9,6 @@ import ( "testing" "google.golang.org/api/drive/v3" - "google.golang.org/api/option" ) type driveRawHit struct { @@ -42,18 +40,8 @@ func newDriveRawTestServer(t *testing.T, status int, body map[string]any, hit *d func installMockDriveService(t *testing.T, srv *httptest.Server) { t.Helper() - orig := newDriveService - t.Cleanup(func() { newDriveService = orig }) - - svc, err := drive.NewService(context.Background(), - option.WithoutAuthentication(), - option.WithHTTPClient(srv.Client()), - option.WithEndpoint(srv.URL+"/"), - ) - if err != nil { - t.Fatalf("NewService: %v", err) - } - newDriveService = func(context.Context, string) (*drive.Service, error) { return svc, nil } + svc := newGoogleTestServiceWithEndpoint(t, srv.Client(), srv.URL+"/", drive.NewService) + stubGoogleTestService(t, &newDriveService, svc) } // sensitiveDriveFile returns a File response containing every sensitive diff --git a/internal/cmd/drive_testutil_test.go b/internal/cmd/drive_testutil_test.go index 8ce9c1f..dfe3c4c 100644 --- a/internal/cmd/drive_testutil_test.go +++ b/internal/cmd/drive_testutil_test.go @@ -5,28 +5,16 @@ import ( "encoding/json" "io" "net/http" - "net/http/httptest" "strings" "testing" "google.golang.org/api/drive/v3" - "google.golang.org/api/option" ) func newDriveTestService(t *testing.T, h http.Handler) (*drive.Service, func()) { t.Helper() - srv := httptest.NewServer(h) - - svc, err := drive.NewService(context.Background(), - option.WithoutAuthentication(), - option.WithHTTPClient(srv.Client()), - option.WithEndpoint(srv.URL+"/"), - ) - if err != nil { - t.Fatalf("NewService: %v", err) - } - return svc, srv.Close + return newGoogleTestService(t, h, drive.NewService) } func stubDriveService(svc *drive.Service) func(context.Context, string) (*drive.Service, error) { @@ -35,9 +23,7 @@ func stubDriveService(svc *drive.Service) func(context.Context, string) (*drive. func stubDriveServiceForTest(t *testing.T, svc *drive.Service) { t.Helper() - origNew := newDriveService - t.Cleanup(func() { newDriveService = origNew }) - newDriveService = stubDriveService(svc) + stubGoogleTestService(t, &newDriveService, svc) } func newDriveMetadataTestService(t *testing.T, mimeType string) (*drive.Service, func()) { diff --git a/internal/cmd/forms_raw_test.go b/internal/cmd/forms_raw_test.go index cf1cf6c..08ed282 100644 --- a/internal/cmd/forms_raw_test.go +++ b/internal/cmd/forms_raw_test.go @@ -1,7 +1,6 @@ package cmd import ( - "context" "encoding/json" "net/http" "net/http/httptest" @@ -9,7 +8,6 @@ import ( "testing" formsapi "google.golang.org/api/forms/v1" - "google.golang.org/api/option" ) func newFormsRawTestServer(t *testing.T, status int, body map[string]any) *httptest.Server { @@ -33,18 +31,8 @@ func newFormsRawTestServer(t *testing.T, status int, body map[string]any) *httpt func installMockFormsService(t *testing.T, srv *httptest.Server) { t.Helper() - orig := newFormsService - t.Cleanup(func() { newFormsService = orig }) - - svc, err := formsapi.NewService(context.Background(), - option.WithoutAuthentication(), - option.WithHTTPClient(srv.Client()), - option.WithEndpoint(srv.URL+"/"), - ) - if err != nil { - t.Fatalf("NewService: %v", err) - } - newFormsService = func(context.Context, string) (*formsapi.Service, error) { return svc, nil } + svc := newGoogleTestServiceWithEndpoint(t, srv.Client(), srv.URL+"/", formsapi.NewService) + stubGoogleTestService(t, &newFormsService, svc) } func fullFormResponse(id string) map[string]any { diff --git a/internal/cmd/gmail_raw_test.go b/internal/cmd/gmail_raw_test.go index e7b2b8a..c33c78a 100644 --- a/internal/cmd/gmail_raw_test.go +++ b/internal/cmd/gmail_raw_test.go @@ -1,7 +1,6 @@ package cmd import ( - "context" "encoding/json" "net/http" "net/http/httptest" @@ -10,7 +9,6 @@ import ( "testing" "google.golang.org/api/gmail/v1" - "google.golang.org/api/option" ) type gmailRawHit struct { @@ -41,18 +39,8 @@ func newGmailRawTestServer(t *testing.T, status int, body map[string]any, hit *g func installMockGmailService(t *testing.T, srv *httptest.Server) { t.Helper() - orig := newGmailService - t.Cleanup(func() { newGmailService = orig }) - - svc, err := gmail.NewService(context.Background(), - option.WithoutAuthentication(), - option.WithHTTPClient(srv.Client()), - option.WithEndpoint(srv.URL+"/"), - ) - if err != nil { - t.Fatalf("NewService: %v", err) - } - newGmailService = func(context.Context, string) (*gmail.Service, error) { return svc, nil } + svc := newGoogleTestServiceWithEndpoint(t, srv.Client(), srv.URL+"/", gmail.NewService) + stubGoogleTestService(t, &newGmailService, svc) } func fullGmailMessageResponse(id string) map[string]any { diff --git a/internal/cmd/gmail_testutil_test.go b/internal/cmd/gmail_testutil_test.go index 035919b..5be279a 100644 --- a/internal/cmd/gmail_testutil_test.go +++ b/internal/cmd/gmail_testutil_test.go @@ -1,34 +1,19 @@ package cmd import ( - "context" "net/http" - "net/http/httptest" "testing" "google.golang.org/api/gmail/v1" - "google.golang.org/api/option" ) func newGmailServiceForTest(t *testing.T, h http.HandlerFunc) (*gmail.Service, func()) { t.Helper() - srv := httptest.NewServer(h) - svc, err := gmail.NewService(context.Background(), - option.WithoutAuthentication(), - option.WithHTTPClient(srv.Client()), - option.WithEndpoint(srv.URL+"/"), - ) - if err != nil { - srv.Close() - t.Fatalf("NewService: %v", err) - } - return svc, srv.Close + return newGoogleTestService(t, h, gmail.NewService) } func stubGmailServiceForTest(t *testing.T, svc *gmail.Service) { t.Helper() - origNew := newGmailService - t.Cleanup(func() { newGmailService = origNew }) - newGmailService = func(context.Context, string) (*gmail.Service, error) { return svc, nil } + stubGoogleTestService(t, &newGmailService, svc) } diff --git a/internal/cmd/google_service_testutil_test.go b/internal/cmd/google_service_testutil_test.go new file mode 100644 index 0000000..19cca3a --- /dev/null +++ b/internal/cmd/google_service_testutil_test.go @@ -0,0 +1,47 @@ +package cmd + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + + "google.golang.org/api/option" +) + +type googleTestServiceFactory[T any] func(context.Context, ...option.ClientOption) (*T, error) + +func newGoogleTestService[T any](t *testing.T, h http.Handler, factory googleTestServiceFactory[T]) (*T, func()) { + t.Helper() + + srv := httptest.NewServer(h) + svc := newGoogleTestServiceWithEndpoint(t, srv.Client(), srv.URL+"/", factory) + return svc, srv.Close +} + +func newGoogleTestServiceWithEndpoint[T any]( + t *testing.T, + client *http.Client, + endpoint string, + factory googleTestServiceFactory[T], +) *T { + t.Helper() + + svc, err := factory(context.Background(), + option.WithoutAuthentication(), + option.WithHTTPClient(client), + option.WithEndpoint(endpoint), + ) + if err != nil { + t.Fatalf("NewService: %v", err) + } + return svc +} + +func stubGoogleTestService[T any](t *testing.T, target *func(context.Context, string) (*T, error), svc *T) { + t.Helper() + + orig := *target + t.Cleanup(func() { *target = orig }) + *target = func(context.Context, string) (*T, error) { return svc, nil } +} diff --git a/internal/cmd/people_raw_test.go b/internal/cmd/people_raw_test.go index 248bd6e..eaf813f 100644 --- a/internal/cmd/people_raw_test.go +++ b/internal/cmd/people_raw_test.go @@ -1,14 +1,12 @@ package cmd import ( - "context" "encoding/json" "net/http" "net/http/httptest" "strings" "testing" - "google.golang.org/api/option" "google.golang.org/api/people/v1" ) @@ -33,18 +31,8 @@ func newPeopleRawTestServer(t *testing.T, status int, body map[string]any) *http func installMockPeopleContactsService(t *testing.T, srv *httptest.Server) { t.Helper() - orig := newPeopleContactsService - t.Cleanup(func() { newPeopleContactsService = orig }) - - svc, err := people.NewService(context.Background(), - option.WithoutAuthentication(), - option.WithHTTPClient(srv.Client()), - option.WithEndpoint(srv.URL+"/"), - ) - if err != nil { - t.Fatalf("NewService: %v", err) - } - newPeopleContactsService = func(context.Context, string) (*people.Service, error) { return svc, nil } + svc := newGoogleTestServiceWithEndpoint(t, srv.Client(), srv.URL+"/", people.NewService) + stubGoogleTestService(t, &newPeopleContactsService, svc) } func fullPersonResponse(id string) map[string]any { diff --git a/internal/cmd/sheets_raw_test.go b/internal/cmd/sheets_raw_test.go index c489aa0..da469c7 100644 --- a/internal/cmd/sheets_raw_test.go +++ b/internal/cmd/sheets_raw_test.go @@ -11,7 +11,6 @@ import ( "sync/atomic" "testing" - "google.golang.org/api/option" "google.golang.org/api/sheets/v4" "github.com/steipete/gogcli/internal/ui" @@ -47,18 +46,8 @@ func newSheetsRawTestServer(t *testing.T, status int, body map[string]any, hit * func installMockSheetsService(t *testing.T, srv *httptest.Server) { t.Helper() - orig := newSheetsService - t.Cleanup(func() { newSheetsService = orig }) - - svc, err := sheets.NewService(context.Background(), - option.WithoutAuthentication(), - option.WithHTTPClient(srv.Client()), - option.WithEndpoint(srv.URL+"/"), - ) - if err != nil { - t.Fatalf("NewService: %v", err) - } - newSheetsService = func(context.Context, string) (*sheets.Service, error) { return svc, nil } + svc := newGoogleTestServiceWithEndpoint(t, srv.Client(), srv.URL+"/", sheets.NewService) + stubGoogleTestService(t, &newSheetsService, svc) } func fullSheetResponse(id string) map[string]any { diff --git a/internal/cmd/slides_raw_test.go b/internal/cmd/slides_raw_test.go index 15c190a..7ef1e51 100644 --- a/internal/cmd/slides_raw_test.go +++ b/internal/cmd/slides_raw_test.go @@ -1,14 +1,12 @@ package cmd import ( - "context" "encoding/json" "net/http" "net/http/httptest" "strings" "testing" - "google.golang.org/api/option" "google.golang.org/api/slides/v1" ) @@ -35,18 +33,8 @@ func newSlidesRawTestServer(t *testing.T, status int, body map[string]any) *http func installMockSlidesService(t *testing.T, srv *httptest.Server) { t.Helper() - orig := newSlidesService - t.Cleanup(func() { newSlidesService = orig }) - - svc, err := slides.NewService(context.Background(), - option.WithoutAuthentication(), - option.WithHTTPClient(srv.Client()), - option.WithEndpoint(srv.URL+"/"), - ) - if err != nil { - t.Fatalf("NewService: %v", err) - } - newSlidesService = func(context.Context, string) (*slides.Service, error) { return svc, nil } + svc := newGoogleTestServiceWithEndpoint(t, srv.Client(), srv.URL+"/", slides.NewService) + stubGoogleTestService(t, &newSlidesService, svc) } func fullPresentationResponse(id string) map[string]any { diff --git a/internal/cmd/tasks_raw_test.go b/internal/cmd/tasks_raw_test.go index f460d3c..4e55a0d 100644 --- a/internal/cmd/tasks_raw_test.go +++ b/internal/cmd/tasks_raw_test.go @@ -1,14 +1,12 @@ package cmd import ( - "context" "encoding/json" "net/http" "net/http/httptest" "strings" "testing" - "google.golang.org/api/option" "google.golang.org/api/tasks/v1" ) @@ -39,18 +37,8 @@ func newTasksRawTestServer(t *testing.T, status int, body map[string]any) *httpt func installMockTasksService(t *testing.T, srv *httptest.Server) { t.Helper() - orig := newTasksService - t.Cleanup(func() { newTasksService = orig }) - - svc, err := tasks.NewService(context.Background(), - option.WithoutAuthentication(), - option.WithHTTPClient(srv.Client()), - option.WithEndpoint(srv.URL+"/"), - ) - if err != nil { - t.Fatalf("NewService: %v", err) - } - newTasksService = func(context.Context, string) (*tasks.Service, error) { return svc, nil } + svc := newGoogleTestServiceWithEndpoint(t, srv.Client(), srv.URL+"/", tasks.NewService) + stubGoogleTestService(t, &newTasksService, svc) } func fullTaskResponse(id string) map[string]any {