package errors_test import ( stderrors "errors" "strings" "testing" apperrors "git.tukangketik.id/swanadiva/hostkeeper/internal/errors" ) func TestAppError(t *testing.T) { cause := stderrors.New("underlying issue") appErr := apperrors.NewAppError( apperrors.ErrAuthFailed, "Authentication failed", cause, []string{"Check credentials", "Verify key permissions"}, ) if appErr.Code != apperrors.ErrAuthFailed { t.Errorf("Expected code '%s', got '%s'", apperrors.ErrAuthFailed, appErr.Code) } if len(appErr.Hints) != 2 { t.Errorf("Expected 2 hints, got %d", len(appErr.Hints)) } // Test error message is non-empty if appErr.Error() == "" { t.Error("Expected non-empty error message") } // Test Unwrap if !stderrors.Is(appErr, cause) { t.Error("Expected errors.Is to match the cause via Unwrap") } } func TestConnectionError(t *testing.T) { connErr := apperrors.NewConnectionError( "auth", "Authentication failed", "ssh: handshake failed", []string{"Check credentials", "Verify key permissions"}, ) if connErr.Type != "auth" { t.Errorf("Expected type 'auth', got '%s'", connErr.Type) } if len(connErr.Hints) != 2 { t.Errorf("Expected 2 hints, got %d", len(connErr.Hints)) } if connErr.Error() == "" { t.Error("Expected non-empty error message") } } func TestHandleSSHError(t *testing.T) { tests := []struct { name string inputErr error expectedType string }{ { name: "connection refused", inputErr: stderrors.New("dial tcp: connection refused"), expectedType: "network", }, { name: "authentication failed", inputErr: stderrors.New("ssh: handshake failed: ssh: unable to authenticate"), expectedType: "auth", }, { name: "timeout", inputErr: stderrors.New("dial tcp: connection timed out"), expectedType: "timeout", }, { name: "no such host", inputErr: stderrors.New("dial tcp: lookup: no such host"), expectedType: "config", }, { name: "permission denied", inputErr: stderrors.New("ssh: permission denied"), expectedType: "auth", }, { name: "unknown error", inputErr: stderrors.New("something went wrong"), expectedType: "unknown", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { connErr := apperrors.HandleSSHError(tt.inputErr) if connErr == nil { t.Fatal("Expected non-nil ConnectionError") } if connErr.Type != tt.expectedType { t.Errorf("Expected type '%s', got '%s'", tt.expectedType, connErr.Type) } if len(connErr.Hints) == 0 { t.Error("Expected at least one hint") } }) } } func TestHandleSSHErrorNil(t *testing.T) { result := apperrors.HandleSSHError(nil) if result != nil { t.Error("Expected nil for nil input") } } func TestFormatConnectionError(t *testing.T) { connErr := apperrors.NewConnectionError( "auth", "Authentication failed", "ssh: handshake failed", []string{"Check credentials", "Verify key permissions"}, ) output := apperrors.FormatConnectionError(connErr) if output == "" { t.Error("Expected non-empty formatted output") } if !strings.Contains(output, "Authentication failed") { t.Error("Expected output to contain error message") } if !strings.Contains(output, "Possible solutions") { t.Error("Expected output to contain hints section") } }