...

Source file src/github.com/google/go-github/v55/github/issues_test.go

Documentation: github.com/google/go-github/v55/github

     1  // Copyright 2013 The go-github AUTHORS. All rights reserved.
     2  //
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package github
     7  
     8  import (
     9  	"context"
    10  	"encoding/json"
    11  	"fmt"
    12  	"net/http"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/google/go-cmp/cmp"
    17  )
    18  
    19  func TestIssuesService_List_all(t *testing.T) {
    20  	client, mux, _, teardown := setup()
    21  	defer teardown()
    22  
    23  	mux.HandleFunc("/issues", func(w http.ResponseWriter, r *http.Request) {
    24  		testMethod(t, r, "GET")
    25  		testHeader(t, r, "Accept", mediaTypeReactionsPreview)
    26  		testFormValues(t, r, values{
    27  			"filter":    "all",
    28  			"state":     "closed",
    29  			"labels":    "a,b",
    30  			"sort":      "updated",
    31  			"direction": "asc",
    32  			"since":     "2002-02-10T15:30:00Z",
    33  			"page":      "1",
    34  			"per_page":  "2",
    35  		})
    36  		fmt.Fprint(w, `[{"number":1}]`)
    37  	})
    38  
    39  	opt := &IssueListOptions{
    40  		"all", "closed", []string{"a", "b"}, "updated", "asc",
    41  		time.Date(2002, time.February, 10, 15, 30, 0, 0, time.UTC),
    42  		ListOptions{Page: 1, PerPage: 2},
    43  	}
    44  	ctx := context.Background()
    45  	issues, _, err := client.Issues.List(ctx, true, opt)
    46  	if err != nil {
    47  		t.Errorf("Issues.List returned error: %v", err)
    48  	}
    49  
    50  	want := []*Issue{{Number: Int(1)}}
    51  	if !cmp.Equal(issues, want) {
    52  		t.Errorf("Issues.List returned %+v, want %+v", issues, want)
    53  	}
    54  
    55  	const methodName = "List"
    56  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
    57  		got, resp, err := client.Issues.List(ctx, true, opt)
    58  		if got != nil {
    59  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
    60  		}
    61  		return resp, err
    62  	})
    63  }
    64  
    65  func TestIssuesService_List_owned(t *testing.T) {
    66  	client, mux, _, teardown := setup()
    67  	defer teardown()
    68  
    69  	mux.HandleFunc("/user/issues", func(w http.ResponseWriter, r *http.Request) {
    70  		testMethod(t, r, "GET")
    71  		testHeader(t, r, "Accept", mediaTypeReactionsPreview)
    72  		fmt.Fprint(w, `[{"number":1}]`)
    73  	})
    74  
    75  	ctx := context.Background()
    76  	issues, _, err := client.Issues.List(ctx, false, nil)
    77  	if err != nil {
    78  		t.Errorf("Issues.List returned error: %v", err)
    79  	}
    80  
    81  	want := []*Issue{{Number: Int(1)}}
    82  	if !cmp.Equal(issues, want) {
    83  		t.Errorf("Issues.List returned %+v, want %+v", issues, want)
    84  	}
    85  }
    86  
    87  func TestIssuesService_ListByOrg(t *testing.T) {
    88  	client, mux, _, teardown := setup()
    89  	defer teardown()
    90  
    91  	mux.HandleFunc("/orgs/o/issues", func(w http.ResponseWriter, r *http.Request) {
    92  		testMethod(t, r, "GET")
    93  		testHeader(t, r, "Accept", mediaTypeReactionsPreview)
    94  		fmt.Fprint(w, `[{"number":1}]`)
    95  	})
    96  
    97  	ctx := context.Background()
    98  	issues, _, err := client.Issues.ListByOrg(ctx, "o", nil)
    99  	if err != nil {
   100  		t.Errorf("Issues.ListByOrg returned error: %v", err)
   101  	}
   102  
   103  	want := []*Issue{{Number: Int(1)}}
   104  	if !cmp.Equal(issues, want) {
   105  		t.Errorf("Issues.List returned %+v, want %+v", issues, want)
   106  	}
   107  
   108  	const methodName = "ListByOrg"
   109  	testBadOptions(t, methodName, func() (err error) {
   110  		_, _, err = client.Issues.ListByOrg(ctx, "\n", nil)
   111  		return err
   112  	})
   113  
   114  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   115  		got, resp, err := client.Issues.ListByOrg(ctx, "o", nil)
   116  		if got != nil {
   117  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   118  		}
   119  		return resp, err
   120  	})
   121  }
   122  
   123  func TestIssuesService_ListByOrg_invalidOrg(t *testing.T) {
   124  	client, _, _, teardown := setup()
   125  	defer teardown()
   126  
   127  	ctx := context.Background()
   128  	_, _, err := client.Issues.ListByOrg(ctx, "%", nil)
   129  	testURLParseError(t, err)
   130  }
   131  
   132  func TestIssuesService_ListByOrg_badOrg(t *testing.T) {
   133  	client, _, _, teardown := setup()
   134  	defer teardown()
   135  
   136  	ctx := context.Background()
   137  	_, _, err := client.Issues.ListByOrg(ctx, "\n", nil)
   138  	testURLParseError(t, err)
   139  }
   140  
   141  func TestIssuesService_ListByRepo(t *testing.T) {
   142  	client, mux, _, teardown := setup()
   143  	defer teardown()
   144  
   145  	mux.HandleFunc("/repos/o/r/issues", func(w http.ResponseWriter, r *http.Request) {
   146  		testMethod(t, r, "GET")
   147  		testHeader(t, r, "Accept", mediaTypeReactionsPreview)
   148  		testFormValues(t, r, values{
   149  			"milestone": "*",
   150  			"state":     "closed",
   151  			"assignee":  "a",
   152  			"creator":   "c",
   153  			"mentioned": "m",
   154  			"labels":    "a,b",
   155  			"sort":      "updated",
   156  			"direction": "asc",
   157  			"since":     "2002-02-10T15:30:00Z",
   158  		})
   159  		fmt.Fprint(w, `[{"number":1}]`)
   160  	})
   161  
   162  	opt := &IssueListByRepoOptions{
   163  		"*", "closed", "a", "c", "m", []string{"a", "b"}, "updated", "asc",
   164  		time.Date(2002, time.February, 10, 15, 30, 0, 0, time.UTC),
   165  		ListOptions{0, 0},
   166  	}
   167  	ctx := context.Background()
   168  	issues, _, err := client.Issues.ListByRepo(ctx, "o", "r", opt)
   169  	if err != nil {
   170  		t.Errorf("Issues.ListByOrg returned error: %v", err)
   171  	}
   172  
   173  	want := []*Issue{{Number: Int(1)}}
   174  	if !cmp.Equal(issues, want) {
   175  		t.Errorf("Issues.List returned %+v, want %+v", issues, want)
   176  	}
   177  
   178  	const methodName = "ListByRepo"
   179  	testBadOptions(t, methodName, func() (err error) {
   180  		_, _, err = client.Issues.ListByRepo(ctx, "\n", "\n", opt)
   181  		return err
   182  	})
   183  
   184  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   185  		got, resp, err := client.Issues.ListByRepo(ctx, "o", "r", opt)
   186  		if got != nil {
   187  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   188  		}
   189  		return resp, err
   190  	})
   191  }
   192  
   193  func TestIssuesService_ListByRepo_invalidOwner(t *testing.T) {
   194  	client, _, _, teardown := setup()
   195  	defer teardown()
   196  
   197  	ctx := context.Background()
   198  	_, _, err := client.Issues.ListByRepo(ctx, "%", "r", nil)
   199  	testURLParseError(t, err)
   200  }
   201  
   202  func TestIssuesService_Get(t *testing.T) {
   203  	client, mux, _, teardown := setup()
   204  	defer teardown()
   205  
   206  	mux.HandleFunc("/repos/o/r/issues/1", func(w http.ResponseWriter, r *http.Request) {
   207  		testMethod(t, r, "GET")
   208  		testHeader(t, r, "Accept", mediaTypeReactionsPreview)
   209  		fmt.Fprint(w, `{"number":1, "author_association": "MEMBER","labels": [{"url": "u", "name": "n", "color": "c"}]}`)
   210  	})
   211  
   212  	ctx := context.Background()
   213  	issue, _, err := client.Issues.Get(ctx, "o", "r", 1)
   214  	if err != nil {
   215  		t.Errorf("Issues.Get returned error: %v", err)
   216  	}
   217  
   218  	want := &Issue{
   219  		Number:            Int(1),
   220  		AuthorAssociation: String("MEMBER"),
   221  		Labels: []*Label{{
   222  			URL:   String("u"),
   223  			Name:  String("n"),
   224  			Color: String("c"),
   225  		}},
   226  	}
   227  	if !cmp.Equal(issue, want) {
   228  		t.Errorf("Issues.Get returned %+v, want %+v", issue, want)
   229  	}
   230  
   231  	const methodName = "Get"
   232  	testBadOptions(t, methodName, func() (err error) {
   233  		_, _, err = client.Issues.Get(ctx, "\n", "\n", 1)
   234  		return err
   235  	})
   236  
   237  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   238  		got, resp, err := client.Issues.Get(ctx, "o", "r", 1)
   239  		if got != nil {
   240  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   241  		}
   242  		return resp, err
   243  	})
   244  }
   245  
   246  func TestIssuesService_Get_invalidOwner(t *testing.T) {
   247  	client, _, _, teardown := setup()
   248  	defer teardown()
   249  
   250  	ctx := context.Background()
   251  	_, _, err := client.Issues.Get(ctx, "%", "r", 1)
   252  	testURLParseError(t, err)
   253  }
   254  
   255  func TestIssuesService_Create(t *testing.T) {
   256  	client, mux, _, teardown := setup()
   257  	defer teardown()
   258  
   259  	input := &IssueRequest{
   260  		Title:    String("t"),
   261  		Body:     String("b"),
   262  		Assignee: String("a"),
   263  		Labels:   &[]string{"l1", "l2"},
   264  	}
   265  
   266  	mux.HandleFunc("/repos/o/r/issues", func(w http.ResponseWriter, r *http.Request) {
   267  		v := new(IssueRequest)
   268  		json.NewDecoder(r.Body).Decode(v)
   269  
   270  		testMethod(t, r, "POST")
   271  		if !cmp.Equal(v, input) {
   272  			t.Errorf("Request body = %+v, want %+v", v, input)
   273  		}
   274  
   275  		fmt.Fprint(w, `{"number":1}`)
   276  	})
   277  
   278  	ctx := context.Background()
   279  	issue, _, err := client.Issues.Create(ctx, "o", "r", input)
   280  	if err != nil {
   281  		t.Errorf("Issues.Create returned error: %v", err)
   282  	}
   283  
   284  	want := &Issue{Number: Int(1)}
   285  	if !cmp.Equal(issue, want) {
   286  		t.Errorf("Issues.Create returned %+v, want %+v", issue, want)
   287  	}
   288  
   289  	const methodName = "Create"
   290  	testBadOptions(t, methodName, func() (err error) {
   291  		_, _, err = client.Issues.Create(ctx, "\n", "\n", input)
   292  		return err
   293  	})
   294  
   295  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   296  		got, resp, err := client.Issues.Create(ctx, "o", "r", input)
   297  		if got != nil {
   298  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   299  		}
   300  		return resp, err
   301  	})
   302  }
   303  
   304  func TestIssuesService_Create_invalidOwner(t *testing.T) {
   305  	client, _, _, teardown := setup()
   306  	defer teardown()
   307  
   308  	ctx := context.Background()
   309  	_, _, err := client.Issues.Create(ctx, "%", "r", nil)
   310  	testURLParseError(t, err)
   311  }
   312  
   313  func TestIssuesService_Edit(t *testing.T) {
   314  	client, mux, _, teardown := setup()
   315  	defer teardown()
   316  
   317  	input := &IssueRequest{Title: String("t")}
   318  
   319  	mux.HandleFunc("/repos/o/r/issues/1", func(w http.ResponseWriter, r *http.Request) {
   320  		v := new(IssueRequest)
   321  		json.NewDecoder(r.Body).Decode(v)
   322  
   323  		testMethod(t, r, "PATCH")
   324  		if !cmp.Equal(v, input) {
   325  			t.Errorf("Request body = %+v, want %+v", v, input)
   326  		}
   327  
   328  		fmt.Fprint(w, `{"number":1}`)
   329  	})
   330  
   331  	ctx := context.Background()
   332  	issue, _, err := client.Issues.Edit(ctx, "o", "r", 1, input)
   333  	if err != nil {
   334  		t.Errorf("Issues.Edit returned error: %v", err)
   335  	}
   336  
   337  	want := &Issue{Number: Int(1)}
   338  	if !cmp.Equal(issue, want) {
   339  		t.Errorf("Issues.Edit returned %+v, want %+v", issue, want)
   340  	}
   341  
   342  	const methodName = "Edit"
   343  	testBadOptions(t, methodName, func() (err error) {
   344  		_, _, err = client.Issues.Edit(ctx, "\n", "\n", -1, input)
   345  		return err
   346  	})
   347  
   348  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   349  		got, resp, err := client.Issues.Edit(ctx, "o", "r", 1, input)
   350  		if got != nil {
   351  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   352  		}
   353  		return resp, err
   354  	})
   355  }
   356  
   357  func TestIssuesService_RemoveMilestone(t *testing.T) {
   358  	client, mux, _, teardown := setup()
   359  	defer teardown()
   360  	mux.HandleFunc("/repos/o/r/issues/1", func(w http.ResponseWriter, r *http.Request) {
   361  		testMethod(t, r, "PATCH")
   362  		fmt.Fprint(w, `{"number":1}`)
   363  	})
   364  
   365  	ctx := context.Background()
   366  	issue, _, err := client.Issues.RemoveMilestone(ctx, "o", "r", 1)
   367  	if err != nil {
   368  		t.Errorf("Issues.RemoveMilestone returned error: %v", err)
   369  	}
   370  
   371  	want := &Issue{Number: Int(1)}
   372  	if !cmp.Equal(issue, want) {
   373  		t.Errorf("Issues.RemoveMilestone returned %+v, want %+v", issue, want)
   374  	}
   375  
   376  	const methodName = "RemoveMilestone"
   377  	testBadOptions(t, methodName, func() (err error) {
   378  		_, _, err = client.Issues.RemoveMilestone(ctx, "\n", "\n", -1)
   379  		return err
   380  	})
   381  
   382  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   383  		got, resp, err := client.Issues.RemoveMilestone(ctx, "o", "r", 1)
   384  		if got != nil {
   385  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   386  		}
   387  		return resp, err
   388  	})
   389  }
   390  
   391  func TestIssuesService_Edit_invalidOwner(t *testing.T) {
   392  	client, _, _, teardown := setup()
   393  	defer teardown()
   394  
   395  	ctx := context.Background()
   396  	_, _, err := client.Issues.Edit(ctx, "%", "r", 1, nil)
   397  	testURLParseError(t, err)
   398  }
   399  
   400  func TestIssuesService_Lock(t *testing.T) {
   401  	client, mux, _, teardown := setup()
   402  	defer teardown()
   403  
   404  	mux.HandleFunc("/repos/o/r/issues/1/lock", func(w http.ResponseWriter, r *http.Request) {
   405  		testMethod(t, r, "PUT")
   406  
   407  		w.WriteHeader(http.StatusNoContent)
   408  	})
   409  
   410  	ctx := context.Background()
   411  	if _, err := client.Issues.Lock(ctx, "o", "r", 1, nil); err != nil {
   412  		t.Errorf("Issues.Lock returned error: %v", err)
   413  	}
   414  
   415  	const methodName = "Lock"
   416  	testBadOptions(t, methodName, func() (err error) {
   417  		_, err = client.Issues.Lock(ctx, "\n", "\n", -1, nil)
   418  		return err
   419  	})
   420  
   421  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   422  		return client.Issues.Lock(ctx, "o", "r", 1, nil)
   423  	})
   424  }
   425  
   426  func TestIssuesService_LockWithReason(t *testing.T) {
   427  	client, mux, _, teardown := setup()
   428  	defer teardown()
   429  
   430  	mux.HandleFunc("/repos/o/r/issues/1/lock", func(w http.ResponseWriter, r *http.Request) {
   431  		testMethod(t, r, "PUT")
   432  		w.WriteHeader(http.StatusNoContent)
   433  	})
   434  
   435  	opt := &LockIssueOptions{LockReason: "off-topic"}
   436  
   437  	ctx := context.Background()
   438  	if _, err := client.Issues.Lock(ctx, "o", "r", 1, opt); err != nil {
   439  		t.Errorf("Issues.Lock returned error: %v", err)
   440  	}
   441  }
   442  
   443  func TestIssuesService_Unlock(t *testing.T) {
   444  	client, mux, _, teardown := setup()
   445  	defer teardown()
   446  
   447  	mux.HandleFunc("/repos/o/r/issues/1/lock", func(w http.ResponseWriter, r *http.Request) {
   448  		testMethod(t, r, "DELETE")
   449  
   450  		w.WriteHeader(http.StatusNoContent)
   451  	})
   452  
   453  	ctx := context.Background()
   454  	if _, err := client.Issues.Unlock(ctx, "o", "r", 1); err != nil {
   455  		t.Errorf("Issues.Unlock returned error: %v", err)
   456  	}
   457  
   458  	const methodName = "Unlock"
   459  	testBadOptions(t, methodName, func() (err error) {
   460  		_, err = client.Issues.Unlock(ctx, "\n", "\n", 1)
   461  		return err
   462  	})
   463  
   464  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   465  		return client.Issues.Unlock(ctx, "o", "r", 1)
   466  	})
   467  }
   468  
   469  func TestIsPullRequest(t *testing.T) {
   470  	i := new(Issue)
   471  	if i.IsPullRequest() == true {
   472  		t.Errorf("expected i.IsPullRequest (%v) to return false, got true", i)
   473  	}
   474  	i.PullRequestLinks = &PullRequestLinks{URL: String("http://example.com")}
   475  	if i.IsPullRequest() == false {
   476  		t.Errorf("expected i.IsPullRequest (%v) to return true, got false", i)
   477  	}
   478  }
   479  
   480  func TestLockIssueOptions_Marshal(t *testing.T) {
   481  	testJSONMarshal(t, &LockIssueOptions{}, "{}")
   482  
   483  	u := &LockIssueOptions{
   484  		LockReason: "lr",
   485  	}
   486  
   487  	want := `{
   488  		"lock_reason": "lr"
   489  		}`
   490  
   491  	testJSONMarshal(t, u, want)
   492  }
   493  
   494  func TestPullRequestLinks_Marshal(t *testing.T) {
   495  	testJSONMarshal(t, &PullRequestLinks{}, "{}")
   496  
   497  	u := &PullRequestLinks{
   498  		URL:      String("url"),
   499  		HTMLURL:  String("hurl"),
   500  		DiffURL:  String("durl"),
   501  		PatchURL: String("purl"),
   502  	}
   503  
   504  	want := `{
   505  		"url": "url",
   506  		"html_url": "hurl",
   507  		"diff_url": "durl",
   508  		"patch_url": "purl"
   509  		}`
   510  
   511  	testJSONMarshal(t, u, want)
   512  }
   513  
   514  func TestIssueRequest_Marshal(t *testing.T) {
   515  	testJSONMarshal(t, &IssueRequest{}, "{}")
   516  
   517  	u := &IssueRequest{
   518  		Title:     String("url"),
   519  		Body:      String("url"),
   520  		Labels:    &[]string{"l"},
   521  		Assignee:  String("url"),
   522  		State:     String("url"),
   523  		Milestone: Int(1),
   524  		Assignees: &[]string{"a"},
   525  	}
   526  
   527  	want := `{
   528  		"title": "url",
   529  		"body": "url",
   530  		"labels": [
   531  			"l"
   532  		],
   533  		"assignee": "url",
   534  		"state": "url",
   535  		"milestone": 1,
   536  		"assignees": [
   537  			"a"
   538  		]
   539  	}`
   540  
   541  	testJSONMarshal(t, u, want)
   542  }
   543  
   544  func TestIssue_Marshal(t *testing.T) {
   545  	testJSONMarshal(t, &Issue{}, "{}")
   546  
   547  	u := &Issue{
   548  		ID:                Int64(1),
   549  		Number:            Int(1),
   550  		State:             String("s"),
   551  		Locked:            Bool(false),
   552  		Title:             String("title"),
   553  		Body:              String("body"),
   554  		AuthorAssociation: String("aa"),
   555  		User:              &User{ID: Int64(1)},
   556  		Labels:            []*Label{{ID: Int64(1)}},
   557  		Assignee:          &User{ID: Int64(1)},
   558  		Comments:          Int(1),
   559  		ClosedAt:          &Timestamp{referenceTime},
   560  		CreatedAt:         &Timestamp{referenceTime},
   561  		UpdatedAt:         &Timestamp{referenceTime},
   562  		ClosedBy:          &User{ID: Int64(1)},
   563  		URL:               String("url"),
   564  		HTMLURL:           String("hurl"),
   565  		CommentsURL:       String("curl"),
   566  		EventsURL:         String("eurl"),
   567  		LabelsURL:         String("lurl"),
   568  		RepositoryURL:     String("rurl"),
   569  		Milestone:         &Milestone{ID: Int64(1)},
   570  		PullRequestLinks:  &PullRequestLinks{URL: String("url")},
   571  		Repository:        &Repository{ID: Int64(1)},
   572  		Reactions:         &Reactions{TotalCount: Int(1)},
   573  		Assignees:         []*User{{ID: Int64(1)}},
   574  		NodeID:            String("nid"),
   575  		TextMatches:       []*TextMatch{{ObjectURL: String("ourl")}},
   576  		ActiveLockReason:  String("alr"),
   577  	}
   578  
   579  	want := `{
   580  		"id": 1,
   581  		"number": 1,
   582  		"state": "s",
   583  		"locked": false,
   584  		"title": "title",
   585  		"body": "body",
   586  		"author_association": "aa",
   587  		"user": {
   588  			"id": 1
   589  		},
   590  		"labels": [
   591  			{
   592  				"id": 1
   593  			}
   594  		],
   595  		"assignee": {
   596  			"id": 1
   597  		},
   598  		"comments": 1,
   599  		"closed_at": ` + referenceTimeStr + `,
   600  		"created_at": ` + referenceTimeStr + `,
   601  		"updated_at": ` + referenceTimeStr + `,
   602  		"closed_by": {
   603  			"id": 1
   604  		},
   605  		"url": "url",
   606  		"html_url": "hurl",
   607  		"comments_url": "curl",
   608  		"events_url": "eurl",
   609  		"labels_url": "lurl",
   610  		"repository_url": "rurl",
   611  		"milestone": {
   612  			"id": 1
   613  		},
   614  		"pull_request": {
   615  			"url": "url"
   616  		},
   617  		"repository": {
   618  			"id": 1
   619  		},
   620  		"reactions": {
   621  			"total_count": 1
   622  		},
   623  		"assignees": [
   624  			{
   625  				"id": 1
   626  			}
   627  		],
   628  		"node_id": "nid",
   629  		"text_matches": [
   630  			{
   631  				"object_url": "ourl"
   632  			}
   633  		],
   634  		"active_lock_reason": "alr"
   635  	}`
   636  
   637  	testJSONMarshal(t, u, want)
   638  }
   639  

View as plain text