feat: 初始化小米 IoT (MIoT) 智能家居 Go 库
- 实现 MIoT 客户端核心功能(MQTT 连接、设备管理、属性读写) - 支持云端 API 调用与局域网设备发现(mDNS) - 集成国际化(i18n)多语言支持 - 添加 MIoT 设备规约解析器(spec_parser) - 包含单元测试与使用示例
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
// Package miot provides white-box tests for miot_cloud.go cloud API client.
|
||||
package miot
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestToFloat64(t *testing.T) {
|
||||
tests := []struct {
|
||||
input interface{}
|
||||
want float64
|
||||
}{
|
||||
{float64(3.14), 3.14},
|
||||
{int(5), 5.0},
|
||||
{int64(10), 10.0},
|
||||
{"123", 123.0},
|
||||
{nil, 0.0},
|
||||
{true, 0.0},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got := toFloat64(tt.input)
|
||||
if got != tt.want {
|
||||
t.Errorf("toFloat64(%v) = %f, want %f", tt.input, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToSlice(t *testing.T) {
|
||||
if s := toSlice(nil); s != nil {
|
||||
t.Errorf("toSlice(nil) = %v, want nil", s)
|
||||
}
|
||||
if s := toSlice([]interface{}{"a", "b"}); len(s) != 2 {
|
||||
t.Errorf("toSlice len = %d, want 2", len(s))
|
||||
}
|
||||
if s := toSlice("not_a_slice"); s != nil {
|
||||
t.Errorf("toSlice(string) = %v, want nil", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestToStringSlice(t *testing.T) {
|
||||
s := toStringSlice([]string{"a", "b", "c"})
|
||||
if len(s) != 3 || s[0] != "a" {
|
||||
t.Errorf("toStringSlice([]string) = %v", s)
|
||||
}
|
||||
s = toStringSlice([]interface{}{"x", "y"})
|
||||
if len(s) != 2 || s[1] != "y" {
|
||||
t.Errorf("toStringSlice([]interface{}) = %v", s)
|
||||
}
|
||||
s = toStringSlice([]interface{}{"str", 42})
|
||||
if s[1] != "42" {
|
||||
t.Errorf("toStringSlice with int = %v, want '42'", s)
|
||||
}
|
||||
s = toStringSlice(nil)
|
||||
if s != nil {
|
||||
t.Errorf("toStringSlice(nil) should be nil, got %v", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsUnsupportedModel(t *testing.T) {
|
||||
if !isUnsupportedModel("chuangmi.ir.v2") {
|
||||
t.Error("chuangmi.ir.v2 should be unsupported")
|
||||
}
|
||||
if isUnsupportedModel("lumi.plug.v1") {
|
||||
t.Error("lumi.plug.v1 should be supported")
|
||||
}
|
||||
if isUnsupportedModel("") {
|
||||
t.Error("empty string should be supported")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsString(t *testing.T) {
|
||||
slice := []string{"a", "b", "c"}
|
||||
if !containsString(slice, "b") {
|
||||
t.Error("should contain 'b'")
|
||||
}
|
||||
if containsString(slice, "z") {
|
||||
t.Error("should not contain 'z'")
|
||||
}
|
||||
if containsString(nil, "a") {
|
||||
t.Error("nil slice should not contain anything")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewMIoTHttpClient_Basic(t *testing.T) {
|
||||
client, err := NewMIoTHttpClient("cn", "client_id_123", "access_token_abc")
|
||||
if err != nil {
|
||||
t.Fatalf("NewMIoTHttpClient failed: %v", err)
|
||||
}
|
||||
if client == nil {
|
||||
t.Fatal("client should not be nil")
|
||||
}
|
||||
client.Close()
|
||||
}
|
||||
|
||||
func TestNewMIoTHttpClient_NonCN(t *testing.T) {
|
||||
client, err := NewMIoTHttpClient("us", "id", "token")
|
||||
if err != nil {
|
||||
t.Fatalf("NewMIoTHttpClient for us failed: %v", err)
|
||||
}
|
||||
client.Close()
|
||||
}
|
||||
|
||||
func TestNewMIoTOauthClient_Basic(t *testing.T) {
|
||||
oa := NewMIoTOauthClient("2882303761520251711", "http://localhost/callback", "cn", "test-uuid")
|
||||
if oa == nil {
|
||||
t.Fatal("NewMIoTOauthClient returned nil")
|
||||
}
|
||||
s := oa.State()
|
||||
if s == "" {
|
||||
t.Error("State should not be empty")
|
||||
}
|
||||
oa.Close()
|
||||
}
|
||||
|
||||
func TestGenAuthURL(t *testing.T) {
|
||||
oa := NewMIoTOauthClient("2882303761520251711", "http://localhost/callback", "cn", "test-uuid")
|
||||
defer oa.Close()
|
||||
|
||||
url := oa.GenAuthURL("", "", nil, false)
|
||||
if url == "" {
|
||||
t.Error("GenAuthURL returned empty string")
|
||||
}
|
||||
|
||||
url2 := oa.GenAuthURL("http://custom/callback", "mystate", []string{"scope1", "scope2"}, true)
|
||||
if url2 == "" {
|
||||
t.Error("GenAuthURL with params returned empty string")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateHTTPHeader_CN(t *testing.T) {
|
||||
client, err := NewMIoTHttpClient("cn", "id1", "tok1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer client.Close()
|
||||
client.UpdateHTTPHeader("cn", "new_id", "new_token")
|
||||
}
|
||||
|
||||
func TestUpdateHTTPHeader_NonCN(t *testing.T) {
|
||||
client, err := NewMIoTHttpClient("us", "id1", "tok1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer client.Close()
|
||||
client.UpdateHTTPHeader("de", "id2", "tok2")
|
||||
}
|
||||
|
||||
func TestMihomeAPIGet_Success(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
t.Errorf("expected GET, got %s", r.Method)
|
||||
}
|
||||
resp := map[string]interface{}{"code": float64(0), "message": "ok", "result": map[string]interface{}{"data": "test"}}
|
||||
json.NewEncoder(w).Encode(resp)
|
||||
}))
|
||||
defer server.Close()
|
||||
_ = server
|
||||
}
|
||||
|
||||
func TestPropParam_Struct(t *testing.T) {
|
||||
p := PropParam{DID: "did1", Siid: 2, Piid: 1, Value: "on"}
|
||||
if p.DID != "did1" || p.Siid != 2 || p.Piid != 1 {
|
||||
t.Error("PropParam fields wrong")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPropResult_Struct(t *testing.T) {
|
||||
r := PropResult{DID: "did1", Siid: 2, Piid: 1, Code: 0, Value: "ok"}
|
||||
if r.Code != 0 {
|
||||
t.Errorf("PropResult Code = %d, want 0", r.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMIoTHttpClient_Close(t *testing.T) {
|
||||
client, err := NewMIoTHttpClient("cn", "id", "token")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
client.Close()
|
||||
client.Close()
|
||||
}
|
||||
|
||||
func TestTokenExpiresTSRatio(t *testing.T) {
|
||||
if TokenExpiresTSRatio <= 0 || TokenExpiresTSRatio >= 1.0 {
|
||||
t.Errorf("TokenExpiresTSRatio = %f, should be between 0 and 1", TokenExpiresTSRatio)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user