155 lines
5.2 KiB
Go
155 lines
5.2 KiB
Go
package forge
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/cruldra/superpowers-vscode/cli/internal/repo"
|
|
"github.com/cruldra/superpowers-vscode/cli/internal/tea"
|
|
)
|
|
|
|
// fakeEnv builds an [Env] whose credential sources are canned answers, recording which hosts were asked.
|
|
type fakeEnv struct {
|
|
ghToken string
|
|
ghErr error
|
|
logins map[string]*tea.TeaLogin
|
|
env map[string]string
|
|
ghAsked []string
|
|
teaAsked []string
|
|
}
|
|
|
|
func (f *fakeEnv) Env() Env {
|
|
return Env{
|
|
GitHubToken: func(host string) (string, error) {
|
|
f.ghAsked = append(f.ghAsked, host)
|
|
return f.ghToken, f.ghErr
|
|
},
|
|
TeaLogin: func(host string) (*tea.TeaLogin, error) {
|
|
f.teaAsked = append(f.teaAsked, host)
|
|
return f.logins[host], nil
|
|
},
|
|
Getenv: func(key string) string { return f.env[key] },
|
|
}
|
|
}
|
|
|
|
func githubOrigin() repo.Origin {
|
|
return repo.Origin{Host: "github.com", WebURL: "https://github.com", Owner: "acme", Repo: "widgets"}
|
|
}
|
|
|
|
func giteaOrigin() repo.Origin {
|
|
return repo.Origin{Host: "gitea.example.com", WebURL: "https://gitea.example.com", Owner: "acme", Repo: "widgets"}
|
|
}
|
|
|
|
func TestKindForHost(t *testing.T) {
|
|
cases := map[string]Kind{
|
|
"github.com": KindGitHub,
|
|
"GitHub.com": KindGitHub,
|
|
"gitea.example.com": KindGitea,
|
|
"github.example.com": KindGitea,
|
|
"api.github.com": KindGitea,
|
|
"localhost": KindGitea,
|
|
}
|
|
for host, want := range cases {
|
|
if got := KindForHost(host); got != want {
|
|
t.Errorf("KindForHost(%q) = %s, want %s", host, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestOpenGitHubUsesGhToken(t *testing.T) {
|
|
fe := &fakeEnv{ghToken: "gho_abc\n", env: map[string]string{"GITEA_TOKEN": "ignored"}}
|
|
f, err := Open(githubOrigin(), fe.Env())
|
|
if err != nil {
|
|
t.Fatalf("Open 出错: %v", err)
|
|
}
|
|
if f.Kind() != KindGitHub {
|
|
t.Fatalf("github.com 应选 GitHub,得到 %s", f.Kind())
|
|
}
|
|
rf := f.(*restForge)
|
|
if rf.apiBase != GitHubAPIBaseURL || rf.header.Get("Authorization") != "Bearer gho_abc" {
|
|
t.Fatalf("GitHub 客户端配置不对: base=%s auth=%q", rf.apiBase, rf.header.Get("Authorization"))
|
|
}
|
|
if rf.owner != "acme" || rf.repo != "widgets" {
|
|
t.Fatalf("owner/repo 不对: %s/%s", rf.owner, rf.repo)
|
|
}
|
|
if len(fe.ghAsked) != 1 || fe.ghAsked[0] != "github.com" || len(fe.teaAsked) != 0 {
|
|
t.Fatalf("应只向 gh 要 github.com 的 token: gh=%v tea=%v", fe.ghAsked, fe.teaAsked)
|
|
}
|
|
}
|
|
|
|
func TestOpenGitHubFailsWithLoginHintWhenGhFails(t *testing.T) {
|
|
fe := &fakeEnv{ghErr: errors.New("exit status 1: no oauth token found")}
|
|
_, err := Open(githubOrigin(), fe.Env())
|
|
if err == nil || !strings.Contains(err.Error(), "gh auth login") {
|
|
t.Fatalf("gh 取 token 失败应提示运行 gh auth login,得到 %v", err)
|
|
}
|
|
if !strings.Contains(err.Error(), "no oauth token found") {
|
|
t.Fatalf("错误里应带上 gh 的原因: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestOpenGitHubFailsWithLoginHintWhenGhTokenEmpty(t *testing.T) {
|
|
fe := &fakeEnv{ghToken: " \n"}
|
|
_, err := Open(githubOrigin(), fe.Env())
|
|
if err == nil || !strings.Contains(err.Error(), "gh auth login") {
|
|
t.Fatalf("gh 返回空 token 应提示运行 gh auth login,得到 %v", err)
|
|
}
|
|
}
|
|
|
|
func TestOpenGiteaUsesTeaLoginOfOriginHost(t *testing.T) {
|
|
fe := &fakeEnv{
|
|
logins: map[string]*tea.TeaLogin{
|
|
"gitea.example.com": {Name: "work", URL: "https://gitea.example.com:8443/", Token: "tea-tok"},
|
|
},
|
|
env: map[string]string{"GITEA_TOKEN": "env-tok"},
|
|
}
|
|
f, err := Open(giteaOrigin(), fe.Env())
|
|
if err != nil {
|
|
t.Fatalf("Open 出错: %v", err)
|
|
}
|
|
rf := f.(*restForge)
|
|
if f.Kind() != KindGitea || rf.apiBase != "https://gitea.example.com:8443/api/v1" || rf.header.Get("Authorization") != "token tea-tok" {
|
|
t.Fatalf("Gitea 客户端配置不对: kind=%s base=%s auth=%q", f.Kind(), rf.apiBase, rf.header.Get("Authorization"))
|
|
}
|
|
if len(fe.teaAsked) != 1 || fe.teaAsked[0] != "gitea.example.com" || len(fe.ghAsked) != 0 {
|
|
t.Fatalf("应只按 origin host 查 tea login: tea=%v gh=%v", fe.teaAsked, fe.ghAsked)
|
|
}
|
|
}
|
|
|
|
func TestOpenGiteaFallsBackToEnvTokenWhenLoginHasNone(t *testing.T) {
|
|
fe := &fakeEnv{
|
|
logins: map[string]*tea.TeaLogin{
|
|
"gitea.example.com": {Name: "work", URL: "https://gitea.example.com", Token: ""},
|
|
},
|
|
env: map[string]string{"GITEA_TOKEN": "env-tok"},
|
|
}
|
|
f, err := Open(giteaOrigin(), fe.Env())
|
|
if err != nil {
|
|
t.Fatalf("Open 出错: %v", err)
|
|
}
|
|
if got := f.(*restForge).header.Get("Authorization"); got != "token env-tok" {
|
|
t.Fatalf("login 没 token 时应回退 GITEA_TOKEN,得到 %q", got)
|
|
}
|
|
}
|
|
|
|
func TestOpenGiteaWithoutLoginUsesOriginWebURLAndEnvToken(t *testing.T) {
|
|
fe := &fakeEnv{env: map[string]string{"GITEA_TOKEN": "env-tok"}}
|
|
f, err := Open(giteaOrigin(), fe.Env())
|
|
if err != nil {
|
|
t.Fatalf("Open 出错: %v", err)
|
|
}
|
|
rf := f.(*restForge)
|
|
if rf.apiBase != "https://gitea.example.com/api/v1" || rf.header.Get("Authorization") != "token env-tok" {
|
|
t.Fatalf("没有 tea login 时应用 origin 地址 + GITEA_TOKEN: base=%s auth=%q", rf.apiBase, rf.header.Get("Authorization"))
|
|
}
|
|
}
|
|
|
|
func TestOpenGiteaWithoutAnyTokenFails(t *testing.T) {
|
|
fe := &fakeEnv{}
|
|
_, err := Open(giteaOrigin(), fe.Env())
|
|
if err == nil || !strings.Contains(err.Error(), "GITEA_TOKEN") || !strings.Contains(err.Error(), "gitea.example.com") {
|
|
t.Fatalf("没有 token 时应报错并点名 host 与 GITEA_TOKEN,得到 %v", err)
|
|
}
|
|
}
|