Files
xiaomihome/miot/miot_error_test.go
T
4566704 cdc459b5ff fix(xiaomihome): 模块路径改为 git.zeroonesoft.cn/golib/xiaomihome
- 改动:go.mod module 声明与全部内部导入路径补全为完整域名路径,README 同步
- 原因:裸模块名无法被 go get 解析,发版前必须修正为 GOPRIVATE 可拉取路径
2026-10-05 08:53:23 +08:00

234 lines
7.6 KiB
Go

// 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"])
}
}