252 lines
7.4 KiB
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)
|
|
}
|
|
}
|
|
}
|