package config import ( "os" "path/filepath" "testing" ) func TestLoadNormalizesDeviceAliases(t *testing.T) { configPath := filepath.Join(t.TempDir(), "config.json") contents := `{ "mqtt": { "broker": "tcp://127.0.0.1:1883", "client_id": "mqqt-scrubber", "topics": ["tele/+/STATE"], "qos": 0 }, "influx": { "url": "http://127.0.0.1:8181", "database": "home", "precision": "ns" }, "app": { "batch_size": 200, "buffer_size": 1000, "flush_interval": "10s", "flush_timeout": "10s", "log_level": "info", "health_address": ":8080" }, "device_aliases": { "Kitchen-Plug": "Kitchen Plug", " Patio Sensor ": "Patio Sensor", "unused": " " } }` if err := os.WriteFile(configPath, []byte(contents), 0o644); err != nil { t.Fatalf("write config file: %v", err) } cfg, err := Load(configPath) if err != nil { t.Fatalf("Load returned error: %v", err) } if got := cfg.DeviceAliases["kitchen_plug"]; got != "Kitchen Plug" { t.Fatalf("unexpected kitchen alias: got %q", got) } if got := cfg.DeviceAliases["patio_sensor"]; got != "Patio Sensor" { t.Fatalf("unexpected patio alias: got %q", got) } if _, exists := cfg.DeviceAliases["unused"]; exists { t.Fatal("expected blank aliases to be discarded") } } func TestLoadOverridesDeviceAliasesFromEnv(t *testing.T) { t.Setenv("MQTT_SCRUBBER_DEVICE_ALIASES", `{"Desk-Plug":"Desk Plug"}`) configPath := filepath.Join(t.TempDir(), "config.json") contents := `{ "mqtt": { "broker": "tcp://127.0.0.1:1883", "client_id": "mqqt-scrubber", "topics": ["tele/+/STATE"], "qos": 0 }, "influx": { "url": "http://127.0.0.1:8181", "database": "home", "precision": "ns" }, "app": { "batch_size": 200, "buffer_size": 1000, "flush_interval": "10s", "flush_timeout": "10s", "log_level": "info", "health_address": ":8080" }, "device_aliases": { "Kitchen-Plug": "Kitchen Plug" } }` if err := os.WriteFile(configPath, []byte(contents), 0o644); err != nil { t.Fatalf("write config file: %v", err) } cfg, err := Load(configPath) if err != nil { t.Fatalf("Load returned error: %v", err) } if len(cfg.DeviceAliases) != 1 { t.Fatalf("expected env aliases to replace file aliases, got %d entries", len(cfg.DeviceAliases)) } if got := cfg.DeviceAliases["desk_plug"]; got != "Desk Plug" { t.Fatalf("unexpected desk alias: got %q", got) } } func TestLoadSupportsTasmotaTimeZone(t *testing.T) { configPath := filepath.Join(t.TempDir(), "config.json") contents := `{ "mqtt": { "broker": "tcp://127.0.0.1:1883", "client_id": "mqqt-scrubber", "topics": ["tele/+/STATE"], "qos": 0 }, "influx": { "url": "http://127.0.0.1:8181", "database": "home", "precision": "ns" }, "app": { "batch_size": 200, "buffer_size": 1000, "flush_interval": "10s", "flush_timeout": "10s", "log_level": "info", "health_address": ":8080", "tasmota_time_zone": "Europe/Prague" } }` if err := os.WriteFile(configPath, []byte(contents), 0o644); err != nil { t.Fatalf("write config file: %v", err) } cfg, err := Load(configPath) if err != nil { t.Fatalf("Load returned error: %v", err) } if got := cfg.App.TasmotaLocation().String(); got != "Europe/Prague" { t.Fatalf("unexpected tasmota timezone: got %q", got) } } func TestLoadRejectsInvalidTasmotaTimeZone(t *testing.T) { configPath := filepath.Join(t.TempDir(), "config.json") contents := `{ "mqtt": { "broker": "tcp://127.0.0.1:1883", "client_id": "mqqt-scrubber", "topics": ["tele/+/STATE"], "qos": 0 }, "influx": { "url": "http://127.0.0.1:8181", "database": "home", "precision": "ns" }, "app": { "batch_size": 200, "buffer_size": 1000, "flush_interval": "10s", "flush_timeout": "10s", "log_level": "info", "health_address": ":8080", "tasmota_time_zone": "Not/AZone" } }` if err := os.WriteFile(configPath, []byte(contents), 0o644); err != nil { t.Fatalf("write config file: %v", err) } if _, err := Load(configPath); err == nil { t.Fatal("expected Load to reject invalid tasmota_time_zone") } }