// Package miot_test provides black-box tests for miot_error.go error types. package miot_test import ( "fmt" "strings" "testing" miot "git.zeroonesoft.cn/golib/xiaomihome/miot" ) // ============================================================================ // Helper: verify error fields // ============================================================================ func checkError(t *testing.T, err error, wantCode int, wantMsg string, typeName string) { t.Helper() if err == nil { t.Fatal("expected non-nil error") } // Check Error() format errStr := err.Error() expected := fmt.Sprintf("code=%d, message=%s", wantCode, wantMsg) if errStr != expected { t.Errorf("%s.Error() = %q, want %q", typeName, errStr, expected) } // Check type assertion asserted := false switch err.(type) { case *miot.MIoTOauthError: asserted = typeName == "MIoTOauthError" case *miot.MIoTHttpError: asserted = typeName == "MIoTHttpError" case *miot.MIoTMipsError: asserted = typeName == "MIoTMipsError" case *miot.MIoTDeviceError: asserted = typeName == "MIoTDeviceError" case *miot.MIoTSpecError: asserted = typeName == "MIoTSpecError" case *miot.MIoTStorageError: asserted = typeName == "MIoTStorageError" case *miot.MIoTCertError: asserted = typeName == "MIoTCertError" case *miot.MIoTClientError: asserted = typeName == "MIoTClientError" case *miot.MIoTEvError: asserted = typeName == "MIoTEvError" case *miot.MipsServiceError: asserted = typeName == "MipsServiceError" case *miot.MIoTConfigError: asserted = typeName == "MIoTConfigError" case *miot.MIoTOptionsError: asserted = typeName == "MIoTOptionsError" case *miot.MIoTLanError: asserted = typeName == "MIoTLanError" } if !asserted { t.Errorf("expected %s type, got %T", typeName, err) } } func checkToDict(t *testing.T, err error, wantCode int, wantMsg string) { t.Helper() // All MIoT*Error types embed MIoTError, so we can cast to that var miotErr interface{ ToDict() map[string]interface{} } switch e := err.(type) { case *miot.MIoTOauthError: miotErr = e case *miot.MIoTHttpError: miotErr = e case *miot.MIoTMipsError: miotErr = e case *miot.MIoTDeviceError: miotErr = e case *miot.MIoTSpecError: miotErr = e case *miot.MIoTStorageError: miotErr = e case *miot.MIoTCertError: miotErr = e case *miot.MIoTClientError: miotErr = e case *miot.MIoTEvError: miotErr = e case *miot.MipsServiceError: miotErr = e case *miot.MIoTConfigError: miotErr = e case *miot.MIoTOptionsError: miotErr = e case *miot.MIoTLanError: miotErr = e default: t.Fatalf("unknown error type: %T", err) return } dict := miotErr.ToDict() if code, ok := dict["code"].(int); !ok || code != wantCode { t.Errorf("ToDict() code = %v, want %d", dict["code"], wantCode) } if msg, ok := dict["message"].(string); !ok || msg != wantMsg { t.Errorf("ToDict() message = %v, want %q", dict["message"], wantMsg) } } // ============================================================================ // All 12 Error Constructors // ============================================================================ func TestNewMIoTOauthError(t *testing.T) { err := miot.NewMIoTOauthError("oauth failed") checkError(t, err, miot.CodeOauthUnauthorized, "oauth failed", "MIoTOauthError") checkToDict(t, err, miot.CodeOauthUnauthorized, "oauth failed") } func TestNewMIoTHttpError(t *testing.T) { err := miot.NewMIoTHttpError("http failed") checkError(t, err, miot.CodeHttpInvalidAccessToken, "http failed", "MIoTHttpError") checkToDict(t, err, miot.CodeHttpInvalidAccessToken, "http failed") } func TestNewMIoTMipsError(t *testing.T) { err := miot.NewMIoTMipsError("mips failed") checkError(t, err, miot.CodeMipsInvalidResult, "mips failed", "MIoTMipsError") checkToDict(t, err, miot.CodeMipsInvalidResult, "mips failed") } func TestNewMIoTDeviceError(t *testing.T) { err := miot.NewMIoTDeviceError("device failed") checkError(t, err, miot.CodeUnknown, "device failed", "MIoTDeviceError") checkToDict(t, err, miot.CodeUnknown, "device failed") } func TestNewMIoTSpecError(t *testing.T) { err := miot.NewMIoTSpecError("spec failed") checkError(t, err, miot.CodeUnknown, "spec failed", "MIoTSpecError") checkToDict(t, err, miot.CodeUnknown, "spec failed") } func TestNewMIoTStorageError(t *testing.T) { err := miot.NewMIoTStorageError("storage failed") checkError(t, err, miot.CodeUnknown, "storage failed", "MIoTStorageError") checkToDict(t, err, miot.CodeUnknown, "storage failed") } func TestNewMIoTCertError(t *testing.T) { err := miot.NewMIoTCertError("cert failed") checkError(t, err, miot.CodeCertInvalidCert, "cert failed", "MIoTCertError") checkToDict(t, err, miot.CodeCertInvalidCert, "cert failed") } func TestNewMIoTClientError(t *testing.T) { err := miot.NewMIoTClientError("client failed") checkError(t, err, miot.CodeUnknown, "client failed", "MIoTClientError") checkToDict(t, err, miot.CodeUnknown, "client failed") } func TestNewMIoTEvError(t *testing.T) { err := miot.NewMIoTEvError("event failed") checkError(t, err, miot.CodeUnknown, "event failed", "MIoTEvError") checkToDict(t, err, miot.CodeUnknown, "event failed") } func TestNewMipsServiceError(t *testing.T) { err := miot.NewMipsServiceError("service failed") checkError(t, err, miot.CodeUnknown, "service failed", "MipsServiceError") checkToDict(t, err, miot.CodeUnknown, "service failed") } func TestNewMIoTConfigError(t *testing.T) { err := miot.NewMIoTConfigError("config failed") checkError(t, err, miot.CodeConfigInvalidInput, "config failed", "MIoTConfigError") checkToDict(t, err, miot.CodeConfigInvalidInput, "config failed") } func TestNewMIoTOptionsError(t *testing.T) { err := miot.NewMIoTOptionsError("options failed") checkError(t, err, miot.CodeUnknown, "options failed", "MIoTOptionsError") checkToDict(t, err, miot.CodeUnknown, "options failed") } func TestNewMIoTLanError(t *testing.T) { err := miot.NewMIoTLanError("lan failed") checkError(t, err, miot.CodeLanUnavailable, "lan failed", "MIoTLanError") checkToDict(t, err, miot.CodeLanUnavailable, "lan failed") } // ============================================================================ // Empty message // ============================================================================ func TestErrors_EmptyMessage(t *testing.T) { err := miot.NewMIoTDeviceError("") if err == nil { t.Fatal("expected non-nil error") } // Error() with empty message should still be valid if !strings.Contains(err.Error(), "message=") { t.Errorf("Error() should contain 'message=', got %q", err.Error()) } } // ============================================================================ // Error implements error interface // ============================================================================ func TestErrors_ImplementsErrorInterface(t *testing.T) { var _ error = miot.NewMIoTDeviceError("test") var _ error = miot.NewMIoTOauthError("test") var _ error = miot.NewMIoTHttpError("test") // Compile-time check — if this compiles, it passes } // ============================================================================ // MIoTError embedded in sub-types // ============================================================================ func TestMIoTError_EmbeddedAccess(t *testing.T) { err := miot.NewMIoTDeviceError("test message") // The embedded MIoTError fields should be accessible via the Error() method if !strings.Contains(err.Error(), "test message") { t.Errorf("Error() = %q, should contain 'test message'", err.Error()) } // MIoTError.ToDict() should be accessible on sub-error types dict := err.ToDict() if dict["message"] != "test message" { t.Errorf("ToDict() message = %v, want 'test message'", dict["message"]) } }