From b42c62fdb2123c2245199559961cc289a59e37e1 Mon Sep 17 00:00:00 2001 From: Will Norris Date: Tue, 18 Jun 2013 19:42:10 -0700 Subject: [PATCH] Add basic issues related methods This adds basic methods for working with issues, assignees, and issue comments. Issue events, labels, and milestones are not included in this commit. (Fixes #7) --- github/github.go | 2 + github/issues.go | 302 +++++++++++++++++++++++++++ github/issues_test.go | 467 ++++++++++++++++++++++++++++++++++++++++++ github/orgs_test.go | 4 +- 4 files changed, 773 insertions(+), 2 deletions(-) create mode 100644 github/issues.go create mode 100644 github/issues_test.go diff --git a/github/github.go b/github/github.go index 1dfc887..760d729 100644 --- a/github/github.go +++ b/github/github.go @@ -76,6 +76,7 @@ type Client struct { // Services used for talking to different parts of the API + Issues *IssuesService Organizations *OrganizationsService Repositories *RepositoriesService Users *UsersService @@ -99,6 +100,7 @@ func NewClient(httpClient *http.Client) *Client { baseURL, _ := url.Parse(defaultBaseURL) c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent} + c.Issues = &IssuesService{client: c} c.Organizations = &OrganizationsService{client: c} c.Repositories = &RepositoriesService{client: c} c.Users = &UsersService{client: c} diff --git a/github/issues.go b/github/issues.go new file mode 100644 index 0000000..4fd47fa --- /dev/null +++ b/github/issues.go @@ -0,0 +1,302 @@ +// Copyright 2013 Google. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +package github + +import ( + "fmt" + "net/url" + "strings" + "time" +) + +// IssuesService handles communication with the issue related +// methods of the GitHub API. +// +// GitHub API docs: http://developer.github.com/v3/issues/ +type IssuesService struct { + client *Client +} + +// Issue represents a GitHub issue on a repository. +type Issue struct { + Number int `json:"number,omitempty"` + State string `json:"state,omitempty"` + Title string `json:"title,omitempty"` + Body string `json:"body,omitempty"` + User *User `json:"user,omitempty"` + Assignee *User `json:"assignee,omitempty"` + Comments int `json:"comments,omitempty"` + ClosedAt *time.Time `json:"closed_at,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + UpdatedAt *time.Time `json:"updated_at,omitempty"` + + // TODO(willnorris): labels and milestone +} + +// IssueComment represents a comment left on an issue. +type IssueComment struct { + ID int `json:"id,omitempty"` + Body string `json:"body:omitempty"` + User *User `json:"user,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + UpdatedAt *time.Time `json:"updated_at,omitempty"` +} + +// IssueListOptions specifies the optional parameters to the IssuesService.List +// and IssuesService.ListByOrg methods. +type IssueListOptions struct { + Filter string + State string + Labels []string + Sort string + Direction string + Since time.Time +} + +// List the issues for the authenticated user. If all is true, list issues +// across all the user's visible repositories including owned, member, and +// organization repositories; if false, list only owned and member +// repositories. +// +// GitHub API docs: http://developer.github.com/v3/issues/#list-issues +func (s *IssuesService) List(all bool, opt *IssueListOptions) ([]Issue, error) { + var u string + if all { + u = "issues" + } else { + u = "user/issues" + } + return s.listIssues(u, opt) +} + +// ListByOrg fetches the issues in the specified organization for the +// authenticated user. +// +// GitHub API docs: http://developer.github.com/v3/issues/#list-issues +func (s *IssuesService) ListByOrg(org string, opt *IssueListOptions) ([]Issue, error) { + u := fmt.Sprintf("orgs/%v/issues", org) + return s.listIssues(u, opt) +} + +func (s *IssuesService) listIssues(u string, opt *IssueListOptions) ([]Issue, error) { + if opt != nil { + params := url.Values{ + "filter": {opt.Filter}, + "state": {opt.State}, + "labels": {strings.Join(opt.Labels, ",")}, + "sort": {opt.Sort}, + "direction": {opt.Direction}, + } + if !opt.Since.IsZero() { + params.Add("since", opt.Since.Format(time.RFC3339)) + } + u += "?" + params.Encode() + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, err + } + + issues := new([]Issue) + _, err = s.client.Do(req, issues) + return *issues, err +} + +// IssueListByRepoOptions specifies the optional parameters to the +// IssuesService.List and IssuesService.ListByOrg methods. +type IssueListByRepoOptions struct { + Milestone string + State string + Assignee string + Creator string + Mentioned string + Labels []string + Sort string + Direction string + Since time.Time +} + +// ListByRepo lists the issues for the specified repository. +// +// GitHub API docs: http://developer.github.com/v3/issues/#list-issues-for-a-repository +func (s *IssuesService) ListByRepo(owner string, repo string, opt *IssueListByRepoOptions) ([]Issue, error) { + u := fmt.Sprintf("repos/%v/%v/issues", owner, repo) + if opt != nil { + params := url.Values{ + "milestone": {opt.Milestone}, + "state": {opt.State}, + "assignee": {opt.Assignee}, + "creator": {opt.Creator}, + "mentioned": {opt.Mentioned}, + "labels": {strings.Join(opt.Labels, ",")}, + "sort": {opt.Sort}, + "direction": {opt.Direction}, + } + if !opt.Since.IsZero() { + params.Add("since", opt.Since.Format(time.RFC3339)) + } + u += "?" + params.Encode() + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, err + } + + issues := new([]Issue) + _, err = s.client.Do(req, issues) + return *issues, err +} + +// Get a single issue. +// +// GitHub API docs: http://developer.github.com/v3/issues/#get-a-single-issue +func (s *IssuesService) Get(owner string, repo string, number int) (*Issue, error) { + u := fmt.Sprintf("repos/%v/%v/issues/%d", owner, repo, number) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, err + } + issue := new(Issue) + _, err = s.client.Do(req, issue) + return issue, err +} + +// Create a new issue on the specified repository. +// +// GitHub API docs: http://developer.github.com/v3/issues/#create-an-issue +func (s *IssuesService) Create(owner string, repo string, issue *Issue) (*Issue, error) { + u := fmt.Sprintf("repos/%v/%v/issues", owner, repo) + req, err := s.client.NewRequest("POST", u, issue) + if err != nil { + return nil, err + } + i := new(Issue) + _, err = s.client.Do(req, i) + return i, err +} + +// Edit an issue. +// +// GitHub API docs: http://developer.github.com/v3/issues/#edit-an-issue +func (s *IssuesService) Edit(owner string, repo string, number int, issue *Issue) (*Issue, error) { + u := fmt.Sprintf("repos/%v/%v/issues/%d", owner, repo, number) + req, err := s.client.NewRequest("PATCH", u, issue) + if err != nil { + return nil, err + } + i := new(Issue) + _, err = s.client.Do(req, i) + return i, err +} + +// ListAssignees fetches all available assignees (owners and collaborators) to +// which issues may be assigned. +// +// GitHub API docs: http://developer.github.com/v3/issues/assignees/#list-assignees +func (s *IssuesService) ListAssignees(owner string, repo string) ([]User, error) { + u := fmt.Sprintf("repos/%v/%v/assignees", owner, repo) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, err + } + assignees := new([]User) + _, err = s.client.Do(req, assignees) + return *assignees, err +} + +// CheckAssignee checks if a user is an assignee for the specified repository. +// +// GitHub API docs: http://developer.github.com/v3/issues/assignees/#check-assignee +func (s *IssuesService) CheckAssignee(owner string, repo string, user string) (bool, error) { + u := fmt.Sprintf("repos/%v/%v/assignees/%v", owner, repo, user) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return false, err + } + _, err = s.client.Do(req, nil) + return parseBoolResponse(err) +} + +// ListComments lists all comments on the specified issue. Specifying an issue +// number of 0 will return all comments on all issues for the repository. +// +// GitHub API docs: http://developer.github.com/v3/issues/comments/#list-comments-on-an-issue +func (s *IssuesService) ListComments(owner string, repo string, number int) ([]IssueComment, error) { + var u string + if number == 0 { + u = fmt.Sprintf("repos/%v/%v/issues/comments", owner, repo) + } else { + u = fmt.Sprintf("repos/%v/%v/issues/%d/comments", owner, repo, number) + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, err + } + comments := new([]IssueComment) + _, err = s.client.Do(req, comments) + return *comments, err +} + +// GetComment fetches the specified issue comment. +// +// GitHub API docs: http://developer.github.com/v3/issues/comments/#get-a-single-comment +func (s *IssuesService) GetComment(owner string, repo string, id int) (*IssueComment, error) { + u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, id) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, err + } + comment := new(IssueComment) + _, err = s.client.Do(req, comment) + return comment, err +} + +// CreateComment creates a new comment on the specified issue. +// +// GitHub API docs: http://developer.github.com/v3/issues/comments/#create-a-comment +func (s *IssuesService) CreateComment(owner string, repo string, number int, comment *IssueComment) (*IssueComment, error) { + u := fmt.Sprintf("repos/%v/%v/issues/%d/comments", owner, repo, number) + req, err := s.client.NewRequest("POST", u, comment) + if err != nil { + return nil, err + } + c := new(IssueComment) + _, err = s.client.Do(req, c) + return c, err +} + +// EditComment updates an issue comment. +// +// GitHub API docs: http://developer.github.com/v3/issues/comments/#edit-a-comment +func (s *IssuesService) EditComment(owner string, repo string, id int, comment *IssueComment) (*IssueComment, error) { + u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, id) + req, err := s.client.NewRequest("PATCH", u, comment) + if err != nil { + return nil, err + } + c := new(IssueComment) + _, err = s.client.Do(req, c) + return c, err +} + +// DeleteComment updates an issue comment. +// +// GitHub API docs: http://developer.github.com/v3/issues/comments/#delete-a-comment +func (s *IssuesService) DeleteComment(owner string, repo string, id int) error { + u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, id) + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return err + } + + _, err = s.client.Do(req, nil) + return err +} diff --git a/github/issues_test.go b/github/issues_test.go new file mode 100644 index 0000000..b084039 --- /dev/null +++ b/github/issues_test.go @@ -0,0 +1,467 @@ +// Copyright 2013 Google. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +package github + +import ( + "encoding/json" + "fmt" + "net/http" + "reflect" + "testing" + "time" +) + +func TestIssuesService_List_all(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/issues", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{ + "filter": "all", + "state": "closed", + "labels": "a,b", + "sort": "updated", + "direction": "asc", + "since": "2002-02-10T15:30:00Z", + }) + fmt.Fprint(w, `[{"number":1}]`) + }) + + opt := &IssueListOptions{ + "all", "closed", []string{"a", "b"}, "updated", "asc", + time.Date(2002, time.February, 10, 15, 30, 0, 0, time.UTC), + } + issues, err := client.Issues.List(true, opt) + + if err != nil { + t.Errorf("Issues.List returned error: %v", err) + } + + want := []Issue{Issue{Number: 1}} + if !reflect.DeepEqual(issues, want) { + t.Errorf("Issues.List returned %+v, want %+v", issues, want) + } +} + +func TestIssuesService_List_owned(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/user/issues", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `[{"number":1}]`) + }) + + issues, err := client.Issues.List(false, nil) + if err != nil { + t.Errorf("Issues.List returned error: %v", err) + } + + want := []Issue{Issue{Number: 1}} + if !reflect.DeepEqual(issues, want) { + t.Errorf("Issues.List returned %+v, want %+v", issues, want) + } +} + +func TestIssuesService_ListByOrg(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/orgs/o/issues", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `[{"number":1}]`) + }) + + issues, err := client.Issues.ListByOrg("o", nil) + if err != nil { + t.Errorf("Issues.ListByOrg returned error: %v", err) + } + + want := []Issue{Issue{Number: 1}} + if !reflect.DeepEqual(issues, want) { + t.Errorf("Issues.List returned %+v, want %+v", issues, want) + } +} + +func TestIssuesService_ListByOrg_invalidOrg(t *testing.T) { + _, err := client.Issues.ListByOrg("%", nil) + testURLParseError(t, err) +} + +func TestIssuesService_ListByRepo(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/issues", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{ + "milestone": "*", + "state": "closed", + "assignee": "a", + "creator": "c", + "mentioned": "m", + "labels": "a,b", + "sort": "updated", + "direction": "asc", + "since": "2002-02-10T15:30:00Z", + }) + fmt.Fprint(w, `[{"number":1}]`) + }) + + opt := &IssueListByRepoOptions{ + "*", "closed", "a", "c", "m", []string{"a", "b"}, "updated", "asc", + time.Date(2002, time.February, 10, 15, 30, 0, 0, time.UTC), + } + issues, err := client.Issues.ListByRepo("o", "r", opt) + if err != nil { + t.Errorf("Issues.ListByOrg returned error: %v", err) + } + + want := []Issue{Issue{Number: 1}} + if !reflect.DeepEqual(issues, want) { + t.Errorf("Issues.List returned %+v, want %+v", issues, want) + } +} + +func TestIssuesService_ListByRepo_invalidOwner(t *testing.T) { + _, err := client.Issues.ListByRepo("%", "r", nil) + testURLParseError(t, err) +} + +func TestIssuesService_Get(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/issues/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"number":1}`) + }) + + issue, err := client.Issues.Get("o", "r", 1) + if err != nil { + t.Errorf("Issues.Get returned error: %v", err) + } + + want := &Issue{Number: 1} + if !reflect.DeepEqual(issue, want) { + t.Errorf("Issues.Get returned %+v, want %+v", issue, want) + } +} + +func TestIssuesService_Get_invalidOwner(t *testing.T) { + _, err := client.Issues.Get("%", "r", 1) + testURLParseError(t, err) +} + +func TestIssuesService_Create(t *testing.T) { + setup() + defer teardown() + + input := &Issue{Title: "t"} + + mux.HandleFunc("/repos/o/r/issues", func(w http.ResponseWriter, r *http.Request) { + v := new(Issue) + json.NewDecoder(r.Body).Decode(v) + + testMethod(t, r, "POST") + if !reflect.DeepEqual(v, input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } + + fmt.Fprint(w, `{"number":1}`) + }) + + issue, err := client.Issues.Create("o", "r", input) + if err != nil { + t.Errorf("Issues.Create returned error: %v", err) + } + + want := &Issue{Number: 1} + if !reflect.DeepEqual(issue, want) { + t.Errorf("Issues.Create returned %+v, want %+v", issue, want) + } +} + +func TestIssuesService_Create_invalidOwner(t *testing.T) { + _, err := client.Issues.Create("%", "r", nil) + testURLParseError(t, err) +} + +func TestIssuesService_Edit(t *testing.T) { + setup() + defer teardown() + + input := &Issue{Title: "t"} + + mux.HandleFunc("/repos/o/r/issues/1", func(w http.ResponseWriter, r *http.Request) { + v := new(Issue) + json.NewDecoder(r.Body).Decode(v) + + testMethod(t, r, "PATCH") + if !reflect.DeepEqual(v, input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } + + fmt.Fprint(w, `{"number":1}`) + }) + + issue, err := client.Issues.Edit("o", "r", 1, input) + if err != nil { + t.Errorf("Issues.Edit returned error: %v", err) + } + + want := &Issue{Number: 1} + if !reflect.DeepEqual(issue, want) { + t.Errorf("Issues.Edit returned %+v, want %+v", issue, want) + } +} + +func TestIssuesService_Edit_invalidOwner(t *testing.T) { + _, err := client.Issues.Edit("%", "r", 1, nil) + testURLParseError(t, err) +} + +func TestIssuesService_ListAssignees(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/assignees", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `[{"id":1}]`) + }) + + assignees, err := client.Issues.ListAssignees("o", "r") + if err != nil { + t.Errorf("Issues.List returned error: %v", err) + } + + want := []User{User{ID: 1}} + if !reflect.DeepEqual(assignees, want) { + t.Errorf("Issues.ListAssignees returned %+v, want %+v", assignees, want) + } +} + +func TestIssuesService_ListAssignees_invalidOwner(t *testing.T) { + _, err := client.Issues.ListAssignees("%", "r") + testURLParseError(t, err) +} + +func TestIssuesService_CheckAssignee_true(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/assignees/u", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + }) + + assignee, err := client.Issues.CheckAssignee("o", "r", "u") + if err != nil { + t.Errorf("Issues.CheckAssignee returned error: %v", err) + } + if want := true; assignee != want { + t.Errorf("Issues.CheckAssignee returned %+v, want %+v", assignee, want) + } +} + +func TestIssuesService_CheckAssignee_false(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/assignees/u", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + w.WriteHeader(http.StatusNotFound) + }) + + assignee, err := client.Issues.CheckAssignee("o", "r", "u") + if err != nil { + t.Errorf("Issues.CheckAssignee returned error: %v", err) + } + if want := false; assignee != want { + t.Errorf("Issues.CheckAssignee returned %+v, want %+v", assignee, want) + } +} + +func TestIssuesService_CheckAssignee_error(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/assignees/u", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + http.Error(w, "BadRequest", http.StatusBadRequest) + }) + + assignee, err := client.Issues.CheckAssignee("o", "r", "u") + if err == nil { + t.Errorf("Expected HTTP 400 response") + } + if want := false; assignee != want { + t.Errorf("Issues.CheckAssignee returned %+v, want %+v", assignee, want) + } +} + +func TestIssuesService_CheckAssignee_invalidOwner(t *testing.T) { + _, err := client.Issues.CheckAssignee("%", "r", "u") + testURLParseError(t, err) +} + +func TestIssuesService_ListComments_allIssues(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/issues/comments", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `[{"id":1}]`) + }) + + comments, err := client.Issues.ListComments("o", "r", 0) + if err != nil { + t.Errorf("Issues.ListComments returned error: %v", err) + } + + want := []IssueComment{IssueComment{ID: 1}} + if !reflect.DeepEqual(comments, want) { + t.Errorf("Issues.ListComments returned %+v, want %+v", comments, want) + } +} + +func TestIssuesService_ListComments_specificIssue(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/issues/1/comments", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `[{"id":1}]`) + }) + + comments, err := client.Issues.ListComments("o", "r", 1) + if err != nil { + t.Errorf("Issues.ListComments returned error: %v", err) + } + + want := []IssueComment{IssueComment{ID: 1}} + if !reflect.DeepEqual(comments, want) { + t.Errorf("Issues.ListComments returned %+v, want %+v", comments, want) + } +} + +func TestIssuesService_ListComments_invalidOwner(t *testing.T) { + _, err := client.Issues.ListComments("%", "r", 1) + testURLParseError(t, err) +} + +func TestIssuesService_GetComment(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/issues/comments/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"id":1}`) + }) + + comment, err := client.Issues.GetComment("o", "r", 1) + if err != nil { + t.Errorf("Issues.GetComment returned error: %v", err) + } + + want := &IssueComment{ID: 1} + if !reflect.DeepEqual(comment, want) { + t.Errorf("Issues.GetComment returned %+v, want %+v", comment, want) + } +} + +func TestIssuesService_GetComment_invalidOrg(t *testing.T) { + _, err := client.Issues.GetComment("%", "r", 1) + testURLParseError(t, err) +} + +func TestIssuesService_CreateComment(t *testing.T) { + setup() + defer teardown() + + input := &IssueComment{Body: "b"} + + mux.HandleFunc("/repos/o/r/issues/1/comments", func(w http.ResponseWriter, r *http.Request) { + v := new(IssueComment) + json.NewDecoder(r.Body).Decode(v) + + testMethod(t, r, "POST") + if !reflect.DeepEqual(v, input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } + + fmt.Fprint(w, `{"id":1}`) + }) + + comment, err := client.Issues.CreateComment("o", "r", 1, input) + if err != nil { + t.Errorf("Issues.CreateComment returned error: %v", err) + } + + want := &IssueComment{ID: 1} + if !reflect.DeepEqual(comment, want) { + t.Errorf("Issues.CreateComment returned %+v, want %+v", comment, want) + } +} + +func TestIssuesService_CreateComment_invalidOrg(t *testing.T) { + _, err := client.Issues.CreateComment("%", "r", 1, nil) + testURLParseError(t, err) +} + +func TestIssuesService_EditComment(t *testing.T) { + setup() + defer teardown() + + input := &IssueComment{Body: "b"} + + mux.HandleFunc("/repos/o/r/issues/comments/1", func(w http.ResponseWriter, r *http.Request) { + v := new(IssueComment) + json.NewDecoder(r.Body).Decode(v) + + testMethod(t, r, "PATCH") + if !reflect.DeepEqual(v, input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } + + fmt.Fprint(w, `{"id":1}`) + }) + + comment, err := client.Issues.EditComment("o", "r", 1, input) + if err != nil { + t.Errorf("Issues.EditComment returned error: %v", err) + } + + want := &IssueComment{ID: 1} + if !reflect.DeepEqual(comment, want) { + t.Errorf("Issues.EditComment returned %+v, want %+v", comment, want) + } +} + +func TestIssuesService_EditComment_invalidOwner(t *testing.T) { + _, err := client.Issues.EditComment("%", "r", 1, nil) + testURLParseError(t, err) +} + +func TestIssuesService_DeleteComment(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/issues/comments/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + }) + + err := client.Issues.DeleteComment("o", "r", 1) + if err != nil { + t.Errorf("Issues.DeleteComments returned error: %v", err) + } +} + +func TestIssuesService_DeleteComment_invalidOwner(t *testing.T) { + err := client.Issues.DeleteComment("%", "r", 1) + testURLParseError(t, err) +} diff --git a/github/orgs_test.go b/github/orgs_test.go index 7af4658..f8c9abd 100644 --- a/github/orgs_test.go +++ b/github/orgs_test.go @@ -455,7 +455,7 @@ func TestOrganizationsService_ListTeamMembers(t *testing.T) { } } -func TestOrganizationsService_CheckTeamMembership(t *testing.T) { +func TestOrganizationsService_CheckTeamMembership_true(t *testing.T) { setup() defer teardown() @@ -473,7 +473,7 @@ func TestOrganizationsService_CheckTeamMembership(t *testing.T) { } // ensure that a 404 response is interpreted as "false" and not an error -func TestOrganizationsService_CheckTeamMembership_notMember(t *testing.T) { +func TestOrganizationsService_CheckTeamMembership_false(t *testing.T) { setup() defer teardown()