// Package miot provides white-box tests for miot_client.go core client. // Complements existing tests in miot_test.go with additional coverage. package miot import ( "testing" ) // ============================================================================ // NewMIoTClient — field initialization // ============================================================================ func TestNewMIoTClient_FieldsInitialized(t *testing.T) { c := NewMIoTClient("entry1", map[string]interface{}{"key": "val"}, "uid1", "cn", CtrlModeCloud) if c.entryID != "entry1" { t.Errorf("entryID = %q, want 'entry1'", c.entryID) } if c.uid != "uid1" { t.Errorf("uid = %q, want 'uid1'", c.uid) } if c.cloudServer != "cn" { t.Errorf("cloudServer = %q, want 'cn'", c.cloudServer) } if c.ctx == nil { t.Error("ctx should not be nil") } if c.cancel == nil { t.Error("cancel should not be nil") } if c.subTree == nil { t.Error("subTree should not be nil") } if c.deviceListCache == nil { t.Error("deviceListCache should not be nil") } if c.refreshPropsList == nil { t.Error("refreshPropsList should not be nil") } if c.mipsLocal == nil { t.Error("mipsLocal should not be nil") } c.Stop() } func TestNewMIoTClient_NoEntryData(t *testing.T) { c := NewMIoTClient("entry2", nil, "uid2", "us", CtrlModeLAN) if c.ctrlMode != CtrlModeLAN { t.Errorf("ctrlMode = %v, want LAN", c.ctrlMode) } c.Stop() } // ============================================================================ // SetStorage / SetHTTPClient / SetMipsCloud / SetMipsLocal // ============================================================================ func TestSetStorage(t *testing.T) { c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud) defer c.Stop() s := NewMIoTStorage(t.TempDir()) c.SetStorage(s) if c.storage != s { t.Error("SetStorage did not set storage") } } func TestSetHTTPClient(t *testing.T) { c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud) defer c.Stop() http := &MIoTHttpClient{} c.SetHTTPClient(http) if c.http != http { t.Error("SetHTTPClient did not set http") } } func TestSetMipsCloud(t *testing.T) { c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud) mc := NewMipsCloudClient("ssl://host:8883", "client1", "user", "pass") c.SetMipsCloud(mc) if c.mipsCloud != mc { t.Error("SetMipsCloud did not set mipsCloud") } // Clean up: nil out mipsCloud before Stop/Deinit to avoid Disconnect panic c.mipsCloud = nil c.Stop() } func TestSetMipsLocal(t *testing.T) { c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud) ml := NewMipsLocalClient("did_local", "host", 8883, "", "", "") c.SetMipsLocal("group1", ml) if got := c.mipsLocal["group1"]; got != ml { t.Errorf("SetMipsLocal = %v, want %v", got, ml) } // Clean up before Stop c.mipsLocal = make(map[string]*MipsLocalClient) c.Stop() } // ============================================================================ // Init — no entryData (no HTTP client created) // ============================================================================ func TestInit_NoCredentials(t *testing.T) { c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud) defer c.Stop() s := NewMIoTStorage(t.TempDir()) c.SetStorage(s) err := c.Init() if err != nil { t.Fatalf("Init should not error: %v", err) } // Without entryData credentials, http should remain nil if c.http != nil { t.Error("http should be nil without credentials in entryData") } } func TestInit_WithCredentials(t *testing.T) { c := NewMIoTClient("test", map[string]interface{}{ "client_id": "test_client_id", "access_token": "test_token", }, "uid", "cn", CtrlModeCloud) defer c.Stop() s := NewMIoTStorage(t.TempDir()) c.SetStorage(s) err := c.Init() if err != nil { t.Fatalf("Init should not error: %v", err) } // With credentials, http should be created if c.http == nil { t.Error("http should not be nil with valid entryData credentials") } } // ============================================================================ // Deinit // ============================================================================ func TestDeinit_ClearsSubTree(t *testing.T) { c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud) defer c.Stop() // Add a subscription h := func(params map[string]interface{}, ctx interface{}) {} c.subTree.Sub("did1/p/1", h, nil) if c.subTree.Size() != 1 { t.Fatal("subTree should have 1 entry") } c.Deinit() if c.subTree.Size() != 0 { t.Error("subTree should be cleared after Deinit") } } // ============================================================================ // Start / Stop // ============================================================================ func TestStart(t *testing.T) { c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud) defer c.Stop() s := NewMIoTStorage(t.TempDir()) c.SetStorage(s) err := c.Start() if err != nil { t.Fatalf("Start should not error: %v", err) } } func TestStop(t *testing.T) { c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud) defer c.Stop() err := c.Stop() if err != nil { t.Errorf("Stop should not error: %v", err) } } // ============================================================================ // LoadDevices (complement to existing test) // ============================================================================ func TestLoadDevices_NoStorage(t *testing.T) { c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud) defer c.Stop() // LoadDevices without storage should not panic err := c.LoadDevices() // May error due to missing storage, but should not panic _ = err } // ============================================================================ // DeviceList copy // ============================================================================ func TestDeviceList_ReturnsCopy(t *testing.T) { c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud) defer c.Stop() c.deviceListMu.Lock() c.deviceListCache["did1"] = map[string]interface{}{"name": "test"} c.deviceListMu.Unlock() list1 := c.DeviceList() list2 := c.DeviceList() // Modifying one copy should not affect the other list1["new"] = map[string]interface{}{} if _, ok := list2["new"]; ok { t.Error("DeviceList should return independent copies") } } // ============================================================================ // loadCacheDevice // ============================================================================ func TestLoadCacheDevice_NoStorage(t *testing.T) { c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud) err := c.loadCacheDevice() if err == nil { t.Error("loadCacheDevice without storage should error") } c.Stop() } func TestLoadCacheDevice_WithStorage(t *testing.T) { c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud) defer c.Stop() s := NewMIoTStorage(t.TempDir()) c.SetStorage(s) err := c.loadCacheDevice() if err != nil { t.Fatalf("loadCacheDevice should succeed: %v", err) } // Cache should be initialized (empty) if c.deviceListCache == nil { t.Error("deviceListCache should not be nil") } }