diff --git a/go.mod b/go.mod index b8d70ff..bd8e1f6 100644 --- a/go.mod +++ b/go.mod @@ -1,18 +1,18 @@ module github.com/hugoh/tmhi-cli -go 1.25.0 +go 1.26.0 require ( github.com/go-ozzo/ozzo-validation/v4 v4.3.0 github.com/hugoh/cellular-signal v1.1.3 - github.com/hugoh/tmhi-gateway v1.2.0 + github.com/hugoh/tmhi-gateway v1.3.0 github.com/pterm/pterm v0.12.83 github.com/stretchr/testify v1.11.1 github.com/urfave/cli-altsrc/v3 v3.1.0 github.com/urfave/cli-validation v0.0.0-20230629031421-92802a7fd6e9 github.com/urfave/cli/v3 v3.9.0 github.com/zenizh/go-capturer v0.0.0-20211219060012-52ea6c8fed04 - golang.org/x/term v0.43.0 + golang.org/x/term v0.44.0 ) require ( @@ -33,8 +33,8 @@ require ( github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect golang.org/x/net v0.55.0 // indirect - golang.org/x/sys v0.45.0 // indirect - golang.org/x/text v0.37.0 // indirect + golang.org/x/sys v0.46.0 // indirect + golang.org/x/text v0.38.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index f4a33bb..b2e4f3a 100644 --- a/go.sum +++ b/go.sum @@ -31,8 +31,8 @@ github.com/gookit/color v1.6.1 h1:KoTnDxJPRgrL0SoX0f8rCFg2zI0t4E3GZZBMo2nN8LU= github.com/gookit/color v1.6.1/go.mod h1:9ACFc7/1IpHGBW8RwuDm/0YEnhg3dwwXpoMsmtyHfjs= github.com/hugoh/cellular-signal v1.1.3 h1:RBreCLAgY5zoeYbmUPVxMKVZVSuiirnrRHo6a6Dqgz4= github.com/hugoh/cellular-signal v1.1.3/go.mod h1:UX0FKsxcPzK7YFM6Glu7LjZQA8m8TxXcRV64/N1rgZk= -github.com/hugoh/tmhi-gateway v1.2.0 h1:vsEi1mVIAYduYsuC3L/ZjKiZdiT8MARjXykl/haESh8= -github.com/hugoh/tmhi-gateway v1.2.0/go.mod h1:3UhUbdTePuQi/sX2T3ElzZOUEF98hXp/Dh0j71rGM6g= +github.com/hugoh/tmhi-gateway v1.3.0 h1:4t8xy29fpGpj/Q8fold63Bg0DlAIngV5Egkad+8+nVE= +github.com/hugoh/tmhi-gateway v1.3.0/go.mod h1:sGfaAFa6xlOVAmyinmWCSuP/zlIr6nZUju6rQjged5g= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -93,20 +93,20 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= -golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= -golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= +golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= +golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= -golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= +golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= +golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/internal/cmd.go b/internal/cmd.go index 9b8e846..5fd8d1b 100644 --- a/internal/cmd.go +++ b/internal/cmd.go @@ -95,8 +95,9 @@ var initGatewayFunc = initGateway // //nolint:ireturn func fetchWithFeedback[T any]( + ctx context.Context, message string, - fetch func() (T, error), + fetch func(context.Context) (T, error), display func(T), successMessage ...any, ) (T, error) { @@ -105,7 +106,7 @@ func fetchWithFeedback[T any]( return *new(T), err } - result, opErr := fetch() + result, opErr := fetch(ctx) if opErr != nil { spinnerInstance.Fail(fmt.Sprintf("%s: %v", message, opErr)) @@ -137,16 +138,17 @@ func initGateway(_ *Config) (tmhi.Gateway, error) { return gateway, nil } -func login(_ context.Context, _ *cli.Command) error { +func login(ctx context.Context, _ *cli.Command) error { gateway, err := initGatewayFunc(appConfig) if err != nil { return err } _, err = fetchWithFeedback( + ctx, "Logging in...", - func() (*tmhi.StatusResult, error) { - return nil, gateway.Login() + func(ctx context.Context) (*tmhi.StatusResult, error) { + return nil, gateway.Login(ctx) }, nil, "Successfully logged in", @@ -155,7 +157,7 @@ func login(_ context.Context, _ *cli.Command) error { return err } -func req(_ context.Context, cmd *cli.Command) error { +func req(ctx context.Context, cmd *cli.Command) error { gateway, err := initGatewayFunc(appConfig) if err != nil { return err @@ -171,12 +173,12 @@ func req(_ context.Context, cmd *cli.Command) error { loginFirst := cmd.Bool("login") if loginFirst { - if err := gateway.Login(); err != nil { + if err := gateway.Login(ctx); err != nil { return fmt.Errorf("request failed: %w", err) } } - result, err := gateway.Request(method, path) + result, err := gateway.Request(ctx, method, path) if err != nil { return fmt.Errorf("request failed: %w", err) } @@ -186,35 +188,41 @@ func req(_ context.Context, cmd *cli.Command) error { return nil } -func info(_ context.Context, _ *cli.Command) error { +func info(ctx context.Context, _ *cli.Command) error { gateway, err := initGatewayFunc(appConfig) if err != nil { return err } - _, err = fetchWithFeedback("Fetching gateway info...", gateway.Info, displayInfoResult) + _, err = fetchWithFeedback(ctx, "Fetching gateway info...", gateway.Info, displayInfoResult) return err } -func status(_ context.Context, _ *cli.Command) error { +func status(ctx context.Context, _ *cli.Command) error { gateway, err := initGatewayFunc(appConfig) if err != nil { return err } - _, err = fetchWithFeedback("Checking gateway status...", gateway.Status, displayStatusResult) + _, err = fetchWithFeedback( + ctx, + "Checking gateway status...", + gateway.Status, + displayStatusResult, + ) return err } -func signalCmd(_ context.Context, _ *cli.Command) error { +func signalCmd(ctx context.Context, _ *cli.Command) error { gateway, err := initGatewayFunc(appConfig) if err != nil { return err } _, err = fetchWithFeedback( + ctx, "Fetching signal information...", gateway.Signal, displaySignalResult, @@ -223,7 +231,7 @@ func signalCmd(_ context.Context, _ *cli.Command) error { return err } -func reboot(_ context.Context, cmd *cli.Command) error { +func reboot(ctx context.Context, cmd *cli.Command) error { gateway, err := initGatewayFunc(appConfig) if err != nil { return err @@ -252,9 +260,10 @@ func reboot(_ context.Context, cmd *cli.Command) error { } _, ret := fetchWithFeedback( + ctx, "Rebooting gateway...", - func() (*tmhi.SignalResult, error) { - rebootErr := gateway.Reboot() + func(ctx context.Context) (*tmhi.SignalResult, error) { + rebootErr := gateway.Reboot(ctx) if rebootErr != nil { return nil, fmt.Errorf("Reboot failed: %w", rebootErr) } diff --git a/internal/cmd_handlers_test.go b/internal/cmd_handlers_test.go index debdb04..88ce9dc 100644 --- a/internal/cmd_handlers_test.go +++ b/internal/cmd_handlers_test.go @@ -26,25 +26,25 @@ type mockGateway struct { signalErr error } -func (m *mockGateway) Login() error { +func (m *mockGateway) Login(context.Context) error { m.loginCalled = true return m.loginErr } -func (m *mockGateway) Reboot() error { +func (m *mockGateway) Reboot(context.Context) error { m.rebootCalled = true return m.rebootErr } -func (m *mockGateway) Request(_, _ string) (*tmhi.InfoResult, error) { +func (m *mockGateway) Request(context.Context, string, string) (*tmhi.InfoResult, error) { m.requestCalled = true return &tmhi.InfoResult{}, nil } -func (m *mockGateway) Info() (*tmhi.InfoResult, error) { +func (m *mockGateway) Info(context.Context) (*tmhi.InfoResult, error) { m.infoCalled = true if m.infoErr != nil { return nil, m.infoErr @@ -53,7 +53,7 @@ func (m *mockGateway) Info() (*tmhi.InfoResult, error) { return &tmhi.InfoResult{}, nil } -func (m *mockGateway) Status() (*tmhi.StatusResult, error) { +func (m *mockGateway) Status(context.Context) (*tmhi.StatusResult, error) { m.statusCalled = true if m.statusErr != nil { return nil, m.statusErr @@ -62,7 +62,7 @@ func (m *mockGateway) Status() (*tmhi.StatusResult, error) { return &tmhi.StatusResult{WebInterfaceUp: true}, nil } -func (m *mockGateway) Signal() (*tmhi.SignalResult, error) { +func (m *mockGateway) Signal(context.Context) (*tmhi.SignalResult, error) { m.signalCalled = true if m.signalErr != nil { return nil, m.signalErr @@ -134,27 +134,29 @@ func TestHandlerSuccessAndFailure(t *testing.T) { for _, tt := range tests { t.Run(tt.name+"/success", func(t *testing.T) { - original := initGatewayFunc - defer func() { initGatewayFunc = original }() + orig := initGatewayFunc + + t.Cleanup(func() { initGatewayFunc = orig }) mg := &mockGateway{} initGatewayFunc = func(_ *Config) (tmhi.Gateway, error) { return mg, nil } - err := tt.handler(context.Background(), nil) + err := tt.handler(t.Context(), nil) require.NoError(t, err) assert.True(t, tt.called(mg)) }) t.Run(tt.name+"/failure", func(t *testing.T) { - original := initGatewayFunc - defer func() { initGatewayFunc = original }() + orig := initGatewayFunc + + t.Cleanup(func() { initGatewayFunc = orig }) mg := &mockGateway{} tt.setupFail(mg) initGatewayFunc = func(_ *Config) (tmhi.Gateway, error) { return mg, nil } - err := tt.handler(context.Background(), nil) + err := tt.handler(t.Context(), nil) require.Error(t, err) for _, check := range tt.errChecks { @@ -167,20 +169,20 @@ func TestHandlerSuccessAndFailure(t *testing.T) { } func TestReboot_DryRunFlagAndFailure(t *testing.T) { - original := initGatewayFunc - originalConfig := appConfig + origInit := initGatewayFunc + origConfig := appConfig - defer func() { - initGatewayFunc = original - appConfig = originalConfig - }() + t.Cleanup(func() { + initGatewayFunc = origInit + appConfig = origConfig + }) t.Run("dry-run true returns early without calling gateway", func(t *testing.T) { appConfig = &Config{DryRun: true} mg := &mockGateway{} initGatewayFunc = func(_ *Config) (tmhi.Gateway, error) { return mg, nil } cmd := newRebootCmd(true) - err := reboot(context.Background(), cmd) + err := reboot(t.Context(), cmd) require.NoError(t, err) assert.False(t, mg.rebootCalled) }) @@ -190,20 +192,20 @@ func TestReboot_DryRunFlagAndFailure(t *testing.T) { mg := &mockGateway{rebootErr: errors.New("reboot boom")} initGatewayFunc = func(_ *Config) (tmhi.Gateway, error) { return mg, nil } cmd := newRebootCmd(false) - err := reboot(context.Background(), cmd) + err := reboot(t.Context(), cmd) require.Error(t, err) assert.True(t, mg.rebootCalled) }) } func TestReboot_ConfirmationDefaultsToNo(t *testing.T) { - original := initGatewayFunc - originalConfig := appConfig + origInit := initGatewayFunc + origConfig := appConfig - defer func() { - initGatewayFunc = original - appConfig = originalConfig - }() + t.Cleanup(func() { + initGatewayFunc = origInit + appConfig = origConfig + }) t.Run("enter accepts default no", func(t *testing.T) { testRebootConfirm(t, false, false, "reboot should be cancelled") @@ -228,7 +230,7 @@ func TestReboot_ConfirmationDefaultsToNo(t *testing.T) { }, } - err := reboot(context.Background(), cmd) + err := reboot(t.Context(), cmd) require.NoError(t, err) assert.True(t, mg.rebootCalled, "reboot should proceed with auto-confirm") }) @@ -237,15 +239,15 @@ func TestReboot_ConfirmationDefaultsToNo(t *testing.T) { func testRebootConfirm(t *testing.T, confirmResult bool, expectCalled bool, msg string) { t.Helper() - original := initGatewayFunc - originalConfig := appConfig - originalConfirm := confirmDialog + origInit := initGatewayFunc + origConfig := appConfig + origConfirm := confirmDialog - defer func() { - initGatewayFunc = original - appConfig = originalConfig - confirmDialog = originalConfirm - }() + t.Cleanup(func() { + initGatewayFunc = origInit + appConfig = origConfig + confirmDialog = origConfirm + }) appConfig = &Config{DryRun: false} mg := &mockGateway{} @@ -260,15 +262,15 @@ func testRebootConfirm(t *testing.T, confirmResult bool, expectCalled bool, msg }, } - err := reboot(context.Background(), cmd) + err := reboot(t.Context(), cmd) require.NoError(t, err) assert.Equal(t, expectCalled, mg.rebootCalled, msg) } func TestReq_Command(t *testing.T) { - original := initGatewayFunc + orig := initGatewayFunc - defer func() { initGatewayFunc = original }() + t.Cleanup(func() { initGatewayFunc = orig }) t.Run("wrong number of arguments", func(t *testing.T) { mg := &mockGateway{} @@ -282,12 +284,12 @@ func TestReq_Command(t *testing.T) { }, } - originalExiter := cli.OsExiter + origExiter := cli.OsExiter cli.OsExiter = func(_ int) {} - defer func() { cli.OsExiter = originalExiter }() + t.Cleanup(func() { cli.OsExiter = origExiter }) - err := reqCmd.Run(context.Background(), []string{appName, cmdReq}) + err := reqCmd.Run(t.Context(), []string{appName, cmdReq}) require.Error(t, err) assert.Contains(t, err.Error(), "exactly 2 arguments required") }) @@ -295,9 +297,9 @@ func TestReq_Command(t *testing.T) { func TestInitGateway(t *testing.T) { t.Run("returns gateway on success", func(t *testing.T) { - originalConfig := appConfig + origConfig := appConfig - defer func() { appConfig = originalConfig }() + t.Cleanup(func() { appConfig = origConfig }) appConfig = &Config{ Model: NOK5G21, diff --git a/internal/cmd_test.go b/internal/cmd_test.go index 4a25de2..25b3d90 100644 --- a/internal/cmd_test.go +++ b/internal/cmd_test.go @@ -39,12 +39,16 @@ func TestCaptureOutput_MultipleWrites(t *testing.T) { func TestFetchWithFeedback_Success(t *testing.T) { pterm.DisableStyling() + t.Cleanup(pterm.EnableStyling) - defer pterm.EnableStyling() - - result, err := fetchWithFeedback("Test operation", func() (string, error) { - return "success", nil - }, nil) + result, err := fetchWithFeedback( + t.Context(), + "Test operation", + func(context.Context) (string, error) { + return "success", nil + }, + nil, + ) require.NoError(t, err) assert.Equal(t, "success", result) @@ -52,13 +56,17 @@ func TestFetchWithFeedback_Success(t *testing.T) { func TestFetchWithFeedback_Error(t *testing.T) { pterm.DisableStyling() - - defer pterm.EnableStyling() + t.Cleanup(pterm.EnableStyling) expectedErr := errors.New("operation failed") - result, err := fetchWithFeedback("Test operation", func() (string, error) { - return "partial", expectedErr - }, nil) + result, err := fetchWithFeedback( + t.Context(), + "Test operation", + func(context.Context) (string, error) { + return "partial", expectedErr + }, + nil, + ) require.Error(t, err) assert.Contains(t, err.Error(), "Test operation") @@ -68,16 +76,20 @@ func TestFetchWithFeedback_Error(t *testing.T) { func TestFetchWithFeedback_WithPointerType(t *testing.T) { pterm.DisableStyling() - - defer pterm.EnableStyling() + t.Cleanup(pterm.EnableStyling) type testResult struct { Value int } - result, err := fetchWithFeedback("Test operation", func() (*testResult, error) { - return &testResult{Value: 42}, nil - }, nil) + result, err := fetchWithFeedback( + t.Context(), + "Test operation", + func(context.Context) (*testResult, error) { + return &testResult{Value: 42}, nil + }, + nil, + ) require.NoError(t, err) require.NotNil(t, result) @@ -86,11 +98,10 @@ func TestFetchWithFeedback_WithPointerType(t *testing.T) { func TestFetchWithFeedback_ErrorWrapping(t *testing.T) { pterm.DisableStyling() - - defer pterm.EnableStyling() + t.Cleanup(pterm.EnableStyling) originalErr := errors.New("underlying error") - _, err := fetchWithFeedback("Doing something", func() (int, error) { + _, err := fetchWithFeedback(t.Context(), "Doing something", func(context.Context) (int, error) { return 0, originalErr }, nil) @@ -100,19 +111,23 @@ func TestFetchWithFeedback_ErrorWrapping(t *testing.T) { func TestFetchWithFeedback_WithDisplay(t *testing.T) { pterm.DisableStyling() - - defer pterm.EnableStyling() + t.Cleanup(pterm.EnableStyling) displayCalled := false var displayedResult string - result, err := fetchWithFeedback("Test operation", func() (string, error) { - return "test value", nil - }, func(r string) { - displayCalled = true - displayedResult = r - }) + result, err := fetchWithFeedback( + t.Context(), + "Test operation", + func(context.Context) (string, error) { + return "test value", nil + }, + func(r string) { + displayCalled = true + displayedResult = r + }, + ) require.NoError(t, err) assert.Equal(t, "test value", result) @@ -121,17 +136,22 @@ func TestFetchWithFeedback_WithDisplay(t *testing.T) { } func TestFetchWithFeedback_SpinnerError(t *testing.T) { - originalSpinnerFunc := spinnerFunc + origSpinner := spinnerFunc - defer func() { spinnerFunc = originalSpinnerFunc }() + t.Cleanup(func() { spinnerFunc = origSpinner }) spinnerFunc = func(_ string) (spinner, error) { return nil, errors.New("spinner failed") } - _, err := fetchWithFeedback("Test operation", func() (string, error) { - return "should not reach", nil - }, nil) + _, err := fetchWithFeedback( + t.Context(), + "Test operation", + func(context.Context) (string, error) { + return "should not reach", nil + }, + nil, + ) require.Error(t, err) assert.Contains(t, err.Error(), "spinner failed") @@ -174,7 +194,7 @@ func TestCmd_Help(t *testing.T) { oldArgs := os.Args os.Args = []string{appName, "--help"} - defer func() { os.Args = oldArgs }() + t.Cleanup(func() { os.Args = oldArgs }) var err error @@ -190,7 +210,7 @@ func TestCmd_Version(t *testing.T) { oldArgs := os.Args os.Args = []string{appName, "--version"} - defer func() { os.Args = oldArgs }() + t.Cleanup(func() { os.Args = oldArgs }) testVersion := "test-version-123" @@ -227,7 +247,7 @@ func TestSetupColor_Never(t *testing.T) { // Simulate parsing the flag _ = cmd.Set("color", "never") - _, err := setupColor(context.Background(), cmd) + _, err := setupColor(t.Context(), cmd) require.NoError(t, err) assert.True(t, pterm.RawOutput, "pterm.RawOutput should be true after --color=never") } @@ -248,7 +268,7 @@ func TestSetupColor_Always(t *testing.T) { _ = cmd.Set("color", "always") - _, err := setupColor(context.Background(), cmd) + _, err := setupColor(t.Context(), cmd) require.NoError(t, err) assert.False(t, pterm.RawOutput, "pterm.RawOutput should be false after --color=always") } @@ -268,7 +288,7 @@ func TestSetupColor_AutoDefault(t *testing.T) { } // Don't set the flag - test default behavior - _, err := setupColor(context.Background(), cmd) + _, err := setupColor(t.Context(), cmd) require.NoError(t, err) // In test environment, stdout is typically not a terminal @@ -290,13 +310,13 @@ func TestOnUsageError(t *testing.T) { }, } - err := app.Run(context.Background(), []string{appName, "--invalid-flag"}) + err := app.Run(t.Context(), []string{appName, "--invalid-flag"}) require.Error(t, err) } func TestDebugFlagAction(t *testing.T) { pterm.DisableDebugMessages() - defer pterm.DisableDebugMessages() + t.Cleanup(pterm.DisableDebugMessages) var configFile string @@ -316,13 +336,13 @@ func TestDebugFlagAction(t *testing.T) { require.NotNil(t, debugFlag.Action) cmd := &cli.Command{Flags: flags} - err := debugFlag.Action(context.Background(), cmd, true) + err := debugFlag.Action(t.Context(), cmd, true) require.NoError(t, err) } func TestQuietFlagAction(t *testing.T) { pterm.EnableOutput() - defer pterm.EnableOutput() + t.Cleanup(pterm.EnableOutput) var configFile string @@ -342,7 +362,7 @@ func TestQuietFlagAction(t *testing.T) { require.NotNil(t, quietFlag.Action) cmd := &cli.Command{Flags: flags} - err := quietFlag.Action(context.Background(), cmd, true) + err := quietFlag.Action(t.Context(), cmd, true) require.NoError(t, err) } @@ -359,15 +379,15 @@ func TestGatewayInitErrors(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - originalInitFunc := initGatewayFunc + origInit := initGatewayFunc - defer func() { initGatewayFunc = originalInitFunc }() + t.Cleanup(func() { initGatewayFunc = origInit }) initGatewayFunc = func(_ *Config) (tmhi.Gateway, error) { return nil, errors.New("gateway init failed") } - err := tt.handler(context.Background(), nil) + err := tt.handler(t.Context(), nil) require.Error(t, err) assert.Contains(t, err.Error(), "gateway init failed") }) diff --git a/internal/config.go b/internal/config.go index 5c5026f..12d9015 100644 --- a/internal/config.go +++ b/internal/config.go @@ -48,8 +48,7 @@ func (c *Config) Validate() error { validation.Field(&c.Retries, validation.Min(0)), ) if err != nil { - var errs validation.Errors - if errors.As(err, &errs) { + if errs, ok := errors.AsType[validation.Errors](err); ok { for field, fieldErr := range errs { if fieldErr != nil { flagName := flagNameFromField(field) diff --git a/internal/integration_test.go b/internal/integration_test.go index 3d6b013..6529380 100644 --- a/internal/integration_test.go +++ b/internal/integration_test.go @@ -1,7 +1,6 @@ package internal import ( - "context" "errors" "testing" @@ -11,9 +10,9 @@ import ( ) func TestLoginIntegration_FullFlow(t *testing.T) { - original := initGatewayFunc + orig := initGatewayFunc - defer func() { initGatewayFunc = original }() + t.Cleanup(func() { initGatewayFunc = orig }) t.Run("successful login flow", func(t *testing.T) { mg := &mockGateway{} @@ -21,7 +20,7 @@ func TestLoginIntegration_FullFlow(t *testing.T) { return mg, nil } - err := login(context.Background(), nil) + err := login(t.Context(), nil) require.NoError(t, err) assert.True(t, mg.loginCalled, "login should be called") }) @@ -32,7 +31,7 @@ func TestLoginIntegration_FullFlow(t *testing.T) { return mg, nil } - err := login(context.Background(), nil) + err := login(t.Context(), nil) require.Error(t, err) assert.Contains(t, err.Error(), "Logging in...") assert.True(t, mg.loginCalled, "login should still be attempted") @@ -40,9 +39,9 @@ func TestLoginIntegration_FullFlow(t *testing.T) { } func TestInfoIntegration_FullFlow(t *testing.T) { - original := initGatewayFunc + orig := initGatewayFunc - defer func() { initGatewayFunc = original }() + t.Cleanup(func() { initGatewayFunc = orig }) t.Run("successful info retrieval", func(t *testing.T) { mg := &mockGateway{} @@ -50,7 +49,7 @@ func TestInfoIntegration_FullFlow(t *testing.T) { return mg, nil } - err := info(context.Background(), nil) + err := info(t.Context(), nil) require.NoError(t, err) assert.True(t, mg.infoCalled, "info should be called") }) @@ -61,7 +60,7 @@ func TestInfoIntegration_FullFlow(t *testing.T) { return mg, nil } - err := info(context.Background(), nil) + err := info(t.Context(), nil) require.Error(t, err) assert.Contains(t, err.Error(), "Fetching gateway info") assert.Contains(t, err.Error(), "info unavailable") @@ -70,9 +69,9 @@ func TestInfoIntegration_FullFlow(t *testing.T) { //nolint:dupl func TestStatusIntegration_FullFlow(t *testing.T) { - original := initGatewayFunc + orig := initGatewayFunc - defer func() { initGatewayFunc = original }() + t.Cleanup(func() { initGatewayFunc = orig }) t.Run("successful status check", func(t *testing.T) { mg := &mockGateway{} @@ -80,7 +79,7 @@ func TestStatusIntegration_FullFlow(t *testing.T) { return mg, nil } - err := status(context.Background(), nil) + err := status(t.Context(), nil) require.NoError(t, err) assert.True(t, mg.statusCalled, "status should be called") }) @@ -91,7 +90,7 @@ func TestStatusIntegration_FullFlow(t *testing.T) { return mg, nil } - err := status(context.Background(), nil) + err := status(t.Context(), nil) require.Error(t, err) assert.Contains(t, err.Error(), "Checking gateway status...") }) @@ -99,9 +98,9 @@ func TestStatusIntegration_FullFlow(t *testing.T) { //nolint:dupl func TestSignalIntegration_FullFlow(t *testing.T) { - original := initGatewayFunc + orig := initGatewayFunc - defer func() { initGatewayFunc = original }() + t.Cleanup(func() { initGatewayFunc = orig }) t.Run("successful signal retrieval", func(t *testing.T) { mg := &mockGateway{} @@ -109,7 +108,7 @@ func TestSignalIntegration_FullFlow(t *testing.T) { return mg, nil } - err := signalCmd(context.Background(), nil) + err := signalCmd(t.Context(), nil) require.NoError(t, err) assert.True(t, mg.signalCalled, "signal should be called") }) @@ -120,20 +119,20 @@ func TestSignalIntegration_FullFlow(t *testing.T) { return mg, nil } - err := signalCmd(context.Background(), nil) + err := signalCmd(t.Context(), nil) require.Error(t, err) assert.Contains(t, err.Error(), "Fetching signal information...") }) } func TestRebootIntegration_FullFlow(t *testing.T) { - original := initGatewayFunc - originalConfig := appConfig + origInit := initGatewayFunc + origConfig := appConfig - defer func() { - initGatewayFunc = original - appConfig = originalConfig - }() + t.Cleanup(func() { + initGatewayFunc = origInit + appConfig = origConfig + }) t.Run("successful reboot with auto-confirm", func(t *testing.T) { appConfig = &Config{DryRun: false} @@ -143,7 +142,7 @@ func TestRebootIntegration_FullFlow(t *testing.T) { } cmd := newRebootCmd(false) - err := reboot(context.Background(), cmd) + err := reboot(t.Context(), cmd) require.NoError(t, err) assert.True(t, mg.rebootCalled, "reboot should be called") }) @@ -156,7 +155,7 @@ func TestRebootIntegration_FullFlow(t *testing.T) { } cmd := newRebootCmd(true) - err := reboot(context.Background(), cmd) + err := reboot(t.Context(), cmd) require.NoError(t, err) assert.False(t, mg.rebootCalled, "reboot should not be called in dry-run mode") }) @@ -169,7 +168,7 @@ func TestRebootIntegration_FullFlow(t *testing.T) { } cmd := newRebootCmd(false) - err := reboot(context.Background(), cmd) + err := reboot(t.Context(), cmd) require.Error(t, err) assert.Contains(t, err.Error(), "Reboot failed: test failure") }) diff --git a/internal/ui_test.go b/internal/ui_test.go index aad1c95..7b86ce0 100644 --- a/internal/ui_test.go +++ b/internal/ui_test.go @@ -12,8 +12,7 @@ import ( func TestDisplayStatusResult(t *testing.T) { pterm.DisableStyling() - - defer pterm.EnableStyling() + t.Cleanup(pterm.EnableStyling) t.Run("web interface up", func(t *testing.T) { result := &tmhi.StatusResult{WebInterfaceUp: true} @@ -51,8 +50,7 @@ func TestDisplayStatusResult(t *testing.T) { func TestDisplaySignalResult(t *testing.T) { pterm.DisableStyling() - - defer pterm.EnableStyling() + t.Cleanup(pterm.EnableStyling) t.Run("with 4G signal", func(t *testing.T) { result := &tmhi.SignalResult{ @@ -146,8 +144,7 @@ func TestDisplaySignalResult(t *testing.T) { func TestDisplayInfoResult(t *testing.T) { pterm.DisableStyling() - - defer pterm.EnableStyling() + t.Cleanup(pterm.EnableStyling) result := &tmhi.InfoResult{}