- 9 table-driven tests covering CFG-01 through CFG-05 - TestLoadPartialOverrideFrequency, TestLoadPartialOverrideWaveform, TestLoadBothOverrides - TestLoadUnknownKey, TestLoadNoConfig, TestLoadExplicitMissing - TestLoadUnknownClass, TestLoadInvalidWaveform, TestLoadAllDefaultsPresent - Stub config.Load returns nil,nil — all tests fail (RED)
181 lines
5.8 KiB
Go
181 lines
5.8 KiB
Go
package config_test
|
|
|
|
import (
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/netsynth/netsynth/classify"
|
|
"github.com/netsynth/netsynth/config"
|
|
"github.com/netsynth/netsynth/synth"
|
|
)
|
|
|
|
// writeTOML creates a temp TOML file with the given content and returns its path.
|
|
func writeTOML(t *testing.T, content string) string {
|
|
t.Helper()
|
|
f, err := os.CreateTemp(t.TempDir(), "*.toml")
|
|
if err != nil {
|
|
t.Fatalf("CreateTemp: %v", err)
|
|
}
|
|
if _, err := f.WriteString(content); err != nil {
|
|
t.Fatalf("WriteString: %v", err)
|
|
}
|
|
if err := f.Close(); err != nil {
|
|
t.Fatalf("Close: %v", err)
|
|
}
|
|
return f.Name()
|
|
}
|
|
|
|
// TestLoadPartialOverrideFrequency: setting only frequency for ICMP overrides BaseHz,
|
|
// leaves WaveformType unchanged (WaveformCustom), and leaves other classes unchanged.
|
|
func TestLoadPartialOverrideFrequency(t *testing.T) {
|
|
path := writeTOML(t, "[sounds.ICMP]\nfrequency = 100.0\n")
|
|
|
|
cfgs, err := config.Load(path)
|
|
if err != nil {
|
|
t.Fatalf("Load: %v", err)
|
|
}
|
|
|
|
if cfgs[classify.ClassICMP].BaseHz != 100.0 {
|
|
t.Errorf("ICMP BaseHz: got %v, want 100.0", cfgs[classify.ClassICMP].BaseHz)
|
|
}
|
|
if cfgs[classify.ClassICMP].WaveformType != synth.WaveformCustom {
|
|
t.Errorf("ICMP WaveformType: got %v, want WaveformCustom (0)", cfgs[classify.ClassICMP].WaveformType)
|
|
}
|
|
// DNS should be unchanged
|
|
want := synth.ClassFreqConfigs[classify.ClassDNS].BaseHz
|
|
if cfgs[classify.ClassDNS].BaseHz != want {
|
|
t.Errorf("DNS BaseHz: got %v, want %v (default)", cfgs[classify.ClassDNS].BaseHz, want)
|
|
}
|
|
}
|
|
|
|
// TestLoadPartialOverrideWaveform: setting only waveform for ICMP changes WaveformType,
|
|
// leaves BaseHz unchanged, and regenerates Harmonics.
|
|
func TestLoadPartialOverrideWaveform(t *testing.T) {
|
|
path := writeTOML(t, "[sounds.ICMP]\nwaveform = \"square\"\n")
|
|
|
|
cfgs, err := config.Load(path)
|
|
if err != nil {
|
|
t.Fatalf("Load: %v", err)
|
|
}
|
|
|
|
if cfgs[classify.ClassICMP].WaveformType != synth.WaveformSquare {
|
|
t.Errorf("ICMP WaveformType: got %v, want WaveformSquare", cfgs[classify.ClassICMP].WaveformType)
|
|
}
|
|
// BaseHz should be unchanged (default is 65.0)
|
|
if cfgs[classify.ClassICMP].BaseHz != 65.0 {
|
|
t.Errorf("ICMP BaseHz: got %v, want 65.0 (default)", cfgs[classify.ClassICMP].BaseHz)
|
|
}
|
|
// Harmonics should be regenerated (non-empty)
|
|
if len(cfgs[classify.ClassICMP].Harmonics) == 0 {
|
|
t.Error("ICMP Harmonics: got empty slice, expected regenerated harmonics for WaveformSquare")
|
|
}
|
|
}
|
|
|
|
// TestLoadBothOverrides: setting both frequency and waveform applies both.
|
|
func TestLoadBothOverrides(t *testing.T) {
|
|
path := writeTOML(t, "[sounds.ICMP]\nfrequency = 100.0\nwaveform = \"square\"\n")
|
|
|
|
cfgs, err := config.Load(path)
|
|
if err != nil {
|
|
t.Fatalf("Load: %v", err)
|
|
}
|
|
|
|
if cfgs[classify.ClassICMP].BaseHz != 100.0 {
|
|
t.Errorf("ICMP BaseHz: got %v, want 100.0", cfgs[classify.ClassICMP].BaseHz)
|
|
}
|
|
if cfgs[classify.ClassICMP].WaveformType != synth.WaveformSquare {
|
|
t.Errorf("ICMP WaveformType: got %v, want WaveformSquare", cfgs[classify.ClassICMP].WaveformType)
|
|
}
|
|
}
|
|
|
|
// TestLoadUnknownKey: a typo'd field name produces an error naming the bad key.
|
|
func TestLoadUnknownKey(t *testing.T) {
|
|
path := writeTOML(t, "[sounds.ICMP]\nfrequncy = 440\n")
|
|
|
|
_, err := config.Load(path)
|
|
if err == nil {
|
|
t.Fatal("expected error for unknown key 'frequncy', got nil")
|
|
}
|
|
if !strings.Contains(err.Error(), "frequncy") {
|
|
t.Errorf("error should name the bad key 'frequncy', got: %v", err)
|
|
}
|
|
}
|
|
|
|
// TestLoadNoConfig: Load("") in a directory with no netsynth.toml returns defaults with no error.
|
|
func TestLoadNoConfig(t *testing.T) {
|
|
// Chdir to a temp dir that has no netsynth.toml
|
|
t.Chdir(t.TempDir())
|
|
|
|
cfgs, err := config.Load("")
|
|
if err != nil {
|
|
t.Fatalf("Load with no config: %v", err)
|
|
}
|
|
if len(cfgs) != 14 {
|
|
t.Errorf("result map size: got %d, want 14", len(cfgs))
|
|
}
|
|
// ICMP should be at its default BaseHz (65.0)
|
|
if cfgs[classify.ClassICMP].BaseHz != 65.0 {
|
|
t.Errorf("ICMP BaseHz: got %v, want 65.0 (default)", cfgs[classify.ClassICMP].BaseHz)
|
|
}
|
|
}
|
|
|
|
// TestLoadExplicitMissing: an explicit path that doesn't exist returns an error containing "not found".
|
|
func TestLoadExplicitMissing(t *testing.T) {
|
|
_, err := config.Load("/nonexistent/path/config.toml")
|
|
if err == nil {
|
|
t.Fatal("expected error for missing explicit file, got nil")
|
|
}
|
|
if !strings.Contains(err.Error(), "not found") {
|
|
t.Errorf("error should contain 'not found', got: %v", err)
|
|
}
|
|
}
|
|
|
|
// TestLoadUnknownClass: unknown class name produces no error (warning only), result has 14 entries.
|
|
func TestLoadUnknownClass(t *testing.T) {
|
|
path := writeTOML(t, "[sounds.BOGUS]\nfrequency = 100.0\n")
|
|
|
|
cfgs, err := config.Load(path)
|
|
if err != nil {
|
|
t.Fatalf("Load with unknown class: %v", err)
|
|
}
|
|
if len(cfgs) != 14 {
|
|
t.Errorf("result map size: got %d, want 14 (BOGUS should not appear)", len(cfgs))
|
|
}
|
|
// Confirm BOGUS is NOT in the map
|
|
if _, ok := cfgs["BOGUS"]; ok {
|
|
t.Error("BOGUS class should not be present in result map")
|
|
}
|
|
}
|
|
|
|
// TestLoadInvalidWaveform: an invalid waveform string produces an error containing "invalid waveform".
|
|
func TestLoadInvalidWaveform(t *testing.T) {
|
|
path := writeTOML(t, "[sounds.ICMP]\nwaveform = \"invalid\"\n")
|
|
|
|
_, err := config.Load(path)
|
|
if err == nil {
|
|
t.Fatal("expected error for invalid waveform, got nil")
|
|
}
|
|
if !strings.Contains(err.Error(), "invalid waveform") {
|
|
t.Errorf("error should contain 'invalid waveform', got: %v", err)
|
|
}
|
|
}
|
|
|
|
// TestLoadAllDefaultsPresent: regardless of overrides, all 14 default classes are in the result map.
|
|
func TestLoadAllDefaultsPresent(t *testing.T) {
|
|
path := writeTOML(t, "[sounds.ICMP]\nfrequency = 200.0\n")
|
|
|
|
cfgs, err := config.Load(path)
|
|
if err != nil {
|
|
t.Fatalf("Load: %v", err)
|
|
}
|
|
if len(cfgs) != 14 {
|
|
t.Errorf("result map size: got %d, want 14", len(cfgs))
|
|
}
|
|
for _, class := range classify.AllClasses() {
|
|
if _, ok := cfgs[class]; !ok {
|
|
t.Errorf("class %q missing from result map", class)
|
|
}
|
|
}
|
|
}
|