go-forge/labels_test.go
Snider de76399608 feat: LabelService, WebhookService, ContentService
Add three new services covering labels, webhooks, and file content
operations. LabelService handles repo and org labels without Resource
embedding due to heterogeneous paths. WebhookService embeds Resource
for standard CRUD on repo hooks plus action methods for test delivery
and org hooks. ContentService provides file CRUD and raw file retrieval.
Adds GetRaw method to Client for non-JSON responses.

Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 17:14:01 +00:00

232 lines
6.5 KiB
Go

package forge
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"forge.lthn.ai/core/go-forge/types"
)
func TestLabelService_Good_ListRepoLabels(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/repos/core/go-forge/labels" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "2")
json.NewEncoder(w).Encode([]types.Label{
{ID: 1, Name: "bug", Color: "#d73a4a"},
{ID: 2, Name: "feature", Color: "#0075ca"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
labels, err := f.Labels.ListRepoLabels(context.Background(), "core", "go-forge")
if err != nil {
t.Fatal(err)
}
if len(labels) != 2 {
t.Errorf("got %d labels, want 2", len(labels))
}
if labels[0].Name != "bug" {
t.Errorf("got name=%q, want %q", labels[0].Name, "bug")
}
if labels[1].Color != "#0075ca" {
t.Errorf("got colour=%q, want %q", labels[1].Color, "#0075ca")
}
}
func TestLabelService_Good_CreateRepoLabel(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
t.Errorf("expected POST, got %s", r.Method)
}
if r.URL.Path != "/api/v1/repos/core/go-forge/labels" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var opts types.CreateLabelOption
if err := json.NewDecoder(r.Body).Decode(&opts); err != nil {
t.Fatal(err)
}
if opts.Name != "enhancement" {
t.Errorf("got name=%q, want %q", opts.Name, "enhancement")
}
if opts.Color != "#a2eeef" {
t.Errorf("got colour=%q, want %q", opts.Color, "#a2eeef")
}
json.NewEncoder(w).Encode(types.Label{
ID: 3,
Name: opts.Name,
Color: opts.Color,
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
label, err := f.Labels.CreateRepoLabel(context.Background(), "core", "go-forge", &types.CreateLabelOption{
Name: "enhancement",
Color: "#a2eeef",
})
if err != nil {
t.Fatal(err)
}
if label.ID != 3 {
t.Errorf("got id=%d, want 3", label.ID)
}
if label.Name != "enhancement" {
t.Errorf("got name=%q, want %q", label.Name, "enhancement")
}
}
func TestLabelService_Good_GetRepoLabel(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/repos/core/go-forge/labels/1" {
t.Errorf("wrong path: %s", r.URL.Path)
}
json.NewEncoder(w).Encode(types.Label{ID: 1, Name: "bug", Color: "#d73a4a"})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
label, err := f.Labels.GetRepoLabel(context.Background(), "core", "go-forge", 1)
if err != nil {
t.Fatal(err)
}
if label.Name != "bug" {
t.Errorf("got name=%q, want %q", label.Name, "bug")
}
}
func TestLabelService_Good_EditRepoLabel(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPatch {
t.Errorf("expected PATCH, got %s", r.Method)
}
if r.URL.Path != "/api/v1/repos/core/go-forge/labels/1" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var opts types.EditLabelOption
if err := json.NewDecoder(r.Body).Decode(&opts); err != nil {
t.Fatal(err)
}
json.NewEncoder(w).Encode(types.Label{ID: 1, Name: opts.Name, Color: opts.Color})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
label, err := f.Labels.EditRepoLabel(context.Background(), "core", "go-forge", 1, &types.EditLabelOption{
Name: "critical-bug",
Color: "#ff0000",
})
if err != nil {
t.Fatal(err)
}
if label.Name != "critical-bug" {
t.Errorf("got name=%q, want %q", label.Name, "critical-bug")
}
}
func TestLabelService_Good_DeleteRepoLabel(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodDelete {
t.Errorf("expected DELETE, got %s", r.Method)
}
if r.URL.Path != "/api/v1/repos/core/go-forge/labels/1" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
err := f.Labels.DeleteRepoLabel(context.Background(), "core", "go-forge", 1)
if err != nil {
t.Fatal(err)
}
}
func TestLabelService_Good_ListOrgLabels(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("expected GET, got %s", r.Method)
}
if r.URL.Path != "/api/v1/orgs/myorg/labels" {
t.Errorf("wrong path: %s", r.URL.Path)
}
w.Header().Set("X-Total-Count", "1")
json.NewEncoder(w).Encode([]types.Label{
{ID: 10, Name: "org-wide", Color: "#333333"},
})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
labels, err := f.Labels.ListOrgLabels(context.Background(), "myorg")
if err != nil {
t.Fatal(err)
}
if len(labels) != 1 {
t.Errorf("got %d labels, want 1", len(labels))
}
if labels[0].Name != "org-wide" {
t.Errorf("got name=%q, want %q", labels[0].Name, "org-wide")
}
}
func TestLabelService_Good_CreateOrgLabel(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
t.Errorf("expected POST, got %s", r.Method)
}
if r.URL.Path != "/api/v1/orgs/myorg/labels" {
t.Errorf("wrong path: %s", r.URL.Path)
}
var opts types.CreateLabelOption
if err := json.NewDecoder(r.Body).Decode(&opts); err != nil {
t.Fatal(err)
}
json.NewEncoder(w).Encode(types.Label{ID: 11, Name: opts.Name, Color: opts.Color})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
label, err := f.Labels.CreateOrgLabel(context.Background(), "myorg", &types.CreateLabelOption{
Name: "priority",
Color: "#e4e669",
})
if err != nil {
t.Fatal(err)
}
if label.ID != 11 {
t.Errorf("got id=%d, want 11", label.ID)
}
if label.Name != "priority" {
t.Errorf("got name=%q, want %q", label.Name, "priority")
}
}
func TestLabelService_Bad_NotFound(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
json.NewEncoder(w).Encode(map[string]string{"message": "label not found"})
}))
defer srv.Close()
f := NewForge(srv.URL, "tok")
_, err := f.Labels.GetRepoLabel(context.Background(), "core", "go-forge", 999)
if err == nil {
t.Fatal("expected error, got nil")
}
if !IsNotFound(err) {
t.Errorf("expected not-found error, got %v", err)
}
}