204 lines
5.5 KiB
Go
204 lines
5.5 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/gitlink-org/gitlink-cli/cmd/cmdutil"
|
|
)
|
|
|
|
func TestResolveFormat(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
flagFormat string
|
|
want string
|
|
}{
|
|
{"empty defaults to json", "", "json"},
|
|
{"explicit json", "json", "json"},
|
|
{"explicit yaml", "yaml", "yaml"},
|
|
{"explicit table", "table", "table"},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
cmdutil.Format = tt.flagFormat
|
|
if got := resolveFormat(); got != tt.want {
|
|
t.Fatalf("resolveFormat = %q, want %q", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewAPICmd(t *testing.T) {
|
|
cmd := NewAPICmd()
|
|
if cmd.Use != "api <METHOD> <PATH>" {
|
|
t.Fatalf("Use = %q", cmd.Use)
|
|
}
|
|
if cmd.Short == "" {
|
|
t.Fatal("Short is empty")
|
|
}
|
|
|
|
// Verify flags exist
|
|
flags := []string{"body", "query", "header"}
|
|
for _, f := range flags {
|
|
if cmd.Flags().Lookup(f) == nil {
|
|
t.Fatalf("flag %q not found", f)
|
|
}
|
|
}
|
|
}
|
|
|
|
func setupAPITest(t *testing.T, handler http.HandlerFunc) string {
|
|
t.Helper()
|
|
server := httptest.NewServer(handler)
|
|
t.Cleanup(server.Close)
|
|
dir := t.TempDir()
|
|
t.Setenv("GITLINK_CONFIG_DIR", dir)
|
|
os.MkdirAll(dir, 0700)
|
|
os.WriteFile(filepath.Join(dir, "config.yaml"), []byte("base_url: "+server.URL+"\ndefault_format: table\n"), 0600)
|
|
return dir
|
|
}
|
|
|
|
func TestRunAPIGet(t *testing.T) {
|
|
setupAPITest(t, func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/users/me.json" {
|
|
t.Fatalf("unexpected path: %s", r.URL.Path)
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(map[string]interface{}{"login": "testuser", "id": 42})
|
|
})
|
|
cmdutil.Format = "json"
|
|
|
|
cmd := NewAPICmd()
|
|
cmd.SetArgs([]string{"GET", "/users/me"})
|
|
if err := cmd.Execute(); err != nil {
|
|
t.Fatalf("runAPI GET error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRunAPIPostWithBody(t *testing.T) {
|
|
var gotBody map[string]interface{}
|
|
setupAPITest(t, func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != "POST" {
|
|
t.Fatalf("expected POST, got %s", r.Method)
|
|
}
|
|
json.NewDecoder(r.Body).Decode(&gotBody)
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(map[string]interface{}{"id": 1, "title": "new issue"})
|
|
})
|
|
cmdutil.Format = "json"
|
|
|
|
cmd := NewAPICmd()
|
|
cmd.SetArgs([]string{"POST", "/repos/owner/repo/issues"})
|
|
cmd.Flags().Set("body", `{"title":"new issue","body":"test"}`)
|
|
if err := cmd.Execute(); err != nil {
|
|
t.Fatalf("runAPI POST error: %v", err)
|
|
}
|
|
if gotBody["title"] != "new issue" {
|
|
t.Fatalf("body title = %q, want 'new issue'", gotBody["title"])
|
|
}
|
|
}
|
|
|
|
func TestRunAPIBadJSONBody(t *testing.T) {
|
|
setupAPITest(t, func(w http.ResponseWriter, r *http.Request) {
|
|
t.Fatal("should not reach server")
|
|
})
|
|
cmdutil.Format = "json"
|
|
|
|
cmd := NewAPICmd()
|
|
cmd.SetArgs([]string{"POST", "/repos/owner/repo/issues"})
|
|
cmd.Flags().Set("body", `{bad json}`)
|
|
err := cmd.Execute()
|
|
if err == nil {
|
|
t.Fatal("expected error for bad JSON body")
|
|
}
|
|
}
|
|
|
|
func TestRunAPIBadQuery(t *testing.T) {
|
|
setupAPITest(t, func(w http.ResponseWriter, r *http.Request) {
|
|
t.Fatal("should not reach server")
|
|
})
|
|
cmdutil.Format = "json"
|
|
|
|
cmd := NewAPICmd()
|
|
cmd.SetArgs([]string{"GET", "/repos/owner/repo/issues"})
|
|
cmd.Flags().Set("query", "key=%zz")
|
|
err := cmd.Execute()
|
|
if err == nil {
|
|
t.Fatal("expected error for bad query string")
|
|
}
|
|
}
|
|
|
|
func TestRunAPIHTTPError(t *testing.T) {
|
|
setupAPITest(t, func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte("not found"))
|
|
})
|
|
cmdutil.Format = "json"
|
|
|
|
cmd := NewAPICmd()
|
|
cmd.SetArgs([]string{"GET", "/nonexistent"})
|
|
// HTTP errors are caught and printed as error envelopes; runAPI does not return the error
|
|
if err := cmd.Execute(); err != nil {
|
|
t.Fatalf("runAPI HTTP error: %v (expected success with error envelope)", err)
|
|
}
|
|
}
|
|
|
|
func TestRunAPIStatusError(t *testing.T) {
|
|
setupAPITest(t, func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
json.NewEncoder(w).Encode(map[string]interface{}{"status": float64(401), "message": "Unauthorized"})
|
|
})
|
|
cmdutil.Format = "json"
|
|
|
|
cmd := NewAPICmd()
|
|
cmd.SetArgs([]string{"GET", "/users/me"})
|
|
// Should print error envelope, not return a Go error (status check in Do() handles this)
|
|
// Actually, HTTP 401 triggers APIError return from Do(), so this should error
|
|
if err := cmd.Execute(); err != nil {
|
|
// Expected — HTTP error
|
|
t.Logf("got expected error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRunAPIDebug(t *testing.T) {
|
|
var gotDebugHeader bool
|
|
setupAPITest(t, func(w http.ResponseWriter, r *http.Request) {
|
|
gotDebugHeader = true
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(map[string]interface{}{"ok": true})
|
|
})
|
|
cmdutil.Format = "json"
|
|
cmdutil.Debug = true
|
|
defer func() { cmdutil.Debug = false }()
|
|
|
|
cmd := NewAPICmd()
|
|
cmd.SetArgs([]string{"GET", "/users/me"})
|
|
if err := cmd.Execute(); err != nil {
|
|
t.Fatalf("runAPI debug error: %v", err)
|
|
}
|
|
if !gotDebugHeader {
|
|
t.Fatal("server not reached")
|
|
}
|
|
}
|
|
|
|
func TestRunAPINoPrefix(t *testing.T) {
|
|
setupAPITest(t, func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/users/me.json" {
|
|
t.Fatalf("unexpected path: %s", r.URL.Path)
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(map[string]interface{}{"login": "testuser"})
|
|
})
|
|
cmdutil.Format = "json"
|
|
|
|
cmd := NewAPICmd()
|
|
cmd.SetArgs([]string{"GET", "users/me"})
|
|
if err := cmd.Execute(); err != nil {
|
|
t.Fatalf("runAPI no-prefix error: %v", err)
|
|
}
|
|
}
|