package e2e
import (
"os"
"path/filepath"
"strings"
"testing"
)
func TestWebAutolinks(t *testing.T) {
inst := startInstance(t)
aliceKey := inst.newKey(t, "alice")
bobKey := inst.newKey(t, "bob")
inst.admin(t, "admin", "user", "create", "alice",
"--key", aliceKey+".pub", "--email", "alice@example.test", "--verified")
inst.admin(t, "admin", "user", "create", "bob", "--key", bobKey+".pub")
// Public repo with an issue, an MR, and a private repo with an issue.
if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/app"); code != 0 {
t.Fatalf("repo create: %s", errOut)
}
if _, _, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/secret", "--private"); code != 0 {
t.Fatal("private repo create failed")
}
if _, _, code := inst.ssh(t, aliceKey, "", "issue", "create", "alice/secret", "--title", "'hidden'"); code != 0 {
t.Fatal("private issue create failed")
}
work := t.TempDir()
env := inst.gitEnv(aliceKey)
mustGit(t, work, env, "clone", inst.sshURL("alice/app"), "w")
dir := filepath.Join(work, "w")
os.WriteFile(filepath.Join(dir, "a.txt"), []byte("a\n"), 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")
mustGit(t, dir, env, "checkout", "-q", "-b", "feat")
os.WriteFile(filepath.Join(dir, "b.txt"), []byte("b\n"), 0o644)
mustGit(t, dir, env, "add", ".")
mustGit(t, dir, env, "commit", "-q", "-m", "feat")
mustGit(t, dir, env, "push", "-q", "origin", "feat")
if _, errOut, code := inst.ssh(t, aliceKey, "", "mr", "create", "alice/app",
"--source", "feat", "--target", "main", "--title", "'feat'"); code != 0 {
t.Fatalf("mr create: %s", errOut)
}
if _, _, code := inst.ssh(t, aliceKey, "", "issue", "create", "alice/app", "--title", "'first'"); code != 0 {
t.Fatal("issue 1 create failed")
}
if _, _, code := inst.ssh(t, aliceKey, "", "issue", "create", "alice/app",
"--title", "'refs'", "--body",
"'see #1 and !1 and alice/app#1 and @bob, not #99, not alice/secret#1, not `#1` in code'"); code != 0 {
t.Fatal("issue 2 create failed")
}
status, body := inst.get(t, "/alice/app/issues/2")
if status != 200 {
t.Fatalf("issue page: %d", status)
}
for _, want := range []string{
`#1`,
`!1`,
`alice/app#1`,
`@bob`,
} {
if !strings.Contains(body, want) {
t.Errorf("missing %q on issue page", want)
}
}
if strings.Contains(body, "issues/99") {
t.Error("nonexistent issue got linked")
}
// The private repo must stay plain text for anonymous viewers: a link
// would confirm it exists.
if strings.Contains(body, `href="/alice/secret`) {
t.Error("private repo reference leaked as a link")
}
if !strings.Contains(body, "alice/secret#1") {
t.Error("private repo reference text missing entirely")
}
if !strings.Contains(body, "#1") {
t.Error("code-span reference was rewritten")
}
// Comments on MR pages get the same treatment.
if _, _, code := inst.ssh(t, bobKey, "", "mr", "comment", "alice/app", "1", "--message", "'closes #2'"); code != 0 {
t.Fatal("mr comment failed")
}
_, body = inst.get(t, "/alice/app/mrs/1")
if !strings.Contains(body, `#2`) {
t.Error("MR comment reference not linked")
}
}