package e2e import ( "encoding/json" "fmt" "net/http" "net/url" "os" "path/filepath" "strings" "testing" ) func TestReadmeRelativeLinks(t *testing.T) { inst := startInstance(t) aliceKey := inst.newKey(t, "alice") inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub") if _, _, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/site"); code != 0 { t.Fatal("repo create failed") } work := t.TempDir() env := inst.gitEnv(aliceKey) mustGit(t, work, env, "clone", inst.sshURL("alice/site"), "w") dir := filepath.Join(work, "w") os.MkdirAll(filepath.Join(dir, "docs"), 0o755) os.MkdirAll(filepath.Join(dir, "img"), 0o755) os.WriteFile(filepath.Join(dir, "README.md"), []byte( "# site\n\n[guide](docs/guide.md) and [export](docs/paper.html) and "+ "[abs](https://example.org/x) here\n\n\n"+ "\n\n"+ "| flag | effect |\n|------|--------|\n| `-v` | verbose |\n\n"+ "```go\nfunc main() {}\n```\n"), 0o644) os.WriteFile(filepath.Join(dir, "docs", "guide.md"), []byte("# guide\n"), 0o644) os.WriteFile(filepath.Join(dir, "docs", "paper.org"), []byte("* paper\n"), 0o644) os.WriteFile(filepath.Join(dir, "img", "logo.png"), []byte{0x89, 0x50}, 0o644) mustGit(t, dir, env, "checkout", "-q", "-b", "main") mustGit(t, dir, env, "add", ".") mustGit(t, dir, env, "commit", "-q", "-m", "base") mustGit(t, dir, env, "push", "-q", "origin", "main") status, body := inst.get(t, "/alice/site") if status != 200 { t.Fatalf("tree: %d", status) } for _, want := range []string{ `href="/alice/site/blob/main/docs/guide.md"`, // relative link `href="/alice/site/blob/main/docs/paper.org"`, // .html mapped to .org source `src="/alice/site/raw/main/img/logo.png"`, // relative image via raw `src="https://example.org/pic.png"`, // remote image untouched `href="https://example.org/x"`, // absolute untouched "
| verbose | ", // GFM table renders `func`, // fenced code highlighted via classes `href="/alice/site/blob/main/README.md">README.md`, // clickable card header `name | `, // file table column headers } { if !strings.Contains(body, want) { t.Errorf("missing %q", want) } } // Branch dropdown lists branches. if !strings.Contains(body, `class="refmenu"`) || !strings.Contains(body, ">all refs") { t.Error("branch dropdown missing") } // Per-file history: ?path= filters the log; blob pages link to it. os.WriteFile(filepath.Join(dir, "docs", "notes.txt"), []byte("n\n"), 0o644) mustGit(t, dir, env, "add", ".") mustGit(t, dir, env, "commit", "-q", "-m", "touch only the notes") mustGit(t, dir, env, "push", "-q", "origin", "main") if _, body := inst.get(t, "/alice/site/log?path=docs/notes.txt"); !strings.Contains(body, "touch only the notes") || strings.Contains(body, ">base<") || !strings.Contains(body, "history of") { t.Fatalf("per-file log wrong:\n%s", body) } if _, body := inst.get(t, "/alice/site/log?path=no/such/file"); !strings.Contains(body, "nothing touches") { t.Fatalf("empty per-file log:\n%s", body) } if _, body := inst.get(t, "/alice/site/blob/main/docs/guide.md"); !strings.Contains(body, `log/main?path=docs%2fguide.md">history`) { t.Fatalf("blob history link missing:\n%s", body) } // CLI parity: repo log --path. logOut, _, _ := inst.ssh(t, aliceKey, "", "repo", "log", "alice/site", "--path", "docs/notes.txt", "--json") if !strings.Contains(logOut, "touch only the notes") || strings.Contains(logOut, `"subject":"base"`) { t.Fatalf("repo log --path wrong:\n%s", logOut) } // Raw serves images with their real type (nosniff otherwise blocks //
|---|