package gitea import ( "context" "net/http" "net/http/httptest" "testing" "time" ) func newTestClient(t *testing.T, h http.Handler) *Client { t.Helper() srv := httptest.NewServer(h) t.Cleanup(srv.Close) c := NewClient(srv.URL, "test-token") return c } func TestListIssuesExcludesPullsAndSendsAuth(t *testing.T) { var gotAuth, gotType, gotState, gotSince string c := newTestClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { gotAuth = r.Header.Get("Authorization") gotType = r.URL.Query().Get("type") gotState = r.URL.Query().Get("state") gotSince = r.URL.Query().Get("since") w.Header().Set("Content-Type", "application/json") // One real issue and one PR-shaped issue that must be filtered out. _, _ = w.Write([]byte(`[ {"id":1,"number":5,"title":"real issue","user":{"login":"alice"}}, {"id":2,"number":6,"title":"a pr","user":{"login":"bob"},"pull_request":{"merged":false}} ]`)) })) since := time.Date(2026, 1, 2, 3, 4, 5, 0, time.UTC) issues, err := c.ListIssues(context.Background(), "unkin/teabot", since) if err != nil { t.Fatalf("ListIssues: %v", err) } if len(issues) != 1 || issues[0].Index != 5 { t.Fatalf("expected 1 non-PR issue #5, got %+v", issues) } if gotAuth != "token test-token" { t.Errorf("Authorization = %q", gotAuth) } if gotType != "issues" || gotState != "open" { t.Errorf("query type=%q state=%q", gotType, gotState) } if gotSince != "2026-01-02T03:04:05Z" { t.Errorf("since = %q", gotSince) } } func TestListPulls(t *testing.T) { c := newTestClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Query().Get("state") != "open" { t.Errorf("state = %q", r.URL.Query().Get("state")) } _, _ = w.Write([]byte(`[{"id":1,"number":7,"title":"add feature","user":{"login":"carol"},"head":{"ref":"benvin/x"},"base":{"ref":"main"}}]`)) })) pulls, err := c.ListPulls(context.Background(), "unkin/teabot") if err != nil { t.Fatalf("ListPulls: %v", err) } if len(pulls) != 1 || pulls[0].Index != 7 || pulls[0].Head.Ref != "benvin/x" { t.Fatalf("unexpected pulls: %+v", pulls) } } func TestListComments(t *testing.T) { c := newTestClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(`[{"id":42,"body":"looks good","user":{"login":"dave"},"issue_url":"https://git.unkin.net/api/v1/repos/unkin/teabot/issues/5"}]`)) })) comments, err := c.ListComments(context.Background(), "unkin/teabot", time.Time{}) if err != nil { t.Fatalf("ListComments: %v", err) } if len(comments) != 1 || comments[0].ID != 42 { t.Fatalf("unexpected comments: %+v", comments) } } func TestGetPullDiff(t *testing.T) { c := newTestClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/api/v1/repos/unkin/teabot/pulls/7.diff" { t.Errorf("path = %q", r.URL.Path) } _, _ = w.Write([]byte("diff --git a/x b/x\n+hello\n")) })) diff, err := c.GetPullDiff(context.Background(), "unkin/teabot", 7) if err != nil { t.Fatalf("GetPullDiff: %v", err) } if diff == "" || diff[:4] != "diff" { t.Errorf("unexpected diff: %q", diff) } } func TestGetErrorsOnNon2xx(t *testing.T) { c := newTestClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Error(w, "nope", http.StatusForbidden) })) if _, err := c.ListIssues(context.Background(), "a/b", time.Time{}); err == nil { t.Error("expected error on 403") } } func TestSplitRepoValidation(t *testing.T) { c := NewClient("https://example.com", "t") if _, err := c.ListIssues(context.Background(), "noslash", time.Time{}); err == nil { t.Error("expected error for repo without slash") } } func TestIssueIndexFromCommentURL(t *testing.T) { cases := []struct { name string comment Comment want int64 ok bool }{ {"issue url", Comment{IssueURL: "https://git.unkin.net/api/v1/repos/unkin/teabot/issues/5"}, 5, true}, {"pr url", Comment{PRURL: "https://git.unkin.net/api/v1/repos/unkin/teabot/pulls/12"}, 12, true}, {"trailing slash", Comment{IssueURL: "https://x/issues/8/"}, 8, true}, {"no url", Comment{}, 0, false}, {"non-numeric", Comment{IssueURL: "https://x/issues/abc"}, 0, false}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { got, ok := IssueIndexFromCommentURL(tc.comment) if ok != tc.ok || got != tc.want { t.Errorf("got (%d,%v), want (%d,%v)", got, ok, tc.want, tc.ok) } }) } }