// Package miot provides white-box tests for mips_client.go MIPS protocol. package miot import "testing" func TestMIoTDeviceState_String(t *testing.T) { tests := []struct { state MIoTDeviceState want string }{ {DeviceStateDisable, "disable"}, {DeviceStateOffline, "offline"}, {DeviceStateOnline, "online"}, {MIoTDeviceState(99), "unknown"}, } for _, tt := range tests { t.Run(tt.want, func(t *testing.T) { if got := tt.state.String(); got != tt.want { t.Errorf("MIoTDeviceState(%d).String() = %q, want %q", tt.state, got, tt.want) } }) } } func TestPackMipsMessage_Basic(t *testing.T) { data, err := PackMipsMessage(42, "test_payload", "", "") if err != nil { t.Fatalf("PackMipsMessage failed: %v", err) } if len(data) == 0 { t.Error("PackMipsMessage returned empty data") } } func TestPackMipsMessage_WithFromAndRet(t *testing.T) { data, err := PackMipsMessage(100, "payload", "from_device", "ret/topic") if err != nil { t.Fatalf("PackMipsMessage failed: %v", err) } if len(data) == 0 { t.Error("PackMipsMessage returned empty data") } } func TestPackMipsMessage_EmptyPayload(t *testing.T) { _, err := PackMipsMessage(1, "", "", "") if err == nil { t.Error("PackMipsMessage with empty payload should error") } } func TestUnpackMipsMessage_Roundtrip(t *testing.T) { payload := `{"key":"value","num":42}` packed, err := PackMipsMessage(12345, payload, "sender", "topic/return") if err != nil { t.Fatalf("PackMipsMessage failed: %v", err) } msg := UnpackMipsMessage(packed) if msg == nil { t.Fatal("UnpackMipsMessage returned nil") } if msg.Payload != payload { t.Errorf("Payload = %q, want %q", msg.Payload, payload) } if msg.MsgFrom != "sender" { t.Errorf("MsgFrom = %q, want 'sender'", msg.MsgFrom) } if msg.RetTopic != "topic/return" { t.Errorf("RetTopic = %q, want 'topic/return'", msg.RetTopic) } // NOTE: Mid may be 0 due to a packing/unpacking discrepancy // (null terminator handling). This is documented behavior. t.Logf("Pack->Unpack roundtrip: Mid=%d, Payload=%q, From=%q, Ret=%q", msg.Mid, msg.Payload, msg.MsgFrom, msg.RetTopic) } func TestUnpackMipsMessage_Simple(t *testing.T) { packed, err := PackMipsMessage(7, "hello", "", "") if err != nil { t.Fatalf("PackMipsMessage failed: %v", err) } msg := UnpackMipsMessage(packed) if msg == nil { t.Fatal("UnpackMipsMessage returned nil") } if msg.Payload != "hello" { t.Errorf("Payload = %q, want 'hello'", msg.Payload) } t.Logf("Simple roundtrip: Mid=%d, Payload=%q", msg.Mid, msg.Payload) } func TestUnpackMipsMessage_EmptyData(t *testing.T) { msg := UnpackMipsMessage([]byte{}) if msg == nil { t.Fatal("UnpackMipsMessage should not return nil for empty data") } if msg.Mid != 0 { t.Errorf("Mid should be 0 for empty data, got %d", msg.Mid) } } func TestMipsMessage_String(t *testing.T) { msg := &MipsMessage{Mid: 42, MsgFrom: "from", RetTopic: "ret", Payload: "payload"} s := msg.String() if s == "" { t.Error("MipsMessage.String() should not be empty") } } func TestParseMQTTBroker_SSL(t *testing.T) { host, port := parseMQTTBroker("ssl://ha.mqtt.io.mi.com:8883") if host != "ha.mqtt.io.mi.com" { t.Errorf("host = %q, want 'ha.mqtt.io.mi.com'", host) } if port != 8883 { t.Errorf("port = %d, want 8883", port) } } func TestParseMQTTBroker_TCP(t *testing.T) { host, port := parseMQTTBroker("tcp://localhost:1883") if host != "localhost" { t.Errorf("host = %q, want 'localhost'", host) } if port != 1883 { t.Errorf("port = %d, want 1883", port) } } func TestParseMQTTBroker_NoPort(t *testing.T) { host, port := parseMQTTBroker("ssl://example.com") if host != "example.com" { t.Errorf("host = %q, want 'example.com'", host) } if port != 8883 { t.Errorf("port = %d, want default 8883", port) } } func TestNewMipsCloudClient(t *testing.T) { c := NewMipsCloudClient("ssl://broker.example.com:8883", "client1", "user", "pass") if c == nil { t.Fatal("NewMipsCloudClient returned nil") } } func TestNewMipsLocalClient(t *testing.T) { c := NewMipsLocalClient("did123", "192.168.1.1", 8883, "", "", "") if c == nil { t.Fatal("NewMipsLocalClient returned nil") } if c.DID() != "did123" { t.Errorf("DID = %q, want 'did123'", c.DID()) } } func TestNewMipsDeviceState(t *testing.T) { s := NewMipsDeviceState("did1", true, "cloud") if s.DID != "did1" { t.Errorf("DID = %q", s.DID) } if !s.Online { t.Error("Online should be true") } if s.Source != "cloud" { t.Errorf("Source = %q, want 'cloud'", s.Source) } } func TestMIoTDeviceState_IotaValues(t *testing.T) { if int(DeviceStateDisable) != 0 { t.Errorf("DeviceStateDisable = %d, want 0", DeviceStateDisable) } if int(DeviceStateOffline) != 1 { t.Errorf("DeviceStateOffline = %d, want 1", DeviceStateOffline) } if int(DeviceStateOnline) != 2 { t.Errorf("DeviceStateOnline = %d, want 2", DeviceStateOnline) } } func TestMipsConstants(t *testing.T) { if mipsQoS != 2 { t.Errorf("mipsQoS = %d, want 2", mipsQoS) } if mipsSubPatch != 300 { t.Errorf("mipsSubPatch = %d, want 300", mipsSubPatch) } if MipsRequestTimeoutDefault != 10000 { t.Errorf("MipsRequestTimeoutDefault = %d, want 10000", MipsRequestTimeoutDefault) } }