Files
xiaomihome/miot/const_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

284 lines
8.4 KiB
Go

// Package miot_test provides black-box tests for const.go constants and enums.
package miot_test
import (
"strings"
"testing"
miot "git.zeroonesoft.cn/golib/xiaomihome/miot"
)
// ============================================================================
// CtrlMode.String()
// ============================================================================
func TestCtrlMode_String(t *testing.T) {
tests := []struct {
mode miot.CtrlMode
want string
}{
{miot.CtrlModeCloud, "cloud"},
{miot.CtrlModeGateway, "gateway"},
{miot.CtrlModeLAN, "lan"},
{miot.CtrlMode(99), "unknown"},
}
for _, tt := range tests {
t.Run(tt.want, func(t *testing.T) {
if got := tt.mode.String(); got != tt.want {
t.Errorf("CtrlMode(%d).String() = %q, want %q", tt.mode, got, tt.want)
}
})
}
}
func TestCtrlMode_IotaValues(t *testing.T) {
// Verify sequential iota values
if int(miot.CtrlModeCloud) != 0 {
t.Errorf("CtrlModeCloud = %d, want 0", miot.CtrlModeCloud)
}
if int(miot.CtrlModeGateway) != 1 {
t.Errorf("CtrlModeGateway = %d, want 1", miot.CtrlModeGateway)
}
if int(miot.CtrlModeLAN) != 2 {
t.Errorf("CtrlModeLAN = %d, want 2", miot.CtrlModeLAN)
}
}
// ============================================================================
// String Constants
// ============================================================================
func TestSupportedPlatforms(t *testing.T) {
if len(miot.SUPPORTED_PLATFORMS) == 0 {
t.Error("SUPPORTED_PLATFORMS should not be empty")
}
mustContain := []string{"switch", "light", "sensor", "binary_sensor", "climate", "cover"}
for _, p := range mustContain {
t.Run("contains_"+p, func(t *testing.T) {
found := false
for _, sp := range miot.SUPPORTED_PLATFORMS {
if sp == p {
found = true
break
}
}
if !found {
t.Errorf("SUPPORTED_PLATFORMS should contain %q", p)
}
})
}
}
func TestUnsupportedModels(t *testing.T) {
if len(miot.UNSUPPORTED_MODELS) == 0 {
t.Error("UNSUPPORTED_MODELS should not be empty")
}
// All entries should be non-empty strings
for i, m := range miot.UNSUPPORTED_MODELS {
if m == "" {
t.Errorf("UNSUPPORTED_MODELS[%d] is empty", i)
}
}
}
func TestCloudServers(t *testing.T) {
mustHave := []string{"cn", "de", "us", "ru", "sg", "i2"}
for _, k := range mustHave {
t.Run("contains_"+k, func(t *testing.T) {
if name, ok := miot.CLOUD_SERVERS[k]; !ok || name == "" {
t.Errorf("CLOUD_SERVERS should contain key %q with non-empty name", k)
}
})
}
}
func TestIntegrationLanguages(t *testing.T) {
mustHave := map[string]string{
"en": "English",
"zh-Hans": "简体中文",
"zh-Hant": "繁體中文",
}
for code, name := range mustHave {
t.Run(code, func(t *testing.T) {
if got, ok := miot.INTEGRATION_LANGUAGES[code]; !ok || got != name {
t.Errorf("INTEGRATION_LANGUAGES[%q] = %q, want %q", code, got, name)
}
})
}
}
func TestSupportedCentralGatewayCtrl(t *testing.T) {
if len(miot.SUPPORT_CENTRAL_GATEWAY_CTRL) == 0 {
t.Error("SUPPORT_CENTRAL_GATEWAY_CTRL should not be empty")
}
// "cn" must be in the list
found := false
for _, r := range miot.SUPPORT_CENTRAL_GATEWAY_CTRL {
if r == "cn" {
found = true
break
}
}
if !found {
t.Error("SUPPORT_CENTRAL_GATEWAY_CTRL should contain \"cn\"")
}
}
// ============================================================================
// Numeric Constants
// ============================================================================
func TestNumericConstants(t *testing.T) {
tests := []struct {
name string
value int
min int
max int
}{
{"MIHOME_HTTP_API_TIMEOUT", miot.MIHOME_HTTP_API_TIMEOUT, 1, 120},
{"MIHOME_MQTT_KEEPALIVE", miot.MIHOME_MQTT_KEEPALIVE, 1, 3600},
{"MIHOME_CERT_EXPIRE_MARGIN", miot.MIHOME_CERT_EXPIRE_MARGIN, 1, 3600 * 24 * 30},
{"NETWORK_REFRESH_INTERVAL", miot.NETWORK_REFRESH_INTERVAL, 1, 3600},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.value < tt.min || tt.value > tt.max {
t.Errorf("%s = %d, expected between %d and %d", tt.name, tt.value, tt.min, tt.max)
}
})
}
}
func TestRefreshConstants(t *testing.T) {
if miot.RefreshPropsDelay <= 0 {
t.Errorf("RefreshPropsDelay = %d, should be positive", miot.RefreshPropsDelay)
}
if miot.RefreshPropsRetryMax <= 0 {
t.Errorf("RefreshPropsRetryMax = %d, should be positive", miot.RefreshPropsRetryMax)
}
if miot.RefreshPropsRetryDelay <= 0 {
t.Errorf("RefreshPropsRetryDelay = %d, should be positive", miot.RefreshPropsRetryDelay)
}
if miot.RefreshCloudDevicesDelay <= 0 {
t.Errorf("RefreshCloudDevicesDelay = %d, should be positive", miot.RefreshCloudDevicesDelay)
}
}
// ============================================================================
// CA Certificate Constants
// ============================================================================
func TestCA_Cert(t *testing.T) {
if miot.MIHOME_CA_CERT_STR == "" {
t.Error("MIHOME_CA_CERT_STR should not be empty")
}
if !strings.HasPrefix(miot.MIHOME_CA_CERT_STR, "-----BEGIN CERTIFICATE-----") {
t.Error("MIHOME_CA_CERT_STR should start with BEGIN CERTIFICATE")
}
if len(miot.MIHOME_CA_CERT_SHA256) != 64 {
t.Errorf("MIHOME_CA_CERT_SHA256 length = %d, want 64 (SHA256 hex)", len(miot.MIHOME_CA_CERT_SHA256))
}
}
// ============================================================================
// MQTT Topics
// ============================================================================
func TestMQTTTopics(t *testing.T) {
if miot.TopicProp != "properties_changed" {
t.Errorf("TopicProp = %q, want %q", miot.TopicProp, "properties_changed")
}
if miot.TopicEvent != "event_occured" {
t.Errorf("TopicEvent = %q, want %q", miot.TopicEvent, "event_occured")
}
if miot.TopicState != "state" {
t.Errorf("TopicState = %q, want %q", miot.TopicState, "state")
}
}
// ============================================================================
// API Paths
// ============================================================================
func TestAPIPaths(t *testing.T) {
if miot.APIPathGetDevices == "" {
t.Error("APIPathGetDevices should not be empty")
}
if miot.APIPathGetProps == "" {
t.Error("APIPathGetProps should not be empty")
}
if miot.APIPathSetProps == "" {
t.Error("APIPathSetProps should not be empty")
}
if miot.APIPathDoAction == "" {
t.Error("APIPathDoAction should not be empty")
}
}
// ============================================================================
// Default Values
// ============================================================================
func TestDefaultValues(t *testing.T) {
if miot.DefaultCloudServer != "cn" {
t.Errorf("DefaultCloudServer = %q, want %q", miot.DefaultCloudServer, "cn")
}
if miot.DefaultOAUTH2APIHost == "" {
t.Error("DefaultOAUTH2APIHost should not be empty")
}
if miot.MHomeHTTPAPITimeout <= 0 {
t.Errorf("MHomeHTTPAPITimeout = %d, should be positive", miot.MHomeHTTPAPITimeout)
}
if miot.DefaultMQTTBroker == "" {
t.Error("DefaultMQTTBroker should not be empty")
}
if miot.DefaultMQTTKeepAlive <= 0 {
t.Errorf("DefaultMQTTKeepAlive = %d, should be positive", miot.DefaultMQTTKeepAlive)
}
if miot.DefaultMQTTQoS < 0 || miot.DefaultMQTTQoS > 2 {
t.Errorf("DefaultMQTTQoS = %d, should be between 0 and 2", miot.DefaultMQTTQoS)
}
}
// ============================================================================
// Domain and OAuth Constants
// ============================================================================
func TestDomainConstants(t *testing.T) {
tests := []struct {
name string
value string
}{
{"DOMAIN", miot.DOMAIN},
{"DEFAULT_NAME", miot.DEFAULT_NAME},
{"OAUTH2_CLIENT_ID", miot.OAUTH2_CLIENT_ID},
{"OAUTH2_AUTH_URL", miot.OAUTH2_AUTH_URL},
{"OAUTH_REDIRECT_URL", miot.OAUTH_REDIRECT_URL},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.value == "" {
t.Errorf("%s should not be empty", tt.name)
}
})
}
}
// ============================================================================
// Cover Dead Zone
// ============================================================================
func TestCoverDeadZone(t *testing.T) {
if miot.DEFAULT_COVER_DEAD_ZONE_WIDTH < miot.MIN_COVER_DEAD_ZONE_WIDTH {
t.Errorf("DEFAULT_COVER_DEAD_ZONE_WIDTH (%d) < MIN (%d)",
miot.DEFAULT_COVER_DEAD_ZONE_WIDTH, miot.MIN_COVER_DEAD_ZONE_WIDTH)
}
if miot.DEFAULT_COVER_DEAD_ZONE_WIDTH > miot.MAX_COVER_DEAD_ZONE_WIDTH {
t.Errorf("DEFAULT_COVER_DEAD_ZONE_WIDTH (%d) > MAX (%d)",
miot.DEFAULT_COVER_DEAD_ZONE_WIDTH, miot.MAX_COVER_DEAD_ZONE_WIDTH)
}
}