Просмотр исходного кода

config: enforce rds text lengths

tags/v0.9.0
Jan 1 месяц назад
Родитель
Сommit
5b0d76048a
2 измененных файлов: 81 добавлений и 20 удалений
  1. +6
    -0
      internal/config/config.go
  2. +75
    -20
      internal/config/config_test.go

+ 6
- 0
internal/config/config.go Просмотреть файл

@@ -183,6 +183,12 @@ func (c Config) Validate() error {
if c.RDS.PTY < 0 || c.RDS.PTY > 31 {
return fmt.Errorf("rds.pty out of range (0-31)")
}
if len(c.RDS.PS) > 8 {
return fmt.Errorf("rds.ps must be <= 8 characters")
}
if len(c.RDS.RadioText) > 64 {
return fmt.Errorf("rds.radioText must be <= 64 characters")
}
return nil
}



+ 75
- 20
internal/config/config_test.go Просмотреть файл

@@ -3,11 +3,14 @@ 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) }
if err := Default().Validate(); err != nil {
t.Fatalf("default invalid: %v", err)
}
}

func TestLoadAndValidate(t *testing.T) {
@@ -15,56 +18,108 @@ func TestLoadAndValidate(t *testing.T) {
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) }
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") }
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") }
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") }
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") }
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 }{
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) }
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") }
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") }
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") }
if cfg.EffectiveDeviceRate() != float64(cfg.FM.CompositeRateHz) {
t.Fatal("expected composite rate")
}
cfg.Backend.DeviceSampleRateHz = 912000
if cfg.EffectiveDeviceRate() != 912000 { t.Fatal("expected 912000") }
if cfg.EffectiveDeviceRate() != 912000 {
t.Fatal("expected 912000")
}
}

Загрузка…
Отмена
Сохранить