- 改动:go.mod module 声明与全部内部导入路径补全为完整域名路径,README 同步 - 原因:裸模块名无法被 go get 解析,发版前必须修正为 GOPRIVATE 可拉取路径
234 lines
7.6 KiB
Go
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"])
|
|
}
|
|
}
|