package gitea import ( "context" "encoding/json" "io" "net/http" "net/http/httptest" "strings" "testing" "time" ) func TestCloseIssueRoundTrip(t *testing.T) { var gotState string srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPatch { t.Errorf("method = %s, want PATCH", r.Method) } if r.Header.Get("Content-Type") != "application/json" { t.Errorf("Content-Type = %q", r.Header.Get("Content-Type")) } var body map[string]string _ = json.NewDecoder(r.Body).Decode(&body) gotState = body["state"] w.WriteHeader(201) _, _ = io.WriteString(w, `{}`) })) defer srv.Close() c := New(srv.URL, "tok") if err := c.CloseIssue(context.Background(), "m", "projax", 42); err != nil { t.Fatalf("CloseIssue: %v", err) } if gotState != "closed" { t.Errorf("upstream got state=%q, want 'closed'", gotState) } } func TestReopenIssueRoundTrip(t *testing.T) { var gotState string srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var body map[string]string _ = json.NewDecoder(r.Body).Decode(&body) gotState = body["state"] w.WriteHeader(201) _, _ = io.WriteString(w, `{}`) })) defer srv.Close() c := New(srv.URL, "tok") if err := c.ReopenIssue(context.Background(), "m", "projax", 42); err != nil { t.Fatalf("ReopenIssue: %v", err) } if gotState != "open" { t.Errorf("upstream got state=%q, want 'open'", gotState) } } func TestCreateIssueRoundTrip(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { t.Errorf("method = %s, want POST", r.Method) } if !strings.HasSuffix(r.URL.Path, "/issues") { t.Errorf("path = %q, want suffix /issues", r.URL.Path) } var body map[string]string _ = json.NewDecoder(r.Body).Decode(&body) if body["title"] != "Test issue" { t.Errorf("title = %q", body["title"]) } w.WriteHeader(201) _, _ = io.WriteString(w, `{ "number": 99, "title": "Test issue", "state": "open", "updated_at": "2026-05-15T19:00:00Z", "html_url": "https://mgit.msbls.de/m/projax/issues/99", "labels": [{"name": "bug"}], "assignees": [{"login": "mAi"}] }`) })) defer srv.Close() c := New(srv.URL, "tok") iss, err := c.CreateIssue(context.Background(), "m", "projax", "Test issue", "body") if err != nil { t.Fatalf("CreateIssue: %v", err) } if iss.Number != 99 || iss.State != "open" { t.Errorf("issue = %+v", iss) } if len(iss.Labels) != 1 || iss.Labels[0] != "bug" { t.Errorf("labels = %v", iss.Labels) } if len(iss.Assignees) != 1 || iss.Assignees[0] != "mAi" { t.Errorf("assignees = %v", iss.Assignees) } } func TestAddCommentRoundTrip(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if !strings.HasSuffix(r.URL.Path, "/comments") { t.Errorf("path = %q", r.URL.Path) } var body map[string]string _ = json.NewDecoder(r.Body).Decode(&body) if body["body"] != "First!" { t.Errorf("body = %q", body["body"]) } w.WriteHeader(201) _, _ = io.WriteString(w, `{ "id": 12345, "body": "First!", "html_url": "https://mgit.msbls.de/m/projax/issues/42#issuecomment-12345", "created_at": "2026-05-15T19:00:00Z" }`) })) defer srv.Close() c := New(srv.URL, "tok") cm, err := c.AddComment(context.Background(), "m", "projax", 42, "First!") if err != nil { t.Fatalf("AddComment: %v", err) } if cm.ID != 12345 || cm.Body != "First!" { t.Errorf("comment = %+v", cm) } want := time.Date(2026, 5, 15, 19, 0, 0, 0, time.UTC) if !cm.CreatedAt.Equal(want) { t.Errorf("CreatedAt = %v, want %v", cm.CreatedAt, want) } } func TestWriteback403ReturnsErrForbidden(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Error(w, `{"message":"forbidden"}`, http.StatusForbidden) })) defer srv.Close() c := New(srv.URL, "tok") if err := c.CloseIssue(context.Background(), "m", "projax", 1); err != ErrForbidden { t.Errorf("expected ErrForbidden, got %v", err) } }