package reporesolver import ( "context" "net/http" "net/http/httptest" "testing" "github.com/bluesky-social/indigo/atproto/identity" "github.com/bluesky-social/indigo/atproto/syntax" "github.com/go-chi/chi/v5" "tangled.org/core/appview/models" ) func TestExtractCurrentDir(t *testing.T) { tests := []struct { path string want string }{ {"/@user/repo/blob/main/docs/README.md", "docs"}, {"/@user/repo/blob/main/README.md", "."}, {"/@user/repo/tree/main/docs", "docs"}, {"/@user/repo/tree/main/docs/", "docs"}, {"/@user/repo/tree/main", "."}, } for _, tt := range tests { if got := extractCurrentDir(tt.path); got != tt.want { t.Errorf("extractCurrentDir(%q) = %q, want %q", tt.path, got, tt.want) } } } func TestCanonicalRepoPath(t *testing.T) { cases := []struct { name string handle string repo *models.Repo want string }{ {"name preferred", "boltless.dev", &models.Repo{Name: "anemone", Rkey: "3kabc"}, "boltless.dev/anemone"}, {"name equals rkey", "boltless.dev", &models.Repo{Name: "clam", Rkey: "clam"}, "boltless.dev/clam"}, {"empty name uses rkey", "akshay.dev", &models.Repo{Rkey: "limpet"}, "akshay.dev/limpet"}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { if got := CanonicalRepoPath(c.handle, c.repo); got != c.want { t.Errorf("CanonicalRepoPath = %q, want %q", got, c.want) } }) } } func TestCanonicalRedirectTargetKeepsTheTailEscaped(t *testing.T) { cases := []struct { name string path string want string }{ {"plain tail", "/boltless.dev/limpet/tree/main", "/akshay.dev/anemone/tree/main"}, {"space in a blob path", "/boltless.dev/limpet/blob/main/a%20b.txt", "/akshay.dev/anemone/blob/main/a%20b.txt"}, {"escaped slash in a ref", "/boltless.dev/limpet/archive/refs%2Fheads%2Fmain", "/akshay.dev/anemone/archive/refs%2Fheads%2Fmain"}, {"hash in a filename", "/boltless.dev/limpet/raw/main/c%23.cs", "/akshay.dev/anemone/raw/main/c%23.cs"}, {"repo root", "/boltless.dev/limpet", "/akshay.dev/anemone"}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { req := httptest.NewRequest("GET", c.path, nil) if got := CanonicalRedirectTarget(req, "akshay.dev/anemone"); got != c.want { t.Errorf("CanonicalRedirectTarget = %q, want %q", got, c.want) } }) } } func reqWithChiParams(user, repo string) *http.Request { r := httptest.NewRequest("GET", "/", nil) rctx := chi.NewRouteContext() rctx.URLParams.Add("user", user) rctx.URLParams.Add("repo", repo) return r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx)) } func TestGetBaseRepoPath_DoesNotVoluntaryRedirectToRepoDid(t *testing.T) { r := reqWithChiParams("@boltless.dev", "anemone") repo := &models.Repo{ Did: "did:plc:boltless", Name: "anemone", Rkey: "3kabcxyz", RepoDid: "did:plc:anemone", } got := GetBaseRepoPath(r, repo) want := "@boltless.dev/anemone" if got != want { t.Errorf("GetBaseRepoPath = %q, want %q", got, want) } } func TestGetBaseRepoPath_HonorsUrlParams(t *testing.T) { r := reqWithChiParams("did:plc:akshay", "limpet") repo := &models.Repo{Did: "did:plc:akshay", Name: "limpet", Rkey: "limpet"} if got, want := GetBaseRepoPath(r, repo), "did:plc:akshay/limpet"; got != want { t.Errorf("GetBaseRepoPath = %q, want %q", got, want) } } func TestGetBaseRepoPath_NoParamsPrefersName(t *testing.T) { r := httptest.NewRequest("GET", "/", nil) repo := &models.Repo{Did: "did:plc:akshay", Name: "scallop", Rkey: "3koldtid"} got := GetBaseRepoPath(r, repo) want := "did:plc:akshay/scallop" if got != want { t.Errorf("GetBaseRepoPath = %q, want %q", got, want) } } func TestGetBaseRepoPath_NoParamsNoNameFallsToRepoIdentifier(t *testing.T) { r := httptest.NewRequest("GET", "/", nil) repo := &models.Repo{Did: "did:plc:akshay", Rkey: "3koldtid", RepoDid: "did:plc:scallop"} if got, want := GetBaseRepoPath(r, repo), "did:plc:scallop"; got != want { t.Errorf("GetBaseRepoPath = %q, want %q", got, want) } } func reqWithResolvedId(handle, did string) *http.Request { r := reqWithChiParams(did, "3koldtid") id := identity.Identity{ DID: syntax.DID(did), Handle: syntax.Handle(handle), } return r.WithContext(context.WithValue(r.Context(), "resolvedId", id)) } func TestGetBaseRepoPath_PrefersResolvedHandleOverChiDid(t *testing.T) { r := reqWithResolvedId("boltless.dev", "did:plc:boltless") repo := &models.Repo{Did: "did:plc:boltless", Name: "anemone", Rkey: "3kabcxyz"} got := GetBaseRepoPath(r, repo) want := "boltless.dev/anemone" if got != want { t.Errorf("GetBaseRepoPath = %q, want %q", got, want) } } func TestGetBaseRepoPath_InvalidHandleFallsThroughToChi(t *testing.T) { r := reqWithChiParams("did:plc:boltless", "limpet") id := identity.Identity{ DID: syntax.DID("did:plc:boltless"), Handle: syntax.HandleInvalid, } r = r.WithContext(context.WithValue(r.Context(), "resolvedId", id)) repo := &models.Repo{Did: "did:plc:boltless", Name: "limpet", Rkey: "limpet"} if got, want := GetBaseRepoPath(r, repo), "did:plc:boltless/limpet"; got != want { t.Errorf("GetBaseRepoPath = %q, want %q", got, want) } }