@ 261101.7
current
package main

import (
	"net/http"
	"net/http/httptest"
	"net/url"
	"os/exec"
	"strings"
	"testing"
)

// A link to a repo on a forge, or a file or directory in one, maps to its
// path on the web address; other pages of a forge, and other hosts, map
// to nothing.
func TestWebPath(t *testing.T) {
	for in, want := range map[string]string{
		"https://github.com/junegunn/fzf":                                               "/github.com/junegunn/fzf/",
		"https://www.github.com/junegunn/fzf.git":                                       "/github.com/junegunn/fzf/",
		"https://github.com/junegunn/fzf/blob/master/README.md":                         "/github.com/junegunn/fzf/README.md",
		"https://github.com/junegunn/fzf/tree/v0.50/shell":                              "/github.com/junegunn/fzf/shell/",
		"https://github.com/junegunn/fzf/tree/master":                                   "/github.com/junegunn/fzf/",
		"https://codeberg.org/forgejo/forgejo/src/branch/main/go.mod":                   "/codeberg.org/forgejo/forgejo/go.mod",
		"https://gitlab.com/a/b/c/-/blob/main/x.md":                                     "/gitlab.com/a/b/c/x.md",
		"https://gitlab.com/a/b":                                                        "/gitlab.com/a/b/",
		"https://bitbucket.org/a/b/src/main/x.md":                                       "/bitbucket.org/a/b/x.md",
		"https://github.com/junegunn/fzf/blob/26ff936/BUILD.md":                         "/github.com/junegunn/fzf@26ff936/BUILD.md",
		"https://github.com/junegunn/fzf/tree/26ff936df038b6a62ec42cf18db27b2ea2bb8ec3": "/github.com/junegunn/fzf@26ff936df038b6a62ec42cf18db27b2ea2bb8ec3/",
		"https://github.com/junegunn/fzf/blob/cafe/x.md":                                "/github.com/junegunn/fzf/x.md",
		"https://github.com/junegunn/fzf/raw/master/x.png":                              "/github.com/junegunn/fzf/x.png",
		"https://raw.githubusercontent.com/rivo/uniseg/master/LICENSE.txt":              "/github.com/rivo/uniseg/LICENSE.txt",
		"https://raw.githubusercontent.com/rivo/uniseg/refs/heads/main/a/b.go":          "/github.com/rivo/uniseg/a/b.go",
		"https://raw.githubusercontent.com/rivo/uniseg/0123abcd/LICENSE":                "/github.com/rivo/uniseg@0123abcd/LICENSE",
		"https://raw.githubusercontent.com/rivo/uniseg":                                 "",
		"https://raw.githubusercontent.com/rivo/uniseg/master":                          "",
		"https://codeberg.org/a/b/raw/branch/main/x.md":                                 "/codeberg.org/a/b/x.md",
		"https://gitlab.com/a/b/-/raw/main/x.md":                                        "/gitlab.com/a/b/x.md",
		"https://github.com/junegunn/fzf/issues/3":                                      "",
		"https://github.com/junegunn":                                                   "",
		"https://github.com/sponsors/junegunn":                                          "",
		"https://example.com/a/b":                                                       "",
		"ftp://github.com/a/b":                                                          "",
		"https://github.com/a/../b":                                                     "",
	} {
		u, err := url.Parse(in)
		if err != nil {
			t.Fatal(err)
		}
		if _, got := webPath(u); got != want {
			t.Errorf("%s: %q, want %q", in, got, want)
		}
	}
}

// A URL pasted whole after the address, or a forge's view of a file,
// redirects to the path that reads it. The mux has folded the URL's //
// into / before.
func TestWebPastedURL(t *testing.T) {
	w := testWeb(t, defaultDisk)
	for in, want := range map[string]string{
		"/https:/git.suckless.org/dwm/":                       "/git.suckless.org/dwm",
		"/https:/git.suckless.org/dwm":                        "/git.suckless.org/dwm",
		"/http:/github.com/junegunn/fzf":                      "/github.com/junegunn/fzf/",
		"/https:/github.com/junegunn/fzf/blob/master/main.go": "/github.com/junegunn/fzf/main.go",
		"/github.com/junegunn/fzf/tree/master/shell":          "/github.com/junegunn/fzf/shell/",
		"/raw.githubusercontent.com/junegunn/fzf/master/x.md": "/github.com/junegunn/fzf/x.md",
	} {
		rec := webGet(w, in)
		if rec.Code != http.StatusMovedPermanently || rec.Header().Get("Location") != want {
			t.Errorf("%s: %d %s, want %s", in, rec.Code, rec.Header().Get("Location"), want)
		}
	}
	for _, in := range []string{"/github.com/junegunn", "/github.com/junegunn/fzf/README.md"} {
		if rec := webGet(w, in); rec.Code == http.StatusMovedPermanently {
			t.Errorf("%s redirects to %s", in, rec.Header().Get("Location"))
		}
	}
}

// A page of a repo on the web address links its forge's own permanent
// URL: a file or directory at the commit shown, or a commit.
func TestForgeLink(t *testing.T) {
	needGit(t)
	_, tr, dir := serveTree(t)
	if out, err := exec.Command("git", "init", "-q", dir).CombinedOutput(); err != nil {
		t.Fatalf("git init: %v\n%s", err, out)
	}
	commitAll(t, dir, "one")
	out, _ := exec.Command("git", "-C", dir, "rev-parse", "HEAD").Output()
	head := strings.TrimSpace(string(out))
	tr.web = &webRepo{key: "github.com/junegunn/fzf"}
	for _, c := range []struct{ path, kind, want string }{
		{"/a/b.go", "code", "https://github.com/junegunn/fzf/blob/" + head + "/a/b.go"},
		{"/a/", "dir", "https://github.com/junegunn/fzf/tree/" + head + "/a"},
		{"/", "dir", "https://github.com/junegunn/fzf/tree/" + head},
		{"/?commit=" + head, "commit", "https://github.com/junegunn/fzf/commit/" + head},
		{"/?log", "log", ""},
	} {
		got, lines := tr.forgeLink(httptest.NewRequest("GET", c.path, nil), c.kind)
		if got != c.want || c.want != "" && lines != "github" {
			t.Errorf("%s: %q %q, want %q", c.path, got, lines, c.want)
		}
	}
	tr.web.key = "gitlab.com/a/b/c"
	if got, lines := tr.forgeLink(httptest.NewRequest("GET", "/a/b.go", nil), "code"); got != "https://gitlab.com/a/b/c/-/blob/"+head+"/a/b.go" || lines != "gitlab" {
		t.Errorf("gitlab: %q %q", got, lines)
	}
	tr.web.key = "git.suckless.org/dwm"
	if got, _ := tr.forgeLink(httptest.NewRequest("GET", "/a/b.go", nil), "code"); got != "" {
		t.Errorf("an unknown forge: %q", got)
	}
}