package main import ( "net/http/httptest" "path/filepath" "testing" "github.com/gin-gonic/gin" ) func scopeCtx(basePath string) *gin.Context { gin.SetMode(gin.TestMode) c, _ := gin.CreateTestContext(httptest.NewRecorder()) c.Set("basePath", basePath) return c } func TestRequireUserScope(t *testing.T) { cfg := &Config{OriginalsRoot: filepath.FromSlash("/originals")} abs := func(rel string) string { return filepath.Join(cfg.OriginalsRoot, filepath.FromSlash(rel)) } cases := []struct { name string basePath string path string strict bool want bool }{ {"admin sees root", "", cfg.OriginalsRoot, false, true}, {"admin anywhere", "", abs("bob/x"), false, true}, {"admin strict rejects root", "", cfg.OriginalsRoot, true, false}, {"scoped inside own tree", "alice", abs("alice/2024"), false, true}, {"scoped own root non-strict", "alice", abs("alice"), false, true}, {"scoped own root strict", "alice", abs("alice"), true, false}, {"scoped other user", "alice", abs("bob/2024"), false, false}, {"scoped sibling prefix", "alice", abs("alice2/2024"), false, false}, {"scoped originals root", "alice", cfg.OriginalsRoot, false, false}, {"nested base path", "family/alice", abs("family/alice/x"), false, true}, {"nested base path parent", "family/alice", abs("family"), false, false}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { c := scopeCtx(tc.basePath) if got := requireUserScope(c, cfg, tc.path, tc.strict); got != tc.want { t.Errorf("requireUserScope(base=%q, path=%q, strict=%v) = %v, want %v", tc.basePath, tc.path, tc.strict, got, tc.want) } }) } }