test(11-02): add group header and reassignment tests (GRP-02, GRP-03)

- TestPrintConfigGroupHeaders: verifies all group section headers in canonical order
- TestLoadGroupOverride: verifies [groups] TOML reassigns class group without changing Hz/waveform
- TestLoadGroupUnknownClass: verifies unknown class in [groups] produces warning not error
- TestPrintConfigGroupReassignment: verifies PrintConfig reflects reassigned group placement
This commit is contained in:
2026-03-27 16:36:07 +01:00
parent 374282e5de
commit 7bf3ea12a3
+85
View File
@@ -600,6 +600,91 @@ func TestLoadResultConfigPath(t *testing.T) {
} }
} }
// --- Tests for Phase 11 Plan 02 (GRP-02, GRP-03) ---
// TestPrintConfigGroupHeaders verifies GRP-02: group section headers appear in canonical order.
func TestPrintConfigGroupHeaders(t *testing.T) {
t.Chdir(t.TempDir())
result, err := config.Load("")
if err != nil {
t.Fatalf("Load: %v", err)
}
output := config.PrintConfig(result)
// Verify all populated group headers appear
expectedGroups := []string{"# Infrastructure", "# Web", "# Mail", "# Remote Access", "# File Transfer", "# Database", "# VoIP", "# Unknown"}
for _, header := range expectedGroups {
if !strings.Contains(output, header+"\n") {
t.Errorf("PrintConfig output missing group header %q", header)
}
}
// Verify canonical order: Infrastructure before Web before Mail etc.
infraIdx := strings.Index(output, "# Infrastructure\n")
webIdx := strings.Index(output, "# Web\n")
mailIdx := strings.Index(output, "# Mail\n")
remoteIdx := strings.Index(output, "# Remote Access\n")
ftIdx := strings.Index(output, "# File Transfer\n")
dbIdx := strings.Index(output, "# Database\n")
voipIdx := strings.Index(output, "# VoIP\n")
unknownIdx := strings.Index(output, "# Unknown\n")
if infraIdx >= webIdx || webIdx >= mailIdx || mailIdx >= remoteIdx ||
remoteIdx >= ftIdx || ftIdx >= dbIdx || dbIdx >= voipIdx || voipIdx >= unknownIdx {
t.Errorf("Group headers not in canonical order: infra=%d web=%d mail=%d remote=%d ft=%d db=%d voip=%d unknown=%d",
infraIdx, webIdx, mailIdx, remoteIdx, ftIdx, dbIdx, voipIdx, unknownIdx)
}
}
// TestLoadGroupOverride verifies GRP-03: [groups] reassigns a class to a different group.
func TestLoadGroupOverride(t *testing.T) {
path := writeTOML(t, "[groups]\nIMAP = \"Web\"\n")
result, err := config.Load(path)
if err != nil {
t.Fatalf("Load: %v", err)
}
cfg := result.FreqCfgs[classify.ClassIMAP]
if cfg.Group != "Web" {
t.Errorf("IMAP Group: got %q, want %q", cfg.Group, "Web")
}
// Frequency and waveform unchanged (D-08)
defaultCfg := synth.ClassFreqConfigs[classify.ClassIMAP]
if cfg.BaseHz != defaultCfg.BaseHz {
t.Errorf("IMAP BaseHz changed: got %v, want %v (should be unchanged by group reassignment)", cfg.BaseHz, defaultCfg.BaseHz)
}
}
// TestLoadGroupUnknownClass verifies D-09: unknown class in [groups] produces no error.
func TestLoadGroupUnknownClass(t *testing.T) {
path := writeTOML(t, "[groups]\nBOGUS = \"Web\"\n")
result, err := config.Load(path)
if err != nil {
t.Fatalf("Load should not error on unknown [groups] class: %v", err)
}
// Should still have all default classes
if len(result.FreqCfgs) != len(classify.AllClasses()) {
t.Errorf("FreqCfgs len: got %d, want %d", len(result.FreqCfgs), len(classify.AllClasses()))
}
}
// TestPrintConfigGroupReassignment verifies PrintConfig reflects [groups] reassignment.
func TestPrintConfigGroupReassignment(t *testing.T) {
path := writeTOML(t, "[groups]\nIMAP = \"Web\"\n")
result, err := config.Load(path)
if err != nil {
t.Fatalf("Load: %v", err)
}
output := config.PrintConfig(result)
// Find the "# Web" section and check IMAP appears after it
webIdx := strings.Index(output, "# Web\n")
mailIdx := strings.Index(output, "# Mail\n")
imapIdx := strings.Index(output, "[sounds.IMAP]")
if imapIdx < webIdx || imapIdx > mailIdx {
t.Errorf("IMAP (reassigned to Web) should appear between Web and Mail headers; web=%d imap=%d mail=%d", webIdx, imapIdx, mailIdx)
}
}
// TestLoadNoConfigReturnsLoadResult: Load("") in empty dir returns LoadResult with // TestLoadNoConfigReturnsLoadResult: Load("") in empty dir returns LoadResult with
// len(FreqCfgs)==14, len(UserRules)==0, ConfigPath=="". // len(FreqCfgs)==14, len(UserRules)==0, ConfigPath=="".
func TestLoadNoConfigReturnsLoadResult(t *testing.T) { func TestLoadNoConfigReturnsLoadResult(t *testing.T) {