package zddc import ( "os" "path/filepath" "testing" ) // TestDefaultToolAt_FromEmbeddedConvention — the canonical default- // tool rules in defaults.zddc.yaml should resolve correctly for the // well-known paths without any on-disk .zddc. func TestDefaultToolAt_FromEmbeddedConvention(t *testing.T) { resetCache() root := t.TempDir() cases := []struct { path string want string }{ {filepath.Join(root, "Project-X", "archive"), "archive"}, {filepath.Join(root, "Project-X", "archive", "Acme", "mdl"), "tables"}, {filepath.Join(root, "Project-X", "archive", "Acme", "incoming"), "classifier"}, {filepath.Join(root, "Project-X", "archive", "Acme", "received"), "archive"}, {filepath.Join(root, "Project-X", "archive", "Acme", "issued"), "archive"}, {filepath.Join(root, "Project-X", "working"), "browse"}, {filepath.Join(root, "Project-X", "working", "alice@example.com"), "browse"}, {filepath.Join(root, "Project-X", "staging"), "transmittal"}, {filepath.Join(root, "Project-X", "reviewing"), "browse"}, } for _, tc := range cases { got := DefaultToolAt(root, tc.path) if got != tc.want { t.Errorf("DefaultToolAt(%q) = %q, want %q", tc.path[len(root):], got, tc.want) } } } // TestDirToolAt — the trailing-slash form floors at "browse" for // every path (the embedded convention sets dir_tool nowhere), and an // on-disk .zddc can override it for a subtree. func TestDirToolAt(t *testing.T) { resetCache() root := t.TempDir() // Nothing declares dir_tool → browse everywhere, including paths // whose default_tool (no-slash form) is something else. for _, p := range []string{ filepath.Join(root, "Project-X"), filepath.Join(root, "Project-X", "working"), filepath.Join(root, "Project-X", "archive", "Acme", "mdl"), filepath.Join(root, "Project-X", "random", "deep", "folder"), } { if got := DirToolAt(root, p); got != "browse" { t.Errorf("DirToolAt(%q) = %q, want browse", p[len(root):], got) } } // Operator override on a subtree; cascades leaf→root. specialDir := filepath.Join(root, "Special") if err := os.MkdirAll(specialDir, 0o755); err != nil { t.Fatal(err) } writeZddc(t, specialDir, "dir_tool: tables\n") resetCache() if got := DirToolAt(root, filepath.Join(root, "Special")); got != "tables" { t.Errorf("DirToolAt(Special) = %q, want tables", got) } if got := DirToolAt(root, filepath.Join(root, "Special", "deep")); got != "tables" { t.Errorf("DirToolAt(Special/deep) = %q, want tables (cascade)", got) } if got := DirToolAt(root, filepath.Join(root, "Other")); got != "browse" { t.Errorf("DirToolAt(Other) = %q, want browse (override scoped to Special)", got) } } // TestAutoOwnAt_FromEmbeddedConvention — auto_own should be true for // working/incoming/staging (per the convention) and false elsewhere. func TestAutoOwnAt_FromEmbeddedConvention(t *testing.T) { resetCache() root := t.TempDir() cases := []struct { path string want bool }{ {filepath.Join(root, "Project-X", "working"), true}, {filepath.Join(root, "Project-X", "working", "alice@example.com"), true}, {filepath.Join(root, "Project-X", "staging"), true}, {filepath.Join(root, "Project-X", "archive", "Acme", "incoming"), true}, {filepath.Join(root, "Project-X", "archive", "Acme", "received"), false}, {filepath.Join(root, "Project-X", "archive", "Acme", "issued"), false}, {filepath.Join(root, "Project-X", "archive", "Acme", "mdl"), false}, } for _, tc := range cases { got := AutoOwnAt(root, tc.path) if got != tc.want { t.Errorf("AutoOwnAt(%q) = %v, want %v", tc.path[len(root):], got, tc.want) } } } // TestVirtualAt_FromEmbeddedConvention — reviewing/ and mdl/ are // declared virtual; everything else (including working/staging/ // incoming) materialises on disk. func TestVirtualAt_FromEmbeddedConvention(t *testing.T) { resetCache() root := t.TempDir() cases := []struct { path string want bool }{ {filepath.Join(root, "Project-X", "reviewing"), true}, {filepath.Join(root, "Project-X", "archive", "Acme", "mdl"), true}, {filepath.Join(root, "Project-X", "working"), false}, {filepath.Join(root, "Project-X", "staging"), false}, {filepath.Join(root, "Project-X", "archive", "Acme", "incoming"), false}, {filepath.Join(root, "Project-X", "archive", "Acme", "received"), false}, } for _, tc := range cases { got := VirtualAt(root, tc.path) if got != tc.want { t.Errorf("VirtualAt(%q) = %v, want %v", tc.path[len(root):], got, tc.want) } } } // TestIsDeclaredPath_FromEmbeddedConvention — canonical paths under // the convention are declared even on a fresh root; arbitrary paths // are not. func TestIsDeclaredPath_FromEmbeddedConvention(t *testing.T) { resetCache() root := t.TempDir() cases := []struct { path string want bool }{ {filepath.Join(root, "Project-X", "archive"), true}, {filepath.Join(root, "Project-X", "archive", "Acme", "incoming"), true}, {filepath.Join(root, "Project-X", "working"), true}, {filepath.Join(root, "Project-X", "reviewing"), true}, {filepath.Join(root, "Project-X", "junk"), false}, // not in convention } for _, tc := range cases { got := IsDeclaredPath(root, tc.path) if got != tc.want { t.Errorf("IsDeclaredPath(%q) = %v, want %v", tc.path[len(root):], got, tc.want) } } } // TestChildrenDeclaredAt_FromEmbeddedConvention — at a project // root, the four canonical children should be enumerated. func TestChildrenDeclaredAt_FromEmbeddedConvention(t *testing.T) { resetCache() root := t.TempDir() got := ChildrenDeclaredAt(root, filepath.Join(root, "Project-X")) want := map[string]bool{ "archive": true, "working": true, "staging": true, "reviewing": true, } if len(got) != len(want) { t.Errorf("ChildrenDeclaredAt = %v, want exactly %v keys", got, want) } for _, n := range got { if !want[n] { t.Errorf("unexpected child %q", n) } } } // TestOperatorOverride_DefaultsAreSurfaceable — operator can override // any of the canonical tool defaults by mirroring the structure in an // on-disk .zddc. The override wins. func TestOperatorOverride_DefaultsAreSurfaceable(t *testing.T) { resetCache() root := t.TempDir() if err := os.MkdirAll(filepath.Join(root, "Special", "working"), 0o755); err != nil { t.Fatal(err) } // Operator declares that Special/working uses classifier // instead of the embedded-default browse. writeZddc(t, filepath.Join(root, "Special", "working"), "default_tool: classifier\n") if got := DefaultToolAt(root, filepath.Join(root, "Special", "working")); got != "classifier" { t.Errorf("operator override should set default_tool=classifier, got %q", got) } // Default still applies at other projects. if got := DefaultToolAt(root, filepath.Join(root, "Project-Y", "working")); got != "browse" { t.Errorf("default convention should hold at unchanged paths, got %q", got) } } // TestDefaultToolAt_PropagatesToDescendants — once an ancestor sets // default_tool, descendants inherit it unless they override. So a // path under working/ that isn't explicitly declared in paths: still // gets browse as its default tool. func TestDefaultToolAt_PropagatesToDescendants(t *testing.T) { resetCache() root := t.TempDir() // Deep path under working/ — not explicitly mentioned in paths:. deep := filepath.Join(root, "Project-X", "working", "alice@example.com", "notes", "sub", "deep") if got := DefaultToolAt(root, deep); got != "browse" { t.Errorf("DefaultToolAt(%q) = %q, want browse (cascade propagation)", deep[len(root):], got) } } // TestAutoOwnAt_DescendantCanDisable — explicit auto_own:false at a // descendant overrides an ancestor's auto_own:true. func TestAutoOwnAt_DescendantCanDisable(t *testing.T) { resetCache() root := t.TempDir() deepDir := filepath.Join(root, "Project-X", "working", "alice@example.com") if err := os.MkdirAll(deepDir, 0o755); err != nil { t.Fatal(err) } writeZddc(t, deepDir, "auto_own: false\n") if got := AutoOwnAt(root, deepDir); got != false { t.Errorf("AutoOwnAt(%q) = %v, want false (descendant override)", deepDir, got) } // Ancestor still has it true. ancestor := filepath.Join(root, "Project-X", "working") if got := AutoOwnAt(root, ancestor); got != true { t.Errorf("AutoOwnAt(%q) = %v, want true (ancestor untouched)", ancestor, got) } } // TestInheritFalse_BlocksEmbeddedDefaults — at the on-disk root, // inherit:false stops the embedded layer from contributing. The // canonical paths are then no longer declared. func TestInheritFalse_BlocksEmbeddedDefaults(t *testing.T) { resetCache() root := t.TempDir() writeZddc(t, root, "inherit: false\n") // Without the embedded defaults' paths: tree, IsDeclaredPath // returns false for previously-canonical paths. if IsDeclaredPath(root, filepath.Join(root, "Project-X", "archive")) { t.Errorf("with inherit:false at root, archive should not be a declared path") } if DefaultToolAt(root, filepath.Join(root, "Project-X", "working")) != "" { t.Errorf("with inherit:false at root, default_tool should be empty for working") } }