|
- package config
-
- import (
- "os"
- "path/filepath"
- "strings"
- "testing"
- )
-
- func TestDefaultValidate(t *testing.T) {
- if err := Default().Validate(); err != nil {
- t.Fatalf("default invalid: %v", err)
- }
- }
-
- func TestLoadAndValidate(t *testing.T) {
- dir := t.TempDir()
- path := filepath.Join(dir, "config.json")
- os.WriteFile(path, []byte(`{"audio":{"toneLeftHz":900,"toneRightHz":1700,"toneAmplitude":0.3},"fm":{"frequencyMHz":99.9},"backend":{"kind":"file","outputPath":"out.f32"},"control":{"listenAddress":"127.0.0.1:8088"}}`), 0o644)
- cfg, err := Load(path)
- if err != nil {
- t.Fatalf("load: %v", err)
- }
- if cfg.Audio.ToneLeftHz != 900 {
- t.Fatalf("unexpected left tone: %v", cfg.Audio.ToneLeftHz)
- }
- }
-
- func TestValidateRejectsBadFrequency(t *testing.T) {
- cfg := Default()
- cfg.FM.FrequencyMHz = 200
- if err := cfg.Validate(); err == nil {
- t.Fatal("expected error")
- }
- }
-
- func TestValidateRejectsBadPreEmphasis(t *testing.T) {
- cfg := Default()
- cfg.FM.PreEmphasisTauUS = 150
- if err := cfg.Validate(); err == nil {
- t.Fatal("expected error")
- }
- }
-
- func TestDefaultPreEmphasis(t *testing.T) {
- if Default().FM.PreEmphasisTauUS != 50 {
- t.Fatal("expected 50")
- }
- }
-
- func TestDefaultFMModulation(t *testing.T) {
- cfg := Default()
- if !cfg.FM.FMModulationEnabled {
- t.Fatal("expected true")
- }
- if cfg.FM.MaxDeviationHz != 75000 {
- t.Fatal("expected 75000")
- }
- }
-
- func TestParsePI(t *testing.T) {
- tests := []struct {
- in string
- want uint16
- ok bool
- }{
- {"1234", 0x1234, true}, {"0xBEEF", 0xBEEF, true}, {"0XCAFE", 0xCAFE, true},
- {" 0x2345 ", 0x2345, true}, {"", 0, false}, {"nope", 0, false},
- }
- for _, tt := range tests {
- got, err := ParsePI(tt.in)
- if tt.ok && err != nil {
- t.Fatalf("ParsePI(%q): %v", tt.in, err)
- }
- if !tt.ok && err == nil {
- t.Fatalf("ParsePI(%q): expected error", tt.in)
- }
- if tt.ok && got != tt.want {
- t.Fatalf("ParsePI(%q): got %x want %x", tt.in, got, tt.want)
- }
- }
- }
-
- func TestValidateRejectsInvalidPI(t *testing.T) {
- cfg := Default()
- cfg.RDS.PI = "nope"
- if err := cfg.Validate(); err == nil {
- t.Fatal("expected error")
- }
- }
-
- func TestValidateRejectsEmptyPI(t *testing.T) {
- cfg := Default()
- cfg.RDS.PI = ""
- if err := cfg.Validate(); err == nil {
- t.Fatal("expected error")
- }
- }
-
- func TestValidateRejectsLongPS(t *testing.T) {
- cfg := Default()
- cfg.RDS.PS = "TOO_LONG_PS"
- if err := cfg.Validate(); err == nil {
- t.Fatal("expected error for PS longer than 8 characters")
- }
- }
-
- func TestValidateRejectsLongRadioText(t *testing.T) {
- cfg := Default()
- cfg.RDS.RadioText = strings.Repeat("x", 65)
- if err := cfg.Validate(); err == nil {
- t.Fatal("expected error for RadioText longer than 64 characters")
- }
- }
-
- func TestEffectiveDeviceRate(t *testing.T) {
- cfg := Default()
- if cfg.EffectiveDeviceRate() != float64(cfg.FM.CompositeRateHz) {
- t.Fatal("expected composite rate")
- }
- cfg.Backend.DeviceSampleRateHz = 912000
- if cfg.EffectiveDeviceRate() != 912000 {
- t.Fatal("expected 912000")
- }
- }
-
- func TestValidateRejectsUnsupportedIngestKind(t *testing.T) {
- cfg := Default()
- cfg.Ingest.Kind = "unsupported"
- if err := cfg.Validate(); err == nil {
- t.Fatal("expected error")
- }
- }
-
- func TestValidateRejectsUnsupportedIngestPCMShape(t *testing.T) {
- cfg := Default()
- cfg.Ingest.Stdin.SampleRateHz = 0
- if err := cfg.Validate(); err == nil {
- t.Fatal("expected sampleRate error")
- }
-
- cfg = Default()
- cfg.Ingest.HTTPRaw.Channels = 6
- if err := cfg.Validate(); err == nil {
- t.Fatal("expected channels error")
- }
-
- cfg = Default()
- cfg.Ingest.Stdin.Format = "f32le"
- if err := cfg.Validate(); err == nil {
- t.Fatal("expected format error")
- }
- }
-
- func TestValidateRejectsUnsupportedIcecastDecoder(t *testing.T) {
- cfg := Default()
- cfg.Ingest.Icecast.Decoder = "mystery"
- if err := cfg.Validate(); err == nil {
- t.Fatal("expected decoder error")
- }
- }
-
- func TestValidateAcceptsIcecastDecoderFallbackAlias(t *testing.T) {
- cfg := Default()
- cfg.Ingest.Icecast.Decoder = "fallback"
- if err := cfg.Validate(); err != nil {
- t.Fatalf("expected fallback alias to be accepted: %v", err)
- }
- }
-
- func TestValidateRejectsIcecastRadioTextMaxLenOutOfRange(t *testing.T) {
- cfg := Default()
- cfg.Ingest.Icecast.RadioText.MaxLen = 65
- if err := cfg.Validate(); err == nil {
- t.Fatal("expected maxLen error")
- }
- }
-
- func TestValidateRejectsReconnectWithMissingBackoff(t *testing.T) {
- cfg := Default()
- cfg.Ingest.Reconnect.Enabled = true
- cfg.Ingest.Reconnect.InitialBackoffMs = 0
- if err := cfg.Validate(); err == nil {
- t.Fatal("expected reconnect backoff error")
- }
- }
-
- func TestValidateRejectsZeroMpxGain(t *testing.T) {
- cfg := Default()
- cfg.FM.MpxGain = 0
- if err := cfg.Validate(); err == nil {
- t.Fatal("expected mpxGain error")
- }
- }
|