package apps import ( "path/filepath" "testing" ) func TestAppAvailableAt(t *testing.T) { root := "/srv/zddc" cases := []struct { dir, app string want bool }{ // archive: everywhere {root, "archive", true}, {root + "/Project-A", "archive", true}, {root + "/Project-A/working", "archive", true}, {root + "/Project-A/some-other-folder", "archive", true}, // landing: only at root {root, "landing", true}, {root + "/Project-A", "landing", false}, // classifier: working/, staging/, archive//incoming/ and subtrees {root, "classifier", false}, {root + "/Project-A", "classifier", false}, {root + "/Project-A/working", "classifier", true}, {root + "/Project-A/working/deep/nested/path", "classifier", true}, {root + "/Project-A/staging", "classifier", true}, {root + "/Project-A/staging/2026-06-15_x (DFT) - y", "classifier", true}, {root + "/Project-A/archive/ACME/incoming", "classifier", true}, {root + "/Project-A/archive/ACME/incoming/sub", "classifier", true}, {root + "/Project-A/archive/ACME/received", "classifier", false}, {root + "/Project-A/archive/ACME/issued", "classifier", false}, {root + "/Project-A/archive/ACME/mdl", "classifier", false}, {root + "/Project-A/some-other-folder", "classifier", false}, // mdedit: working/ only (review responses live in working//) {root + "/Project-A/working", "mdedit", true}, {root + "/Project-A/working/sub", "mdedit", true}, {root + "/Project-A/staging", "mdedit", false}, {root + "/Project-A/archive/ACME/incoming", "mdedit", false}, // transmittal: staging/ only {root + "/Project-A/staging", "transmittal", true}, {root + "/Project-A/staging/sub", "transmittal", true}, {root + "/Project-A/working", "transmittal", false}, {root + "/Project-A/archive/ACME/issued", "transmittal", false}, // case-fold: any case of canonical names matches {root + "/Project-A/Working", "mdedit", true}, {root + "/Project-A/WORKING", "mdedit", true}, {root + "/Project-A/Staging", "transmittal", true}, {root + "/Project-A/STAGING", "transmittal", true}, {root + "/Project-A/archive/ACME/Incoming", "classifier", true}, {root + "/Project-A/Archive/ACME/incoming", "classifier", true}, // unknown app {root + "/Project-A", "weird", false}, } for _, tc := range cases { t.Run(tc.app+"@"+tc.dir, func(t *testing.T) { got := AppAvailableAt(root, filepath.Clean(tc.dir), tc.app) if got != tc.want { t.Errorf("AppAvailableAt(%q, %q) = %v, want %v", tc.dir, tc.app, got, tc.want) } }) } } func TestDefaultAppAt(t *testing.T) { root := "/srv/zddc" cases := []struct { dir string want string }{ // At the deployment root itself, no default tool — landing handles // the project picker via a separate path. {root, ""}, // Bare project root: no default. Trailing-slash URL serves browse; // no-slash falls through to the redirect. {root + "/Project-A", ""}, // Canonical project-root folders. {root + "/Project-A/working", "mdedit"}, {root + "/Project-A/working/alice@example.com", "mdedit"}, {root + "/Project-A/working/2026-06-15_x (DFT) - y", "mdedit"}, {root + "/Project-A/staging", "transmittal"}, {root + "/Project-A/staging/2026-06-15_x (DFT) - y", "transmittal"}, // archive: at the archive root, party folders, and per-party // subfolders (incoming/received/issued). {root + "/Project-A/archive", "archive"}, {root + "/Project-A/archive/Acme", "archive"}, {root + "/Project-A/archive/Acme/incoming", "archive"}, {root + "/Project-A/archive/Acme/issued", "archive"}, {root + "/Project-A/archive/Acme/received", "archive"}, // mdl wins over the broader archive rule. {root + "/Project-A/archive/Acme/mdl", "tables"}, {root + "/Project-A/archive/Acme/mdl/anything-deeper", "tables"}, // reviewing/ is virtual — no default tool wired here yet. {root + "/Project-A/reviewing", ""}, // Random non-canonical folder names → no default. {root + "/Project-A/scratch", ""}, // Case-fold on canonical names. {root + "/Project-A/Working", "mdedit"}, {root + "/Project-A/STAGING", "transmittal"}, {root + "/Project-A/Archive/Acme/MDL", "tables"}, } for _, tc := range cases { t.Run(tc.dir, func(t *testing.T) { if got := DefaultAppAt(root, tc.dir); got != tc.want { t.Errorf("DefaultAppAt(%q) = %q, want %q", tc.dir, got, tc.want) } }) } }