package backthink import ( "context" "errors" "testing" "git.yeij.top/AskaEth/Cyrene_v2/internal/config" "git.yeij.top/AskaEth/Cyrene_v2/internal/iot" ) // stateMockProvider is a tiny iot.Provider that returns a heart-rate watch, a // sleep band and a working-calendar device, to exercise the state decoding. type stateMockProvider struct{} func (stateMockProvider) Name() string { return "state-mock" } func (stateMockProvider) List(context.Context) ([]iot.Device, error) { return []iot.Device{ {ID: "watch.heart", Name: "心率手表", Type: "sensor", State: map[string]any{"bpm": 62}}, {ID: "band.sleep", Name: "睡眠手环", Type: "sensor", State: map[string]any{"sleeping": true}}, {ID: "cal.schedule", Name: "日程", State: map[string]any{"working": true}}, }, nil } func (stateMockProvider) Control(context.Context, string, string, map[string]any) (*iot.Device, error) { return nil, iot.ErrUnsupported } func (stateMockProvider) Status(context.Context, string) (*iot.Device, error) { return nil, iot.ErrDeviceNotFound } func TestIoTStateProvider_Current(t *testing.T) { t.Parallel() mgr, err := iot.New(config.IoTConfig{Provider: "none"}, nil) if err != nil { t.Fatalf("iot.New: %v", err) } if err := mgr.Register(stateMockProvider{}); err != nil { t.Fatalf("Register: %v", err) } p := NewIoTStateProvider(mgr, nil) st, err := p.Current(context.Background()) if err != nil { t.Fatalf("Current: %v", err) } if st.HeartRateBPM != 62 { t.Fatalf("HeartRateBPM = %d, want 62", st.HeartRateBPM) } if !st.Sleeping { t.Fatalf("Sleeping = false, want true") } if !st.Working { t.Fatalf("Working = false, want true") } } func TestIoTStateProvider_NilManager(t *testing.T) { t.Parallel() p := NewIoTStateProvider(nil, nil) _, err := p.Current(context.Background()) if !errors.Is(err, iot.ErrProviderNotRegistered) { t.Fatalf("err = %v, want ErrProviderNotRegistered", err) } } func TestIoTStateProvider_EmptyNeutral(t *testing.T) { t.Parallel() mgr, err := iot.New(config.IoTConfig{Provider: "mock"}, nil) if err != nil { t.Fatalf("iot.New: %v", err) } p := NewIoTStateProvider(mgr, nil) // The mock provider has no heart-rate/sleep/working device, so it must yield // a zero state instead of an error, keeping the service operable. st, err := p.Current(context.Background()) if err != nil { t.Fatalf("Current: %v", err) } if st != (UserState{}) { t.Fatalf("state = %+v, want zero UserState", st) } }