github.com/google/go-github/v60@v60.0.0/github/pulls_test.go (about)

     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  	"io"
    13  	"net/http"
    14  	"strings"
    15  	"testing"
    16  
    17  	"github.com/google/go-cmp/cmp"
    18  )
    19  
    20  func TestPullRequestsService_List(t *testing.T) {
    21  	client, mux, _, teardown := setup()
    22  	defer teardown()
    23  
    24  	mux.HandleFunc("/repos/o/r/pulls", func(w http.ResponseWriter, r *http.Request) {
    25  		testMethod(t, r, "GET")
    26  		testFormValues(t, r, values{
    27  			"state":     "closed",
    28  			"head":      "h",
    29  			"base":      "b",
    30  			"sort":      "created",
    31  			"direction": "desc",
    32  			"page":      "2",
    33  		})
    34  		fmt.Fprint(w, `[{"number":1}]`)
    35  	})
    36  
    37  	opts := &PullRequestListOptions{"closed", "h", "b", "created", "desc", ListOptions{Page: 2}}
    38  	ctx := context.Background()
    39  	pulls, _, err := client.PullRequests.List(ctx, "o", "r", opts)
    40  	if err != nil {
    41  		t.Errorf("PullRequests.List returned error: %v", err)
    42  	}
    43  
    44  	want := []*PullRequest{{Number: Int(1)}}
    45  	if !cmp.Equal(pulls, want) {
    46  		t.Errorf("PullRequests.List returned %+v, want %+v", pulls, want)
    47  	}
    48  
    49  	const methodName = "List"
    50  	testBadOptions(t, methodName, func() (err error) {
    51  		_, _, err = client.PullRequests.List(ctx, "\n", "\n", opts)
    52  		return err
    53  	})
    54  
    55  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
    56  		got, resp, err := client.PullRequests.List(ctx, "o", "r", opts)
    57  		if got != nil {
    58  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
    59  		}
    60  		return resp, err
    61  	})
    62  }
    63  
    64  func TestPullRequestsService_ListPullRequestsWithCommit(t *testing.T) {
    65  	client, mux, _, teardown := setup()
    66  	defer teardown()
    67  
    68  	mux.HandleFunc("/repos/o/r/commits/sha/pulls", func(w http.ResponseWriter, r *http.Request) {
    69  		testMethod(t, r, "GET")
    70  		testHeader(t, r, "Accept", mediaTypeListPullsOrBranchesForCommitPreview)
    71  		testFormValues(t, r, values{
    72  			"page": "2",
    73  		})
    74  		fmt.Fprint(w, `[{"number":1}]`)
    75  	})
    76  
    77  	opts := &ListOptions{Page: 2}
    78  	ctx := context.Background()
    79  	pulls, _, err := client.PullRequests.ListPullRequestsWithCommit(ctx, "o", "r", "sha", opts)
    80  	if err != nil {
    81  		t.Errorf("PullRequests.ListPullRequestsWithCommit returned error: %v", err)
    82  	}
    83  
    84  	want := []*PullRequest{{Number: Int(1)}}
    85  	if !cmp.Equal(pulls, want) {
    86  		t.Errorf("PullRequests.ListPullRequestsWithCommit returned %+v, want %+v", pulls, want)
    87  	}
    88  
    89  	const methodName = "ListPullRequestsWithCommit"
    90  	testBadOptions(t, methodName, func() (err error) {
    91  		_, _, err = client.PullRequests.ListPullRequestsWithCommit(ctx, "\n", "\n", "\n", opts)
    92  		return err
    93  	})
    94  
    95  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
    96  		got, resp, err := client.PullRequests.ListPullRequestsWithCommit(ctx, "o", "r", "sha", opts)
    97  		if got != nil {
    98  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
    99  		}
   100  		return resp, err
   101  	})
   102  }
   103  
   104  func TestPullRequestsService_List_invalidOwner(t *testing.T) {
   105  	client, _, _, teardown := setup()
   106  	defer teardown()
   107  
   108  	ctx := context.Background()
   109  	_, _, err := client.PullRequests.List(ctx, "%", "r", nil)
   110  	testURLParseError(t, err)
   111  }
   112  
   113  func TestPullRequestsService_Get(t *testing.T) {
   114  	client, mux, _, teardown := setup()
   115  	defer teardown()
   116  
   117  	mux.HandleFunc("/repos/o/r/pulls/1", func(w http.ResponseWriter, r *http.Request) {
   118  		testMethod(t, r, "GET")
   119  		fmt.Fprint(w, `{"number":1}`)
   120  	})
   121  
   122  	ctx := context.Background()
   123  	pull, _, err := client.PullRequests.Get(ctx, "o", "r", 1)
   124  	if err != nil {
   125  		t.Errorf("PullRequests.Get returned error: %v", err)
   126  	}
   127  
   128  	want := &PullRequest{Number: Int(1)}
   129  	if !cmp.Equal(pull, want) {
   130  		t.Errorf("PullRequests.Get returned %+v, want %+v", pull, want)
   131  	}
   132  
   133  	const methodName = "Get"
   134  	testBadOptions(t, methodName, func() (err error) {
   135  		_, _, err = client.PullRequests.Get(ctx, "\n", "\n", -1)
   136  		return err
   137  	})
   138  
   139  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   140  		got, resp, err := client.PullRequests.Get(ctx, "o", "r", 1)
   141  		if got != nil {
   142  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   143  		}
   144  		return resp, err
   145  	})
   146  }
   147  
   148  func TestPullRequestsService_GetRaw_diff(t *testing.T) {
   149  	client, mux, _, teardown := setup()
   150  	defer teardown()
   151  
   152  	const rawStr = "@@diff content"
   153  
   154  	mux.HandleFunc("/repos/o/r/pulls/1", func(w http.ResponseWriter, r *http.Request) {
   155  		testMethod(t, r, "GET")
   156  		testHeader(t, r, "Accept", mediaTypeV3Diff)
   157  		fmt.Fprint(w, rawStr)
   158  	})
   159  
   160  	ctx := context.Background()
   161  	got, _, err := client.PullRequests.GetRaw(ctx, "o", "r", 1, RawOptions{Diff})
   162  	if err != nil {
   163  		t.Fatalf("PullRequests.GetRaw returned error: %v", err)
   164  	}
   165  	want := rawStr
   166  	if got != want {
   167  		t.Errorf("PullRequests.GetRaw returned %s want %s", got, want)
   168  	}
   169  
   170  	const methodName = "GetRaw"
   171  	testBadOptions(t, methodName, func() (err error) {
   172  		_, _, err = client.PullRequests.GetRaw(ctx, "\n", "\n", -1, RawOptions{Diff})
   173  		return err
   174  	})
   175  
   176  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   177  		got, resp, err := client.PullRequests.GetRaw(ctx, "o", "r", 1, RawOptions{Diff})
   178  		if got != "" {
   179  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   180  		}
   181  		return resp, err
   182  	})
   183  }
   184  
   185  func TestPullRequestsService_GetRaw_patch(t *testing.T) {
   186  	client, mux, _, teardown := setup()
   187  	defer teardown()
   188  
   189  	const rawStr = "@@patch content"
   190  
   191  	mux.HandleFunc("/repos/o/r/pulls/1", func(w http.ResponseWriter, r *http.Request) {
   192  		testMethod(t, r, "GET")
   193  		testHeader(t, r, "Accept", mediaTypeV3Patch)
   194  		fmt.Fprint(w, rawStr)
   195  	})
   196  
   197  	ctx := context.Background()
   198  	got, _, err := client.PullRequests.GetRaw(ctx, "o", "r", 1, RawOptions{Patch})
   199  	if err != nil {
   200  		t.Fatalf("PullRequests.GetRaw returned error: %v", err)
   201  	}
   202  	want := rawStr
   203  	if got != want {
   204  		t.Errorf("PullRequests.GetRaw returned %s want %s", got, want)
   205  	}
   206  }
   207  
   208  func TestPullRequestsService_GetRaw_invalid(t *testing.T) {
   209  	client, _, _, teardown := setup()
   210  	defer teardown()
   211  
   212  	ctx := context.Background()
   213  	_, _, err := client.PullRequests.GetRaw(ctx, "o", "r", 1, RawOptions{100})
   214  	if err == nil {
   215  		t.Fatal("PullRequests.GetRaw should return error")
   216  	}
   217  	if !strings.Contains(err.Error(), "unsupported raw type") {
   218  		t.Error("PullRequests.GetRaw should return unsupported raw type error")
   219  	}
   220  }
   221  
   222  func TestPullRequestsService_Get_links(t *testing.T) {
   223  	client, mux, _, teardown := setup()
   224  	defer teardown()
   225  
   226  	mux.HandleFunc("/repos/o/r/pulls/1", func(w http.ResponseWriter, r *http.Request) {
   227  		testMethod(t, r, "GET")
   228  		fmt.Fprint(w, `{
   229  			"number":1,
   230  			"_links":{
   231  				"self":{"href":"https://api.github.com/repos/octocat/Hello-World/pulls/1347"},
   232  				"html":{"href":"https://github.com/octocat/Hello-World/pull/1347"},
   233  				"issue":{"href":"https://api.github.com/repos/octocat/Hello-World/issues/1347"},
   234  				"comments":{"href":"https://api.github.com/repos/octocat/Hello-World/issues/1347/comments"},
   235  				"review_comments":{"href":"https://api.github.com/repos/octocat/Hello-World/pulls/1347/comments"},
   236  				"review_comment":{"href":"https://api.github.com/repos/octocat/Hello-World/pulls/comments{/number}"},
   237  				"commits":{"href":"https://api.github.com/repos/octocat/Hello-World/pulls/1347/commits"},
   238  				"statuses":{"href":"https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e"}
   239  				}
   240  			}`)
   241  	})
   242  
   243  	ctx := context.Background()
   244  	pull, _, err := client.PullRequests.Get(ctx, "o", "r", 1)
   245  	if err != nil {
   246  		t.Errorf("PullRequests.Get returned error: %v", err)
   247  	}
   248  
   249  	want := &PullRequest{
   250  		Number: Int(1),
   251  		Links: &PRLinks{
   252  			Self: &PRLink{
   253  				HRef: String("https://api.github.com/repos/octocat/Hello-World/pulls/1347"),
   254  			}, HTML: &PRLink{
   255  				HRef: String("https://github.com/octocat/Hello-World/pull/1347"),
   256  			}, Issue: &PRLink{
   257  				HRef: String("https://api.github.com/repos/octocat/Hello-World/issues/1347"),
   258  			}, Comments: &PRLink{
   259  				HRef: String("https://api.github.com/repos/octocat/Hello-World/issues/1347/comments"),
   260  			}, ReviewComments: &PRLink{
   261  				HRef: String("https://api.github.com/repos/octocat/Hello-World/pulls/1347/comments"),
   262  			}, ReviewComment: &PRLink{
   263  				HRef: String("https://api.github.com/repos/octocat/Hello-World/pulls/comments{/number}"),
   264  			}, Commits: &PRLink{
   265  				HRef: String("https://api.github.com/repos/octocat/Hello-World/pulls/1347/commits"),
   266  			}, Statuses: &PRLink{
   267  				HRef: String("https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e"),
   268  			},
   269  		},
   270  	}
   271  	if !cmp.Equal(pull, want) {
   272  		t.Errorf("PullRequests.Get returned %+v, want %+v", pull, want)
   273  	}
   274  }
   275  
   276  func TestPullRequestsService_Get_headAndBase(t *testing.T) {
   277  	client, mux, _, teardown := setup()
   278  	defer teardown()
   279  
   280  	mux.HandleFunc("/repos/o/r/pulls/1", func(w http.ResponseWriter, r *http.Request) {
   281  		testMethod(t, r, "GET")
   282  		fmt.Fprint(w, `{"number":1,"head":{"ref":"r2","repo":{"id":2}},"base":{"ref":"r1","repo":{"id":1}}}`)
   283  	})
   284  
   285  	ctx := context.Background()
   286  	pull, _, err := client.PullRequests.Get(ctx, "o", "r", 1)
   287  	if err != nil {
   288  		t.Errorf("PullRequests.Get returned error: %v", err)
   289  	}
   290  
   291  	want := &PullRequest{
   292  		Number: Int(1),
   293  		Head: &PullRequestBranch{
   294  			Ref:  String("r2"),
   295  			Repo: &Repository{ID: Int64(2)},
   296  		},
   297  		Base: &PullRequestBranch{
   298  			Ref:  String("r1"),
   299  			Repo: &Repository{ID: Int64(1)},
   300  		},
   301  	}
   302  	if !cmp.Equal(pull, want) {
   303  		t.Errorf("PullRequests.Get returned %+v, want %+v", pull, want)
   304  	}
   305  }
   306  
   307  func TestPullRequestsService_Get_urlFields(t *testing.T) {
   308  	client, mux, _, teardown := setup()
   309  	defer teardown()
   310  
   311  	mux.HandleFunc("/repos/o/r/pulls/1", func(w http.ResponseWriter, r *http.Request) {
   312  		testMethod(t, r, "GET")
   313  		fmt.Fprint(w, `{"number":1,
   314  			"url": "https://api.github.com/repos/octocat/Hello-World/pulls/1347",
   315  			"html_url": "https://github.com/octocat/Hello-World/pull/1347",
   316  			"issue_url": "https://api.github.com/repos/octocat/Hello-World/issues/1347",
   317  			"statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e",
   318  			"diff_url": "https://github.com/octocat/Hello-World/pull/1347.diff",
   319  			"patch_url": "https://github.com/octocat/Hello-World/pull/1347.patch",
   320  			"review_comments_url": "https://api.github.com/repos/octocat/Hello-World/pulls/1347/comments",
   321  			"review_comment_url": "https://api.github.com/repos/octocat/Hello-World/pulls/comments{/number}"}`)
   322  	})
   323  
   324  	ctx := context.Background()
   325  	pull, _, err := client.PullRequests.Get(ctx, "o", "r", 1)
   326  	if err != nil {
   327  		t.Errorf("PullRequests.Get returned error: %v", err)
   328  	}
   329  
   330  	want := &PullRequest{
   331  		Number:            Int(1),
   332  		URL:               String("https://api.github.com/repos/octocat/Hello-World/pulls/1347"),
   333  		HTMLURL:           String("https://github.com/octocat/Hello-World/pull/1347"),
   334  		IssueURL:          String("https://api.github.com/repos/octocat/Hello-World/issues/1347"),
   335  		StatusesURL:       String("https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e"),
   336  		DiffURL:           String("https://github.com/octocat/Hello-World/pull/1347.diff"),
   337  		PatchURL:          String("https://github.com/octocat/Hello-World/pull/1347.patch"),
   338  		ReviewCommentsURL: String("https://api.github.com/repos/octocat/Hello-World/pulls/1347/comments"),
   339  		ReviewCommentURL:  String("https://api.github.com/repos/octocat/Hello-World/pulls/comments{/number}"),
   340  	}
   341  
   342  	if !cmp.Equal(pull, want) {
   343  		t.Errorf("PullRequests.Get returned %+v, want %+v", pull, want)
   344  	}
   345  }
   346  
   347  func TestPullRequestsService_Get_invalidOwner(t *testing.T) {
   348  	client, _, _, teardown := setup()
   349  	defer teardown()
   350  
   351  	ctx := context.Background()
   352  	_, _, err := client.PullRequests.Get(ctx, "%", "r", 1)
   353  	testURLParseError(t, err)
   354  }
   355  
   356  func TestPullRequestsService_Create(t *testing.T) {
   357  	client, mux, _, teardown := setup()
   358  	defer teardown()
   359  
   360  	input := &NewPullRequest{Title: String("t")}
   361  
   362  	mux.HandleFunc("/repos/o/r/pulls", func(w http.ResponseWriter, r *http.Request) {
   363  		v := new(NewPullRequest)
   364  		assertNilError(t, json.NewDecoder(r.Body).Decode(v))
   365  
   366  		testMethod(t, r, "POST")
   367  		if !cmp.Equal(v, input) {
   368  			t.Errorf("Request body = %+v, want %+v", v, input)
   369  		}
   370  
   371  		fmt.Fprint(w, `{"number":1}`)
   372  	})
   373  
   374  	ctx := context.Background()
   375  	pull, _, err := client.PullRequests.Create(ctx, "o", "r", input)
   376  	if err != nil {
   377  		t.Errorf("PullRequests.Create returned error: %v", err)
   378  	}
   379  
   380  	want := &PullRequest{Number: Int(1)}
   381  	if !cmp.Equal(pull, want) {
   382  		t.Errorf("PullRequests.Create returned %+v, want %+v", pull, want)
   383  	}
   384  
   385  	const methodName = "Create"
   386  	testBadOptions(t, methodName, func() (err error) {
   387  		_, _, err = client.PullRequests.Create(ctx, "\n", "\n", input)
   388  		return err
   389  	})
   390  
   391  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   392  		got, resp, err := client.PullRequests.Create(ctx, "o", "r", input)
   393  		if got != nil {
   394  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   395  		}
   396  		return resp, err
   397  	})
   398  }
   399  
   400  func TestPullRequestsService_Create_invalidOwner(t *testing.T) {
   401  	client, _, _, teardown := setup()
   402  	defer teardown()
   403  
   404  	ctx := context.Background()
   405  	_, _, err := client.PullRequests.Create(ctx, "%", "r", nil)
   406  	testURLParseError(t, err)
   407  }
   408  
   409  func TestPullRequestsService_UpdateBranch(t *testing.T) {
   410  	client, mux, _, teardown := setup()
   411  	defer teardown()
   412  
   413  	mux.HandleFunc("/repos/o/r/pulls/1/update-branch", func(w http.ResponseWriter, r *http.Request) {
   414  		testMethod(t, r, "PUT")
   415  		testHeader(t, r, "Accept", mediaTypeUpdatePullRequestBranchPreview)
   416  		fmt.Fprint(w, `
   417  			{
   418  			  "message": "Updating pull request branch.",
   419  			  "url": "https://github.com/repos/o/r/pulls/1"
   420  			}`)
   421  	})
   422  
   423  	opts := &PullRequestBranchUpdateOptions{
   424  		ExpectedHeadSHA: String("s"),
   425  	}
   426  
   427  	ctx := context.Background()
   428  	pull, _, err := client.PullRequests.UpdateBranch(ctx, "o", "r", 1, opts)
   429  	if err != nil {
   430  		t.Errorf("PullRequests.UpdateBranch returned error: %v", err)
   431  	}
   432  
   433  	want := &PullRequestBranchUpdateResponse{
   434  		Message: String("Updating pull request branch."),
   435  		URL:     String("https://github.com/repos/o/r/pulls/1"),
   436  	}
   437  
   438  	if !cmp.Equal(pull, want) {
   439  		t.Errorf("PullRequests.UpdateBranch returned %+v, want %+v", pull, want)
   440  	}
   441  
   442  	const methodName = "UpdateBranch"
   443  	testBadOptions(t, methodName, func() (err error) {
   444  		_, _, err = client.PullRequests.UpdateBranch(ctx, "\n", "\n", -1, opts)
   445  		return err
   446  	})
   447  
   448  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   449  		got, resp, err := client.PullRequests.UpdateBranch(ctx, "o", "r", 1, opts)
   450  		if got != nil {
   451  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   452  		}
   453  		return resp, err
   454  	})
   455  }
   456  
   457  func TestPullRequestsService_Edit(t *testing.T) {
   458  	client, mux, _, teardown := setup()
   459  	defer teardown()
   460  
   461  	tests := []struct {
   462  		input        *PullRequest
   463  		sendResponse string
   464  
   465  		wantUpdate string
   466  		want       *PullRequest
   467  	}{
   468  		{
   469  			input:        &PullRequest{Title: String("t")},
   470  			sendResponse: `{"number":1}`,
   471  			wantUpdate:   `{"title":"t"}`,
   472  			want:         &PullRequest{Number: Int(1)},
   473  		},
   474  		{
   475  			// base update
   476  			input:        &PullRequest{Base: &PullRequestBranch{Ref: String("master")}},
   477  			sendResponse: `{"number":1,"base":{"ref":"master"}}`,
   478  			wantUpdate:   `{"base":"master"}`,
   479  			want: &PullRequest{
   480  				Number: Int(1),
   481  				Base:   &PullRequestBranch{Ref: String("master")},
   482  			},
   483  		},
   484  	}
   485  
   486  	for i, tt := range tests {
   487  		madeRequest := false
   488  		mux.HandleFunc(fmt.Sprintf("/repos/o/r/pulls/%v", i), func(w http.ResponseWriter, r *http.Request) {
   489  			testMethod(t, r, "PATCH")
   490  			testBody(t, r, tt.wantUpdate+"\n")
   491  			_, err := io.WriteString(w, tt.sendResponse)
   492  			assertNilError(t, err)
   493  			madeRequest = true
   494  		})
   495  
   496  		ctx := context.Background()
   497  		pull, _, err := client.PullRequests.Edit(ctx, "o", "r", i, tt.input)
   498  		if err != nil {
   499  			t.Errorf("%d: PullRequests.Edit returned error: %v", i, err)
   500  		}
   501  
   502  		if !cmp.Equal(pull, tt.want) {
   503  			t.Errorf("%d: PullRequests.Edit returned %+v, want %+v", i, pull, tt.want)
   504  		}
   505  
   506  		if !madeRequest {
   507  			t.Errorf("%d: PullRequest.Edit did not make the expected request", i)
   508  		}
   509  
   510  		const methodName = "Edit"
   511  		testBadOptions(t, methodName, func() (err error) {
   512  			_, _, err = client.PullRequests.Edit(ctx, "\n", "\n", -i, tt.input)
   513  			return err
   514  		})
   515  	}
   516  }
   517  
   518  func TestPullRequestsService_Edit_invalidOwner(t *testing.T) {
   519  	client, _, _, teardown := setup()
   520  	defer teardown()
   521  
   522  	ctx := context.Background()
   523  	_, _, err := client.PullRequests.Edit(ctx, "%", "r", 1, &PullRequest{})
   524  	testURLParseError(t, err)
   525  }
   526  
   527  func TestPullRequestsService_ListCommits(t *testing.T) {
   528  	client, mux, _, teardown := setup()
   529  	defer teardown()
   530  
   531  	mux.HandleFunc("/repos/o/r/pulls/1/commits", func(w http.ResponseWriter, r *http.Request) {
   532  		testMethod(t, r, "GET")
   533  		testFormValues(t, r, values{"page": "2"})
   534  		fmt.Fprint(w, `
   535  			[
   536  			  {
   537  			    "sha": "3",
   538  			    "parents": [
   539  			      {
   540  			        "sha": "2"
   541  			      }
   542  			    ]
   543  			  },
   544  			  {
   545  			    "sha": "2",
   546  			    "parents": [
   547  			      {
   548  			        "sha": "1"
   549  			      }
   550  			    ]
   551  			  }
   552  			]`)
   553  	})
   554  
   555  	opts := &ListOptions{Page: 2}
   556  	ctx := context.Background()
   557  	commits, _, err := client.PullRequests.ListCommits(ctx, "o", "r", 1, opts)
   558  	if err != nil {
   559  		t.Errorf("PullRequests.ListCommits returned error: %v", err)
   560  	}
   561  
   562  	want := []*RepositoryCommit{
   563  		{
   564  			SHA: String("3"),
   565  			Parents: []*Commit{
   566  				{
   567  					SHA: String("2"),
   568  				},
   569  			},
   570  		},
   571  		{
   572  			SHA: String("2"),
   573  			Parents: []*Commit{
   574  				{
   575  					SHA: String("1"),
   576  				},
   577  			},
   578  		},
   579  	}
   580  	if !cmp.Equal(commits, want) {
   581  		t.Errorf("PullRequests.ListCommits returned %+v, want %+v", commits, want)
   582  	}
   583  
   584  	const methodName = "ListCommits"
   585  	testBadOptions(t, methodName, func() (err error) {
   586  		_, _, err = client.PullRequests.ListCommits(ctx, "\n", "\n", -1, opts)
   587  		return err
   588  	})
   589  
   590  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   591  		got, resp, err := client.PullRequests.ListCommits(ctx, "o", "r", 1, opts)
   592  		if got != nil {
   593  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   594  		}
   595  		return resp, err
   596  	})
   597  }
   598  
   599  func TestPullRequestsService_ListFiles(t *testing.T) {
   600  	client, mux, _, teardown := setup()
   601  	defer teardown()
   602  
   603  	mux.HandleFunc("/repos/o/r/pulls/1/files", func(w http.ResponseWriter, r *http.Request) {
   604  		testMethod(t, r, "GET")
   605  		testFormValues(t, r, values{"page": "2"})
   606  		fmt.Fprint(w, `
   607  			[
   608  			  {
   609  			    "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
   610  			    "filename": "file1.txt",
   611  			    "status": "added",
   612  			    "additions": 103,
   613  			    "deletions": 21,
   614  			    "changes": 124,
   615  			    "patch": "@@ -132,7 +132,7 @@ module Test @@ -1000,7 +1000,7 @@ module Test"
   616  			  },
   617  			  {
   618  			    "sha": "f61aebed695e2e4193db5e6dcb09b5b57875f334",
   619  			    "filename": "file2.txt",
   620  			    "status": "modified",
   621  			    "additions": 5,
   622  			    "deletions": 3,
   623  			    "changes": 103,
   624  			    "patch": "@@ -132,7 +132,7 @@ module Test @@ -1000,7 +1000,7 @@ module Test"
   625  			  }
   626  			]`)
   627  	})
   628  
   629  	opts := &ListOptions{Page: 2}
   630  	ctx := context.Background()
   631  	commitFiles, _, err := client.PullRequests.ListFiles(ctx, "o", "r", 1, opts)
   632  	if err != nil {
   633  		t.Errorf("PullRequests.ListFiles returned error: %v", err)
   634  	}
   635  
   636  	want := []*CommitFile{
   637  		{
   638  			SHA:       String("6dcb09b5b57875f334f61aebed695e2e4193db5e"),
   639  			Filename:  String("file1.txt"),
   640  			Additions: Int(103),
   641  			Deletions: Int(21),
   642  			Changes:   Int(124),
   643  			Status:    String("added"),
   644  			Patch:     String("@@ -132,7 +132,7 @@ module Test @@ -1000,7 +1000,7 @@ module Test"),
   645  		},
   646  		{
   647  			SHA:       String("f61aebed695e2e4193db5e6dcb09b5b57875f334"),
   648  			Filename:  String("file2.txt"),
   649  			Additions: Int(5),
   650  			Deletions: Int(3),
   651  			Changes:   Int(103),
   652  			Status:    String("modified"),
   653  			Patch:     String("@@ -132,7 +132,7 @@ module Test @@ -1000,7 +1000,7 @@ module Test"),
   654  		},
   655  	}
   656  
   657  	if !cmp.Equal(commitFiles, want) {
   658  		t.Errorf("PullRequests.ListFiles returned %+v, want %+v", commitFiles, want)
   659  	}
   660  
   661  	const methodName = "ListFiles"
   662  	testBadOptions(t, methodName, func() (err error) {
   663  		_, _, err = client.PullRequests.ListFiles(ctx, "\n", "\n", -1, opts)
   664  		return err
   665  	})
   666  
   667  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   668  		got, resp, err := client.PullRequests.ListFiles(ctx, "o", "r", 1, opts)
   669  		if got != nil {
   670  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   671  		}
   672  		return resp, err
   673  	})
   674  }
   675  
   676  func TestPullRequestsService_IsMerged(t *testing.T) {
   677  	client, mux, _, teardown := setup()
   678  	defer teardown()
   679  
   680  	mux.HandleFunc("/repos/o/r/pulls/1/merge", func(w http.ResponseWriter, r *http.Request) {
   681  		testMethod(t, r, "GET")
   682  		w.WriteHeader(http.StatusNoContent)
   683  	})
   684  
   685  	ctx := context.Background()
   686  	isMerged, _, err := client.PullRequests.IsMerged(ctx, "o", "r", 1)
   687  	if err != nil {
   688  		t.Errorf("PullRequests.IsMerged returned error: %v", err)
   689  	}
   690  
   691  	want := true
   692  	if !cmp.Equal(isMerged, want) {
   693  		t.Errorf("PullRequests.IsMerged returned %+v, want %+v", isMerged, want)
   694  	}
   695  
   696  	const methodName = "IsMerged"
   697  	testBadOptions(t, methodName, func() (err error) {
   698  		_, _, err = client.PullRequests.IsMerged(ctx, "\n", "\n", -1)
   699  		return err
   700  	})
   701  
   702  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   703  		got, resp, err := client.PullRequests.IsMerged(ctx, "o", "r", 1)
   704  		if got {
   705  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want false", methodName, got)
   706  		}
   707  		return resp, err
   708  	})
   709  }
   710  
   711  func TestPullRequestsService_Merge(t *testing.T) {
   712  	client, mux, _, teardown := setup()
   713  	defer teardown()
   714  
   715  	mux.HandleFunc("/repos/o/r/pulls/1/merge", func(w http.ResponseWriter, r *http.Request) {
   716  		testMethod(t, r, "PUT")
   717  		fmt.Fprint(w, `
   718  			{
   719  			  "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
   720  			  "merged": true,
   721  			  "message": "Pull Request successfully merged"
   722  			}`)
   723  	})
   724  
   725  	options := &PullRequestOptions{MergeMethod: "rebase"}
   726  	ctx := context.Background()
   727  	merge, _, err := client.PullRequests.Merge(ctx, "o", "r", 1, "merging pull request", options)
   728  	if err != nil {
   729  		t.Errorf("PullRequests.Merge returned error: %v", err)
   730  	}
   731  
   732  	want := &PullRequestMergeResult{
   733  		SHA:     String("6dcb09b5b57875f334f61aebed695e2e4193db5e"),
   734  		Merged:  Bool(true),
   735  		Message: String("Pull Request successfully merged"),
   736  	}
   737  	if !cmp.Equal(merge, want) {
   738  		t.Errorf("PullRequests.Merge returned %+v, want %+v", merge, want)
   739  	}
   740  
   741  	const methodName = "Merge"
   742  	testBadOptions(t, methodName, func() (err error) {
   743  		_, _, err = client.PullRequests.Merge(ctx, "\n", "\n", -1, "\n", options)
   744  		return err
   745  	})
   746  
   747  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   748  		got, resp, err := client.PullRequests.Merge(ctx, "o", "r", 1, "merging pull request", options)
   749  		if got != nil {
   750  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   751  		}
   752  		return resp, err
   753  	})
   754  }
   755  
   756  // Test that different merge options produce expected PUT requests. See issue https://github.com/google/go-github/issues/500.
   757  func TestPullRequestsService_Merge_options(t *testing.T) {
   758  	client, mux, _, teardown := setup()
   759  	defer teardown()
   760  
   761  	tests := []struct {
   762  		options  *PullRequestOptions
   763  		wantBody string
   764  	}{
   765  		{
   766  			options:  nil,
   767  			wantBody: `{"commit_message":"merging pull request"}`,
   768  		},
   769  		{
   770  			options:  &PullRequestOptions{},
   771  			wantBody: `{"commit_message":"merging pull request"}`,
   772  		},
   773  		{
   774  			options:  &PullRequestOptions{MergeMethod: "rebase"},
   775  			wantBody: `{"commit_message":"merging pull request","merge_method":"rebase"}`,
   776  		},
   777  		{
   778  			options:  &PullRequestOptions{SHA: "6dcb09b5b57875f334f61aebed695e2e4193db5e"},
   779  			wantBody: `{"commit_message":"merging pull request","sha":"6dcb09b5b57875f334f61aebed695e2e4193db5e"}`,
   780  		},
   781  		{
   782  			options: &PullRequestOptions{
   783  				CommitTitle: "Extra detail",
   784  				SHA:         "6dcb09b5b57875f334f61aebed695e2e4193db5e",
   785  				MergeMethod: "squash",
   786  			},
   787  			wantBody: `{"commit_message":"merging pull request","commit_title":"Extra detail","merge_method":"squash","sha":"6dcb09b5b57875f334f61aebed695e2e4193db5e"}`,
   788  		},
   789  		{
   790  			options: &PullRequestOptions{
   791  				DontDefaultIfBlank: true,
   792  			},
   793  			wantBody: `{"commit_message":"merging pull request"}`,
   794  		},
   795  	}
   796  
   797  	for i, test := range tests {
   798  		madeRequest := false
   799  		mux.HandleFunc(fmt.Sprintf("/repos/o/r/pulls/%d/merge", i), func(w http.ResponseWriter, r *http.Request) {
   800  			testMethod(t, r, "PUT")
   801  			testBody(t, r, test.wantBody+"\n")
   802  			madeRequest = true
   803  		})
   804  		ctx := context.Background()
   805  		_, _, _ = client.PullRequests.Merge(ctx, "o", "r", i, "merging pull request", test.options)
   806  		if !madeRequest {
   807  			t.Errorf("%d: PullRequests.Merge(%#v): expected request was not made", i, test.options)
   808  		}
   809  	}
   810  }
   811  
   812  func TestPullRequestsService_Merge_Blank_Message(t *testing.T) {
   813  	client, mux, _, teardown := setup()
   814  	defer teardown()
   815  	madeRequest := false
   816  	expectedBody := ""
   817  	mux.HandleFunc("/repos/o/r/pulls/1/merge", func(w http.ResponseWriter, r *http.Request) {
   818  		testMethod(t, r, "PUT")
   819  		testBody(t, r, expectedBody+"\n")
   820  		madeRequest = true
   821  	})
   822  
   823  	ctx := context.Background()
   824  	expectedBody = `{}`
   825  	_, _, _ = client.PullRequests.Merge(ctx, "o", "r", 1, "", nil)
   826  	if !madeRequest {
   827  		t.Error("TestPullRequestsService_Merge_Blank_Message #1 did not make request")
   828  	}
   829  
   830  	madeRequest = false
   831  	opts := PullRequestOptions{
   832  		DontDefaultIfBlank: true,
   833  	}
   834  	expectedBody = `{"commit_message":""}`
   835  	_, _, _ = client.PullRequests.Merge(ctx, "o", "r", 1, "", &opts)
   836  	if !madeRequest {
   837  		t.Error("TestPullRequestsService_Merge_Blank_Message #2 did not make request")
   838  	}
   839  }
   840  
   841  func TestPullRequestMergeRequest_Marshal(t *testing.T) {
   842  	testJSONMarshal(t, &pullRequestMergeRequest{}, "{}")
   843  
   844  	u := &pullRequestMergeRequest{
   845  		CommitMessage: String("cm"),
   846  		CommitTitle:   "ct",
   847  		MergeMethod:   "mm",
   848  		SHA:           "sha",
   849  	}
   850  
   851  	want := `{
   852  		"commit_message": "cm",
   853  		"commit_title": "ct",
   854  		"merge_method": "mm",
   855  		"sha": "sha"
   856  	}`
   857  
   858  	testJSONMarshal(t, u, want)
   859  }
   860  
   861  func TestPullRequestMergeResult_Marshal(t *testing.T) {
   862  	testJSONMarshal(t, &PullRequestMergeResult{}, "{}")
   863  
   864  	u := &PullRequestMergeResult{
   865  		SHA:     String("sha"),
   866  		Merged:  Bool(false),
   867  		Message: String("msg"),
   868  	}
   869  
   870  	want := `{
   871  		"sha": "sha",
   872  		"merged": false,
   873  		"message": "msg"
   874  	}`
   875  
   876  	testJSONMarshal(t, u, want)
   877  }
   878  
   879  func TestPullRequestUpdate_Marshal(t *testing.T) {
   880  	testJSONMarshal(t, &pullRequestUpdate{}, "{}")
   881  
   882  	u := &pullRequestUpdate{
   883  		Title:               String("title"),
   884  		Body:                String("body"),
   885  		State:               String("state"),
   886  		Base:                String("base"),
   887  		MaintainerCanModify: Bool(false),
   888  	}
   889  
   890  	want := `{
   891  		"title": "title",
   892  		"body": "body",
   893  		"state": "state",
   894  		"base": "base",
   895  		"maintainer_can_modify": false
   896  	}`
   897  
   898  	testJSONMarshal(t, u, want)
   899  }
   900  
   901  func TestPullRequestBranchUpdateResponse_Marshal(t *testing.T) {
   902  	testJSONMarshal(t, &PullRequestBranchUpdateResponse{}, "{}")
   903  
   904  	u := &PullRequestBranchUpdateResponse{
   905  		Message: String("message"),
   906  		URL:     String("url"),
   907  	}
   908  
   909  	want := `{
   910  		"message": "message",
   911  		"url": "url"
   912  	}`
   913  
   914  	testJSONMarshal(t, u, want)
   915  }
   916  
   917  func TestPullRequestBranchUpdateOptions_Marshal(t *testing.T) {
   918  	testJSONMarshal(t, &PullRequestBranchUpdateOptions{}, "{}")
   919  
   920  	u := &PullRequestBranchUpdateOptions{
   921  		ExpectedHeadSHA: String("eh"),
   922  	}
   923  
   924  	want := `{
   925  		"expected_head_sha": "eh"
   926  	}`
   927  
   928  	testJSONMarshal(t, u, want)
   929  }
   930  
   931  func TestNewPullRequest_Marshal(t *testing.T) {
   932  	testJSONMarshal(t, &NewPullRequest{}, "{}")
   933  
   934  	u := &NewPullRequest{
   935  		Title:               String("eh"),
   936  		Head:                String("eh"),
   937  		HeadRepo:            String("eh"),
   938  		Base:                String("eh"),
   939  		Body:                String("eh"),
   940  		Issue:               Int(1),
   941  		MaintainerCanModify: Bool(false),
   942  		Draft:               Bool(false),
   943  	}
   944  
   945  	want := `{
   946  		"title": "eh",
   947  		"head": "eh",
   948  		"head_repo": "eh",
   949  		"base": "eh",
   950  		"body": "eh",
   951  		"issue": 1,
   952  		"maintainer_can_modify": false,
   953  		"draft": false
   954  	}`
   955  
   956  	testJSONMarshal(t, u, want)
   957  }
   958  
   959  func TestPullRequestBranch_Marshal(t *testing.T) {
   960  	testJSONMarshal(t, &PullRequestBranch{}, "{}")
   961  
   962  	u := &PullRequestBranch{
   963  		Label: String("label"),
   964  		Ref:   String("ref"),
   965  		SHA:   String("sha"),
   966  		Repo:  &Repository{ID: Int64(1)},
   967  		User: &User{
   968  			Login:           String("l"),
   969  			ID:              Int64(1),
   970  			URL:             String("u"),
   971  			AvatarURL:       String("a"),
   972  			GravatarID:      String("g"),
   973  			Name:            String("n"),
   974  			Company:         String("c"),
   975  			Blog:            String("b"),
   976  			Location:        String("l"),
   977  			Email:           String("e"),
   978  			Hireable:        Bool(true),
   979  			Bio:             String("b"),
   980  			TwitterUsername: String("t"),
   981  			PublicRepos:     Int(1),
   982  			Followers:       Int(1),
   983  			Following:       Int(1),
   984  			CreatedAt:       &Timestamp{referenceTime},
   985  			SuspendedAt:     &Timestamp{referenceTime},
   986  		},
   987  	}
   988  
   989  	want := `{
   990  		"label": "label",
   991  		"ref": "ref",
   992  		"sha": "sha",
   993  		"repo": {
   994  			"id": 1
   995  		},
   996  		"user": {
   997  			"login": "l",
   998  			"id": 1,
   999  			"avatar_url": "a",
  1000  			"gravatar_id": "g",
  1001  			"name": "n",
  1002  			"company": "c",
  1003  			"blog": "b",
  1004  			"location": "l",
  1005  			"email": "e",
  1006  			"hireable": true,
  1007  			"bio": "b",
  1008  			"twitter_username": "t",
  1009  			"public_repos": 1,
  1010  			"followers": 1,
  1011  			"following": 1,
  1012  			"created_at": ` + referenceTimeStr + `,
  1013  			"suspended_at": ` + referenceTimeStr + `,
  1014  			"url": "u"
  1015  		}
  1016  	}`
  1017  
  1018  	testJSONMarshal(t, u, want)
  1019  }
  1020  
  1021  func TestPRLink_Marshal(t *testing.T) {
  1022  	testJSONMarshal(t, &PRLink{}, "{}")
  1023  
  1024  	u := &PRLink{
  1025  		HRef: String("href"),
  1026  	}
  1027  
  1028  	want := `{
  1029  		"href": "href"
  1030  	}`
  1031  
  1032  	testJSONMarshal(t, u, want)
  1033  }
  1034  
  1035  func TestPRLinks_Marshal(t *testing.T) {
  1036  	testJSONMarshal(t, &PRLinks{}, "{}")
  1037  
  1038  	u := &PRLinks{
  1039  		Self: &PRLink{
  1040  			HRef: String("href"),
  1041  		},
  1042  		HTML: &PRLink{
  1043  			HRef: String("href"),
  1044  		},
  1045  		Issue: &PRLink{
  1046  			HRef: String("href"),
  1047  		},
  1048  		Comments: &PRLink{
  1049  			HRef: String("href"),
  1050  		},
  1051  		ReviewComments: &PRLink{
  1052  			HRef: String("href"),
  1053  		},
  1054  		ReviewComment: &PRLink{
  1055  			HRef: String("href"),
  1056  		},
  1057  		Commits: &PRLink{
  1058  			HRef: String("href"),
  1059  		},
  1060  		Statuses: &PRLink{
  1061  			HRef: String("href"),
  1062  		},
  1063  	}
  1064  
  1065  	want := `{
  1066  		"self": {
  1067  			"href": "href"
  1068  		},
  1069  		"html": {
  1070  			"href": "href"
  1071  		},
  1072  		"issue": {
  1073  			"href": "href"
  1074  		},
  1075  		"comments": {
  1076  			"href": "href"
  1077  		},
  1078  		"review_comments": {
  1079  			"href": "href"
  1080  		},
  1081  		"review_comment": {
  1082  			"href": "href"
  1083  		},
  1084  		"commits": {
  1085  			"href": "href"
  1086  		},
  1087  		"statuses": {
  1088  			"href": "href"
  1089  		}
  1090  	}`
  1091  
  1092  	testJSONMarshal(t, u, want)
  1093  }
  1094  
  1095  func TestPullRequestAutoMerge_Marshal(t *testing.T) {
  1096  	testJSONMarshal(t, &PullRequestAutoMerge{}, "{}")
  1097  
  1098  	u := &PullRequestAutoMerge{
  1099  		EnabledBy: &User{
  1100  			Login:           String("l"),
  1101  			ID:              Int64(1),
  1102  			URL:             String("u"),
  1103  			AvatarURL:       String("a"),
  1104  			GravatarID:      String("g"),
  1105  			Name:            String("n"),
  1106  			Company:         String("c"),
  1107  			Blog:            String("b"),
  1108  			Location:        String("l"),
  1109  			Email:           String("e"),
  1110  			Hireable:        Bool(true),
  1111  			Bio:             String("b"),
  1112  			TwitterUsername: String("t"),
  1113  			PublicRepos:     Int(1),
  1114  			Followers:       Int(1),
  1115  			Following:       Int(1),
  1116  			CreatedAt:       &Timestamp{referenceTime},
  1117  			SuspendedAt:     &Timestamp{referenceTime},
  1118  		},
  1119  		MergeMethod:   String("mm"),
  1120  		CommitTitle:   String("ct"),
  1121  		CommitMessage: String("cm"),
  1122  	}
  1123  
  1124  	want := `{
  1125  		"enabled_by": {
  1126  			"login": "l",
  1127  			"id": 1,
  1128  			"avatar_url": "a",
  1129  			"gravatar_id": "g",
  1130  			"name": "n",
  1131  			"company": "c",
  1132  			"blog": "b",
  1133  			"location": "l",
  1134  			"email": "e",
  1135  			"hireable": true,
  1136  			"bio": "b",
  1137  			"twitter_username": "t",
  1138  			"public_repos": 1,
  1139  			"followers": 1,
  1140  			"following": 1,
  1141  			"created_at": ` + referenceTimeStr + `,
  1142  			"suspended_at": ` + referenceTimeStr + `,
  1143  			"url": "u"
  1144  		},
  1145  		"merge_method": "mm",
  1146  		"commit_title": "ct",
  1147  		"commit_message": "cm"
  1148  	}`
  1149  
  1150  	testJSONMarshal(t, u, want)
  1151  }
  1152  
  1153  func TestPullRequest_Marshal(t *testing.T) {
  1154  	testJSONMarshal(t, &PullRequest{}, "{}")
  1155  
  1156  	u := &PullRequest{
  1157  		ID:        Int64(1),
  1158  		Number:    Int(1),
  1159  		State:     String("state"),
  1160  		Locked:    Bool(false),
  1161  		Title:     String("title"),
  1162  		Body:      String("body"),
  1163  		CreatedAt: &Timestamp{referenceTime},
  1164  		UpdatedAt: &Timestamp{referenceTime},
  1165  		ClosedAt:  &Timestamp{referenceTime},
  1166  		MergedAt:  &Timestamp{referenceTime},
  1167  		Labels:    []*Label{{ID: Int64(1)}},
  1168  		User: &User{
  1169  			Login:           String("l"),
  1170  			ID:              Int64(1),
  1171  			URL:             String("u"),
  1172  			AvatarURL:       String("a"),
  1173  			GravatarID:      String("g"),
  1174  			Name:            String("n"),
  1175  			Company:         String("c"),
  1176  			Blog:            String("b"),
  1177  			Location:        String("l"),
  1178  			Email:           String("e"),
  1179  			Hireable:        Bool(true),
  1180  			Bio:             String("b"),
  1181  			TwitterUsername: String("t"),
  1182  			PublicRepos:     Int(1),
  1183  			Followers:       Int(1),
  1184  			Following:       Int(1),
  1185  			CreatedAt:       &Timestamp{referenceTime},
  1186  			SuspendedAt:     &Timestamp{referenceTime},
  1187  		},
  1188  		Draft:          Bool(false),
  1189  		Merged:         Bool(false),
  1190  		Mergeable:      Bool(false),
  1191  		MergeableState: String("ms"),
  1192  		MergedBy: &User{
  1193  			Login:           String("l"),
  1194  			ID:              Int64(1),
  1195  			URL:             String("u"),
  1196  			AvatarURL:       String("a"),
  1197  			GravatarID:      String("g"),
  1198  			Name:            String("n"),
  1199  			Company:         String("c"),
  1200  			Blog:            String("b"),
  1201  			Location:        String("l"),
  1202  			Email:           String("e"),
  1203  			Hireable:        Bool(true),
  1204  			Bio:             String("b"),
  1205  			TwitterUsername: String("t"),
  1206  			PublicRepos:     Int(1),
  1207  			Followers:       Int(1),
  1208  			Following:       Int(1),
  1209  			CreatedAt:       &Timestamp{referenceTime},
  1210  			SuspendedAt:     &Timestamp{referenceTime},
  1211  		},
  1212  		MergeCommitSHA:    String("mcs"),
  1213  		Rebaseable:        Bool(false),
  1214  		Comments:          Int(1),
  1215  		Commits:           Int(1),
  1216  		Additions:         Int(1),
  1217  		Deletions:         Int(1),
  1218  		ChangedFiles:      Int(1),
  1219  		URL:               String("url"),
  1220  		HTMLURL:           String("hurl"),
  1221  		IssueURL:          String("iurl"),
  1222  		StatusesURL:       String("surl"),
  1223  		DiffURL:           String("durl"),
  1224  		PatchURL:          String("purl"),
  1225  		CommitsURL:        String("curl"),
  1226  		CommentsURL:       String("comurl"),
  1227  		ReviewCommentsURL: String("rcurls"),
  1228  		ReviewCommentURL:  String("rcurl"),
  1229  		ReviewComments:    Int(1),
  1230  		Assignee: &User{
  1231  			Login:           String("l"),
  1232  			ID:              Int64(1),
  1233  			URL:             String("u"),
  1234  			AvatarURL:       String("a"),
  1235  			GravatarID:      String("g"),
  1236  			Name:            String("n"),
  1237  			Company:         String("c"),
  1238  			Blog:            String("b"),
  1239  			Location:        String("l"),
  1240  			Email:           String("e"),
  1241  			Hireable:        Bool(true),
  1242  			Bio:             String("b"),
  1243  			TwitterUsername: String("t"),
  1244  			PublicRepos:     Int(1),
  1245  			Followers:       Int(1),
  1246  			Following:       Int(1),
  1247  			CreatedAt:       &Timestamp{referenceTime},
  1248  			SuspendedAt:     &Timestamp{referenceTime},
  1249  		},
  1250  		Assignees: []*User{
  1251  			{
  1252  				Login:           String("l"),
  1253  				ID:              Int64(1),
  1254  				URL:             String("u"),
  1255  				AvatarURL:       String("a"),
  1256  				GravatarID:      String("g"),
  1257  				Name:            String("n"),
  1258  				Company:         String("c"),
  1259  				Blog:            String("b"),
  1260  				Location:        String("l"),
  1261  				Email:           String("e"),
  1262  				Hireable:        Bool(true),
  1263  				Bio:             String("b"),
  1264  				TwitterUsername: String("t"),
  1265  				PublicRepos:     Int(1),
  1266  				Followers:       Int(1),
  1267  				Following:       Int(1),
  1268  				CreatedAt:       &Timestamp{referenceTime},
  1269  				SuspendedAt:     &Timestamp{referenceTime},
  1270  			},
  1271  		},
  1272  		Milestone:           &Milestone{ID: Int64(1)},
  1273  		MaintainerCanModify: Bool(true),
  1274  		AuthorAssociation:   String("aa"),
  1275  		NodeID:              String("nid"),
  1276  		RequestedReviewers: []*User{
  1277  			{
  1278  				Login:           String("l"),
  1279  				ID:              Int64(1),
  1280  				URL:             String("u"),
  1281  				AvatarURL:       String("a"),
  1282  				GravatarID:      String("g"),
  1283  				Name:            String("n"),
  1284  				Company:         String("c"),
  1285  				Blog:            String("b"),
  1286  				Location:        String("l"),
  1287  				Email:           String("e"),
  1288  				Hireable:        Bool(true),
  1289  				Bio:             String("b"),
  1290  				TwitterUsername: String("t"),
  1291  				PublicRepos:     Int(1),
  1292  				Followers:       Int(1),
  1293  				Following:       Int(1),
  1294  				CreatedAt:       &Timestamp{referenceTime},
  1295  				SuspendedAt:     &Timestamp{referenceTime},
  1296  			},
  1297  		},
  1298  		AutoMerge: &PullRequestAutoMerge{
  1299  			EnabledBy: &User{
  1300  				Login:           String("l"),
  1301  				ID:              Int64(1),
  1302  				URL:             String("u"),
  1303  				AvatarURL:       String("a"),
  1304  				GravatarID:      String("g"),
  1305  				Name:            String("n"),
  1306  				Company:         String("c"),
  1307  				Blog:            String("b"),
  1308  				Location:        String("l"),
  1309  				Email:           String("e"),
  1310  				Hireable:        Bool(true),
  1311  				Bio:             String("b"),
  1312  				TwitterUsername: String("t"),
  1313  				PublicRepos:     Int(1),
  1314  				Followers:       Int(1),
  1315  				Following:       Int(1),
  1316  				CreatedAt:       &Timestamp{referenceTime},
  1317  				SuspendedAt:     &Timestamp{referenceTime},
  1318  			},
  1319  			MergeMethod:   String("mm"),
  1320  			CommitTitle:   String("ct"),
  1321  			CommitMessage: String("cm"),
  1322  		},
  1323  		RequestedTeams: []*Team{{ID: Int64(1)}},
  1324  		Links: &PRLinks{
  1325  			Self: &PRLink{
  1326  				HRef: String("href"),
  1327  			},
  1328  			HTML: &PRLink{
  1329  				HRef: String("href"),
  1330  			},
  1331  			Issue: &PRLink{
  1332  				HRef: String("href"),
  1333  			},
  1334  			Comments: &PRLink{
  1335  				HRef: String("href"),
  1336  			},
  1337  			ReviewComments: &PRLink{
  1338  				HRef: String("href"),
  1339  			},
  1340  			ReviewComment: &PRLink{
  1341  				HRef: String("href"),
  1342  			},
  1343  			Commits: &PRLink{
  1344  				HRef: String("href"),
  1345  			},
  1346  			Statuses: &PRLink{
  1347  				HRef: String("href"),
  1348  			},
  1349  		},
  1350  		Head: &PullRequestBranch{
  1351  			Ref:  String("r2"),
  1352  			Repo: &Repository{ID: Int64(2)},
  1353  		},
  1354  		Base: &PullRequestBranch{
  1355  			Ref:  String("r2"),
  1356  			Repo: &Repository{ID: Int64(2)},
  1357  		},
  1358  		ActiveLockReason: String("alr"),
  1359  	}
  1360  
  1361  	want := `{
  1362  		"id": 1,
  1363  		"number": 1,
  1364  		"state": "state",
  1365  		"locked": false,
  1366  		"title": "title",
  1367  		"body": "body",
  1368  		"created_at": ` + referenceTimeStr + `,
  1369  		"updated_at": ` + referenceTimeStr + `,
  1370  		"closed_at": ` + referenceTimeStr + `,
  1371  		"merged_at": ` + referenceTimeStr + `,
  1372  		"labels": [
  1373  			{
  1374  				"id": 1
  1375  			}
  1376  		],
  1377  		"user": {
  1378  			"login": "l",
  1379  			"id": 1,
  1380  			"avatar_url": "a",
  1381  			"gravatar_id": "g",
  1382  			"name": "n",
  1383  			"company": "c",
  1384  			"blog": "b",
  1385  			"location": "l",
  1386  			"email": "e",
  1387  			"hireable": true,
  1388  			"bio": "b",
  1389  			"twitter_username": "t",
  1390  			"public_repos": 1,
  1391  			"followers": 1,
  1392  			"following": 1,
  1393  			"created_at": ` + referenceTimeStr + `,
  1394  			"suspended_at": ` + referenceTimeStr + `,
  1395  			"url": "u"
  1396  		},
  1397  		"draft": false,
  1398  		"merged": false,
  1399  		"mergeable": false,
  1400  		"mergeable_state": "ms",
  1401  		"merged_by": {
  1402  			"login": "l",
  1403  			"id": 1,
  1404  			"avatar_url": "a",
  1405  			"gravatar_id": "g",
  1406  			"name": "n",
  1407  			"company": "c",
  1408  			"blog": "b",
  1409  			"location": "l",
  1410  			"email": "e",
  1411  			"hireable": true,
  1412  			"bio": "b",
  1413  			"twitter_username": "t",
  1414  			"public_repos": 1,
  1415  			"followers": 1,
  1416  			"following": 1,
  1417  			"created_at": ` + referenceTimeStr + `,
  1418  			"suspended_at": ` + referenceTimeStr + `,
  1419  			"url": "u"
  1420  		},
  1421  		"merge_commit_sha": "mcs",
  1422  		"rebaseable": false,
  1423  		"comments": 1,
  1424  		"commits": 1,
  1425  		"additions": 1,
  1426  		"deletions": 1,
  1427  		"changed_files": 1,
  1428  		"url": "url",
  1429  		"html_url": "hurl",
  1430  		"issue_url": "iurl",
  1431  		"statuses_url": "surl",
  1432  		"diff_url": "durl",
  1433  		"patch_url": "purl",
  1434  		"commits_url": "curl",
  1435  		"comments_url": "comurl",
  1436  		"review_comments_url": "rcurls",
  1437  		"review_comment_url": "rcurl",
  1438  		"review_comments": 1,
  1439  		"assignee": {
  1440  			"login": "l",
  1441  			"id": 1,
  1442  			"avatar_url": "a",
  1443  			"gravatar_id": "g",
  1444  			"name": "n",
  1445  			"company": "c",
  1446  			"blog": "b",
  1447  			"location": "l",
  1448  			"email": "e",
  1449  			"hireable": true,
  1450  			"bio": "b",
  1451  			"twitter_username": "t",
  1452  			"public_repos": 1,
  1453  			"followers": 1,
  1454  			"following": 1,
  1455  			"created_at": ` + referenceTimeStr + `,
  1456  			"suspended_at": ` + referenceTimeStr + `,
  1457  			"url": "u"
  1458  		},
  1459  		"assignees": [
  1460  			{
  1461  				"login": "l",
  1462  				"id": 1,
  1463  				"avatar_url": "a",
  1464  				"gravatar_id": "g",
  1465  				"name": "n",
  1466  				"company": "c",
  1467  				"blog": "b",
  1468  				"location": "l",
  1469  				"email": "e",
  1470  				"hireable": true,
  1471  				"bio": "b",
  1472  				"twitter_username": "t",
  1473  				"public_repos": 1,
  1474  				"followers": 1,
  1475  				"following": 1,
  1476  				"created_at": ` + referenceTimeStr + `,
  1477  				"suspended_at": ` + referenceTimeStr + `,
  1478  				"url": "u"
  1479  			}
  1480  		],
  1481  		"milestone": {
  1482  			"id": 1
  1483  		},
  1484  		"maintainer_can_modify": true,
  1485  		"author_association": "aa",
  1486  		"node_id": "nid",
  1487  		"requested_reviewers": [
  1488  			{
  1489  				"login": "l",
  1490  				"id": 1,
  1491  				"avatar_url": "a",
  1492  				"gravatar_id": "g",
  1493  				"name": "n",
  1494  				"company": "c",
  1495  				"blog": "b",
  1496  				"location": "l",
  1497  				"email": "e",
  1498  				"hireable": true,
  1499  				"bio": "b",
  1500  				"twitter_username": "t",
  1501  				"public_repos": 1,
  1502  				"followers": 1,
  1503  				"following": 1,
  1504  				"created_at": ` + referenceTimeStr + `,
  1505  				"suspended_at": ` + referenceTimeStr + `,
  1506  				"url": "u"
  1507  			}
  1508  		],
  1509  		"auto_merge": {
  1510  			"enabled_by": {
  1511  				"login": "l",
  1512  				"id": 1,
  1513  				"avatar_url": "a",
  1514  				"gravatar_id": "g",
  1515  				"name": "n",
  1516  				"company": "c",
  1517  				"blog": "b",
  1518  				"location": "l",
  1519  				"email": "e",
  1520  				"hireable": true,
  1521  				"bio": "b",
  1522  				"twitter_username": "t",
  1523  				"public_repos": 1,
  1524  				"followers": 1,
  1525  				"following": 1,
  1526  				"created_at": ` + referenceTimeStr + `,
  1527  				"suspended_at": ` + referenceTimeStr + `,
  1528  				"url": "u"
  1529  			},
  1530  			"merge_method": "mm",
  1531  			"commit_title": "ct",
  1532  			"commit_message": "cm"
  1533  		},
  1534  		"requested_teams": [
  1535  			{
  1536  				"id": 1
  1537  			}
  1538  		],
  1539  		"_links": {
  1540  			"self": {
  1541  				"href": "href"
  1542  			},
  1543  			"html": {
  1544  				"href": "href"
  1545  			},
  1546  			"issue": {
  1547  				"href": "href"
  1548  			},
  1549  			"comments": {
  1550  				"href": "href"
  1551  			},
  1552  			"review_comments": {
  1553  				"href": "href"
  1554  			},
  1555  			"review_comment": {
  1556  				"href": "href"
  1557  			},
  1558  			"commits": {
  1559  				"href": "href"
  1560  			},
  1561  			"statuses": {
  1562  				"href": "href"
  1563  			}
  1564  		},
  1565  		"head": {
  1566  			"ref": "r2",
  1567  			"repo": {
  1568  				"id": 2
  1569  			}
  1570  		},
  1571  		"base": {
  1572  			"ref": "r2",
  1573  			"repo": {
  1574  				"id": 2
  1575  			}
  1576  		},
  1577  		"active_lock_reason": "alr"
  1578  	}`
  1579  
  1580  	testJSONMarshal(t, u, want)
  1581  }