gitlink-cli/internal/web/url_builder_test.go

252 lines
7.4 KiB
Go

package web
import (
"encoding/json"
"strings"
"testing"
)
func TestNewBuilderDefaultBaseURL(t *testing.T) {
b := NewBuilder()
if b.BaseURL != DefaultBaseURL {
t.Fatalf("BaseURL = %q, want %q", b.BaseURL, DefaultBaseURL)
}
}
func TestJoinTrimsTrailingSlash(t *testing.T) {
b := &Builder{BaseURL: "https://example.com///"}
got := b.join("/x")
want := "https://example.com/x"
if got != want {
t.Fatalf("join = %q, want %q", got, want)
}
}
func TestJoinAddsLeadingSlash(t *testing.T) {
b := &Builder{BaseURL: "https://example.com"}
got := b.join("y")
want := "https://example.com/y"
if got != want {
t.Fatalf("join = %q, want %q", got, want)
}
}
func TestJoinEmptyPath(t *testing.T) {
b := &Builder{BaseURL: "https://example.com/"}
if got := b.join(""); got != "https://example.com" {
t.Fatalf("join(\"\") = %q", got)
}
}
// urlCase captures one Builder scenario for table-driven testing.
type urlCase struct {
name string
target *ResourceURL
wantURL string
wantRes string
wantID string
wantCLI string
wantSubs []string // substrings the CLI command must contain
}
func runURLCases(t *testing.T, cases []urlCase) {
t.Helper()
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
if c.target.URL != c.wantURL {
t.Errorf("URL = %q, want %q", c.target.URL, c.wantURL)
}
if c.target.Resource != c.wantRes {
t.Errorf("Resource = %q, want %q", c.target.Resource, c.wantRes)
}
if c.wantID != "" && c.target.Identifier != c.wantID {
t.Errorf("Identifier = %q, want %q", c.target.Identifier, c.wantID)
}
if c.wantCLI != "" && c.target.CLICommand != c.wantCLI {
t.Errorf("CLICommand = %q, want %q", c.target.CLICommand, c.wantCLI)
}
for _, sub := range c.wantSubs {
if !strings.Contains(c.target.CLICommand, sub) {
t.Errorf("CLICommand %q missing substring %q", c.target.CLICommand, sub)
}
}
})
}
}
func TestBuilderRepoScopedURLs(t *testing.T) {
b := NewBuilder()
cases := []urlCase{
{
name: "repo",
target: b.RepoURL("jiangtx", "gitlink-cli-demo"),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo",
wantRes: "repo",
},
{
name: "issue with number",
target: b.IssueURL("jiangtx", "gitlink-cli-demo", 42),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/issues/42",
wantRes: "issue", wantID: "#42",
},
{
name: "issue list (number<=0)",
target: b.IssueURL("jiangtx", "gitlink-cli-demo", 0),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/issues",
wantRes: "issue",
},
{
name: "pr with number",
target: b.PRURL("jiangtx", "gitlink-cli-demo", 128),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/pulls/128",
wantRes: "pr", wantID: "#128",
},
{
name: "pr list (number<=0)",
target: b.PRURL("jiangtx", "gitlink-cli-demo", 0),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/pulls",
wantRes: "pr",
},
{
name: "wiki page with spaces escaped",
target: b.WikiURL("jiangtx", "gitlink-cli-demo", "API 使用指南"),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/wiki/API%20%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97",
wantRes: "wiki", wantID: "API 使用指南",
},
{
name: "wiki index (empty page)",
target: b.WikiURL("jiangtx", "gitlink-cli-demo", ""),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/wiki",
wantRes: "wiki",
},
{
name: "member",
target: b.MemberURL("jiangtx", "gitlink-cli-demo"),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/settings/collaboration",
wantRes: "member",
},
{
name: "webhook",
target: b.WebhookURL("jiangtx", "gitlink-cli-demo"),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/settings/hooks",
wantRes: "webhook",
},
{
name: "label",
target: b.LabelURL("jiangtx", "gitlink-cli-demo"),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/issues/labels",
wantRes: "label",
},
{
name: "milestone",
target: b.MilestoneURL("jiangtx", "gitlink-cli-demo"),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/milestones",
wantRes: "milestone",
},
{
name: "branch specific",
target: b.BranchURL("jiangtx", "gitlink-cli-demo", "feat/x"),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/branches/feat%2Fx",
wantRes: "branch", wantID: "feat/x",
},
{
name: "branch list",
target: b.BranchURL("jiangtx", "gitlink-cli-demo", ""),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/branches",
wantRes: "branch",
},
{
name: "release specific",
target: b.ReleaseURL("jiangtx", "gitlink-cli-demo", "v2.0"),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/releases/v2.0",
wantRes: "release", wantID: "v2.0",
},
{
name: "release list (empty tag)",
target: b.ReleaseURL("jiangtx", "gitlink-cli-demo", ""),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/releases",
wantRes: "release",
},
{
name: "commit specific",
target: b.CommitURL("jiangtx", "gitlink-cli-demo", "abc1234"),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/commits/abc1234",
wantRes: "commit", wantID: "abc1234",
},
{
name: "commit list (empty sha)",
target: b.CommitURL("jiangtx", "gitlink-cli-demo", ""),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/commits",
wantRes: "commit",
},
{
name: "ci",
target: b.CIURL("jiangtx", "gitlink-cli-demo"),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/actions",
wantRes: "ci",
},
{
name: "compare",
target: b.CompareURL("jiangtx", "gitlink-cli-demo", "master", "feat/x"),
wantURL: "https://gitlink.org.cn/jiangtx/gitlink-cli-demo/compare/master...feat%2Fx",
wantRes: "compare", wantID: "master...feat/x",
},
}
runURLCases(t, cases)
}
func TestBuilderGlobalURLs(t *testing.T) {
b := NewBuilder()
cases := []urlCase{
{
name: "notification",
target: b.NotificationURL(),
wantURL: "https://gitlink.org.cn/notifications",
wantRes: "notification",
},
{
name: "org",
target: b.OrgURL("ccf"),
wantURL: "https://gitlink.org.cn/ccf",
wantRes: "org", wantID: "ccf",
},
{
name: "user",
target: b.UserURL("jiangtx"),
wantURL: "https://gitlink.org.cn/jiangtx",
wantRes: "user", wantID: "jiangtx",
},
}
runURLCases(t, cases)
}
func TestCLICommandsContainFlags(t *testing.T) {
b := NewBuilder()
// Sanity: the show_command strings carry the flags the show subcommands parse.
if got := b.IssueURL("o", "r", 7).CLICommand; !strings.Contains(got, "--number 7") {
t.Errorf("issue CLI missing --number: %q", got)
}
if got := b.WikiURL("o", "r", "P").CLICommand; !strings.Contains(got, "--page P") {
t.Errorf("wiki CLI missing --page: %q", got)
}
if got := b.BranchURL("o", "r", "main").CLICommand; !strings.Contains(got, "--branch main") {
t.Errorf("branch CLI missing --branch: %q", got)
}
}
func TestResourceURLJSONTags(t *testing.T) {
// Guard against accidental rename of the JSON keys the demo script and
// AI Agents depend on (html_url / resource / show_command).
r := ResourceURL{URL: "u", Resource: "issue", CLICommand: "c"}
data, err := json.Marshal(r)
if err != nil {
t.Fatalf("marshal: %v", err)
}
out := string(data)
for _, key := range []string{`"html_url":"u"`, `"resource":"issue"`, `"show_command":"c"`} {
if !strings.Contains(out, key) {
t.Errorf("JSON %q missing key %s", out, key)
}
}
}