package main import ( "os" "os/exec" "path/filepath" "strings" "testing" ) // A catalogue whose dunst falls back to font-size, and the trunk's list holding font-size and // agent-managed-settings. func aCatalogue(t *testing.T, list string) (root, base string) { t.Helper() root = t.TempDir() write := func(path, text string) { t.Helper() if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(path, []byte(text), 0o644); err != nil { t.Fatal(err) } } write(filepath.Join(root, "modules", "dunst", "module.json"), `{"module": "dunst", "config": {"font-size": {"type": "number", "description": "points", "default": 10, "predefined": "font-size"}}}`) write(filepath.Join(root, "modules", "claude-code", "module.json"), `{"module": "claude-code", "settings": { "managed_settings": {"kind": "preference", "default": "{}", "why": "none"}}}`) write(filepath.Join(root, "modules", "plain", "module.json"), `{"module": "plain"}`) if list != "" { write(filepath.Join(root, File), list) } base = filepath.Join(t.TempDir(), "base.json") write(base, `{"font-size": {"type": "number"}, "agent-managed-settings": {"type": "object"}}`) return root, base } func run(t *testing.T, args ...string) (string, error) { t.Helper() out, err := exec.Command("go", append([]string{"run", "."}, args...)...).CombinedOutput() return string(out), err } func TestARemovalOfAKeyAModuleStillNamesIsRefused(t *testing.T) { // The planted removal: font-size goes while dunst still falls back to it. root, base := aCatalogue(t, `{"agent-managed-settings": {"type": "object"}}`) out, err := run(t, "-base", base, root) if err == nil || !strings.Contains(out, `the key "font-size" is removed and still named by dunst`) { t.Fatalf("a removal of a named key passed:\n%s", out) } } func TestARemovalNobodyNamesPassesAndSaysWhatItCannotKnow(t *testing.T) { root, base := aCatalogue(t, `{"font-size": {"type": "number"}}`) out, err := run(t, "-base", base, root) if err != nil || !strings.Contains(out, `"agent-managed-settings" is removed and no module names it`) || !strings.Contains(out, "mesh-config's to refuse") { t.Fatalf("a removal nobody names: %v\n%s", err, out) } } func TestAListUnchangedOrGrownPasses(t *testing.T) { for _, list := range []string{ `{"font-size": {"type": "number"}, "agent-managed-settings": {"type": "object"}}`, `{"font-size": {"type": "number"}, "agent-managed-settings": {"type": "object"}, "accent": {"type": "string"}}`, } { root, base := aCatalogue(t, list) if out, err := run(t, "-base", base, root); err != nil || !strings.Contains(out, "none removed") { t.Fatalf("%s: %v\n%s", list, err, out) } } // No trunk list given: nothing was removed. root, _ := aCatalogue(t, `{}`) if out, err := run(t, root); err != nil || !strings.Contains(out, "none was removed") { t.Fatalf("without a base: %v\n%s", err, out) } } func TestTheFileRemovedWholeIsARemovalOfEveryKey(t *testing.T) { root, base := aCatalogue(t, "") out, err := run(t, "-base", base, root) if err == nil || !strings.Contains(out, `"font-size" is removed and still named by dunst`) { t.Fatalf("the list removed whole passed:\n%s", out) } } func TestNamedReadsBothForms(t *testing.T) { root, _ := aCatalogue(t, "") if err := os.WriteFile(filepath.Join(root, "modules", "plain", "module.json"), []byte(`{"module": "plain", "settings": {"size": {"predefined": "font-size"}}}`), 0o644); err != nil { t.Fatal(err) } named, err := Named(root) if err != nil { t.Fatal(err) } if got := strings.Join(named["font-size"], ","); got != "dunst,plain" { t.Fatalf("font-size named by %s", got) } }