github.com/google/go-github/v70@v70.0.0/github/pulls_reviews_test.go (about)

     1  // Copyright 2016 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  
    15  	"github.com/google/go-cmp/cmp"
    16  )
    17  
    18  func TestPullRequestsService_ListReviews(t *testing.T) {
    19  	t.Parallel()
    20  	client, mux, _ := setup(t)
    21  
    22  	mux.HandleFunc("/repos/o/r/pulls/1/reviews", func(w http.ResponseWriter, r *http.Request) {
    23  		testMethod(t, r, "GET")
    24  		testFormValues(t, r, values{
    25  			"page": "2",
    26  		})
    27  		fmt.Fprint(w, `[{"id":1},{"id":2}]`)
    28  	})
    29  
    30  	opt := &ListOptions{Page: 2}
    31  	ctx := context.Background()
    32  	reviews, _, err := client.PullRequests.ListReviews(ctx, "o", "r", 1, opt)
    33  	if err != nil {
    34  		t.Errorf("PullRequests.ListReviews returned error: %v", err)
    35  	}
    36  
    37  	want := []*PullRequestReview{
    38  		{ID: Ptr(int64(1))},
    39  		{ID: Ptr(int64(2))},
    40  	}
    41  	if !cmp.Equal(reviews, want) {
    42  		t.Errorf("PullRequests.ListReviews returned %+v, want %+v", reviews, want)
    43  	}
    44  
    45  	const methodName = "ListReviews"
    46  	testBadOptions(t, methodName, func() (err error) {
    47  		_, _, err = client.PullRequests.ListReviews(ctx, "\n", "\n", -1, opt)
    48  		return err
    49  	})
    50  
    51  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
    52  		got, resp, err := client.PullRequests.ListReviews(ctx, "o", "r", 1, opt)
    53  		if got != nil {
    54  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
    55  		}
    56  		return resp, err
    57  	})
    58  }
    59  
    60  func TestPullRequestsService_ListReviews_invalidOwner(t *testing.T) {
    61  	t.Parallel()
    62  	client, _, _ := setup(t)
    63  
    64  	ctx := context.Background()
    65  	_, _, err := client.PullRequests.ListReviews(ctx, "%", "r", 1, nil)
    66  	testURLParseError(t, err)
    67  }
    68  
    69  func TestPullRequestsService_GetReview(t *testing.T) {
    70  	t.Parallel()
    71  	client, mux, _ := setup(t)
    72  
    73  	mux.HandleFunc("/repos/o/r/pulls/1/reviews/1", func(w http.ResponseWriter, r *http.Request) {
    74  		testMethod(t, r, "GET")
    75  		fmt.Fprint(w, `{"id":1}`)
    76  	})
    77  
    78  	ctx := context.Background()
    79  	review, _, err := client.PullRequests.GetReview(ctx, "o", "r", 1, 1)
    80  	if err != nil {
    81  		t.Errorf("PullRequests.GetReview returned error: %v", err)
    82  	}
    83  
    84  	want := &PullRequestReview{ID: Ptr(int64(1))}
    85  	if !cmp.Equal(review, want) {
    86  		t.Errorf("PullRequests.GetReview returned %+v, want %+v", review, want)
    87  	}
    88  
    89  	const methodName = "GetReview"
    90  	testBadOptions(t, methodName, func() (err error) {
    91  		_, _, err = client.PullRequests.GetReview(ctx, "\n", "\n", -1, -1)
    92  		return err
    93  	})
    94  
    95  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
    96  		got, resp, err := client.PullRequests.GetReview(ctx, "o", "r", 1, 1)
    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_GetReview_invalidOwner(t *testing.T) {
   105  	t.Parallel()
   106  	client, _, _ := setup(t)
   107  
   108  	ctx := context.Background()
   109  	_, _, err := client.PullRequests.GetReview(ctx, "%", "r", 1, 1)
   110  	testURLParseError(t, err)
   111  }
   112  
   113  func TestPullRequestsService_DeletePendingReview(t *testing.T) {
   114  	t.Parallel()
   115  	client, mux, _ := setup(t)
   116  
   117  	mux.HandleFunc("/repos/o/r/pulls/1/reviews/1", func(w http.ResponseWriter, r *http.Request) {
   118  		testMethod(t, r, "DELETE")
   119  		fmt.Fprint(w, `{"id":1}`)
   120  	})
   121  
   122  	ctx := context.Background()
   123  	review, _, err := client.PullRequests.DeletePendingReview(ctx, "o", "r", 1, 1)
   124  	if err != nil {
   125  		t.Errorf("PullRequests.DeletePendingReview returned error: %v", err)
   126  	}
   127  
   128  	want := &PullRequestReview{ID: Ptr(int64(1))}
   129  	if !cmp.Equal(review, want) {
   130  		t.Errorf("PullRequests.DeletePendingReview returned %+v, want %+v", review, want)
   131  	}
   132  
   133  	const methodName = "DeletePendingReview"
   134  	testBadOptions(t, methodName, func() (err error) {
   135  		_, _, err = client.PullRequests.DeletePendingReview(ctx, "\n", "\n", -1, -1)
   136  		return err
   137  	})
   138  
   139  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   140  		got, resp, err := client.PullRequests.DeletePendingReview(ctx, "o", "r", 1, 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_DeletePendingReview_invalidOwner(t *testing.T) {
   149  	t.Parallel()
   150  	client, _, _ := setup(t)
   151  
   152  	ctx := context.Background()
   153  	_, _, err := client.PullRequests.DeletePendingReview(ctx, "%", "r", 1, 1)
   154  	testURLParseError(t, err)
   155  }
   156  
   157  func TestPullRequestsService_ListReviewComments(t *testing.T) {
   158  	t.Parallel()
   159  	client, mux, _ := setup(t)
   160  
   161  	mux.HandleFunc("/repos/o/r/pulls/1/reviews/1/comments", func(w http.ResponseWriter, r *http.Request) {
   162  		testMethod(t, r, "GET")
   163  		fmt.Fprint(w, `[{"id":1},{"id":2}]`)
   164  	})
   165  
   166  	ctx := context.Background()
   167  	comments, _, err := client.PullRequests.ListReviewComments(ctx, "o", "r", 1, 1, nil)
   168  	if err != nil {
   169  		t.Errorf("PullRequests.ListReviewComments returned error: %v", err)
   170  	}
   171  
   172  	want := []*PullRequestComment{
   173  		{ID: Ptr(int64(1))},
   174  		{ID: Ptr(int64(2))},
   175  	}
   176  	if !cmp.Equal(comments, want) {
   177  		t.Errorf("PullRequests.ListReviewComments returned %+v, want %+v", comments, want)
   178  	}
   179  
   180  	const methodName = "ListReviewComments"
   181  	testBadOptions(t, methodName, func() (err error) {
   182  		_, _, err = client.PullRequests.ListReviewComments(ctx, "\n", "\n", -1, -1, nil)
   183  		return err
   184  	})
   185  
   186  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   187  		got, resp, err := client.PullRequests.ListReviewComments(ctx, "o", "r", 1, 1, nil)
   188  		if got != nil {
   189  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   190  		}
   191  		return resp, err
   192  	})
   193  }
   194  
   195  func TestPullRequestsService_ListReviewComments_withOptions(t *testing.T) {
   196  	t.Parallel()
   197  	client, mux, _ := setup(t)
   198  
   199  	mux.HandleFunc("/repos/o/r/pulls/1/reviews/1/comments", func(w http.ResponseWriter, r *http.Request) {
   200  		testMethod(t, r, "GET")
   201  		testFormValues(t, r, values{
   202  			"page": "2",
   203  		})
   204  		fmt.Fprint(w, `[]`)
   205  	})
   206  
   207  	ctx := context.Background()
   208  	_, _, err := client.PullRequests.ListReviewComments(ctx, "o", "r", 1, 1, &ListOptions{Page: 2})
   209  	if err != nil {
   210  		t.Errorf("PullRequests.ListReviewComments returned error: %v", err)
   211  	}
   212  
   213  	const methodName = "ListReviewComments"
   214  	testBadOptions(t, methodName, func() (err error) {
   215  		_, _, err = client.PullRequests.ListReviewComments(ctx, "\n", "\n", -1, -1, &ListOptions{Page: 2})
   216  		return err
   217  	})
   218  
   219  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   220  		got, resp, err := client.PullRequests.ListReviewComments(ctx, "o", "r", 1, 1, &ListOptions{Page: 2})
   221  		if got != nil {
   222  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   223  		}
   224  		return resp, err
   225  	})
   226  }
   227  
   228  func TestPullRequestReviewRequest_isComfortFadePreview(t *testing.T) {
   229  	t.Parallel()
   230  	path := "path/to/file.go"
   231  	body := "this is a comment body"
   232  	left, right := "LEFT", "RIGHT"
   233  	pos1, pos2, pos3 := 1, 2, 3
   234  	line1, line2, line3 := 11, 22, 33
   235  
   236  	tests := []struct {
   237  		name     string
   238  		review   *PullRequestReviewRequest
   239  		wantErr  error
   240  		wantBool bool
   241  	}{{
   242  		name:     "empty review",
   243  		review:   &PullRequestReviewRequest{},
   244  		wantBool: false,
   245  	}, {
   246  		name:     "nil comment",
   247  		review:   &PullRequestReviewRequest{Comments: []*DraftReviewComment{nil}},
   248  		wantBool: false,
   249  	}, {
   250  		name: "old-style review",
   251  		review: &PullRequestReviewRequest{
   252  			Comments: []*DraftReviewComment{{
   253  				Path:     &path,
   254  				Body:     &body,
   255  				Position: &pos1,
   256  			}, {
   257  				Path:     &path,
   258  				Body:     &body,
   259  				Position: &pos2,
   260  			}, {
   261  				Path:     &path,
   262  				Body:     &body,
   263  				Position: &pos3,
   264  			}},
   265  		},
   266  		wantBool: false,
   267  	}, {
   268  		name: "new-style review",
   269  		review: &PullRequestReviewRequest{
   270  			Comments: []*DraftReviewComment{{
   271  				Path: &path,
   272  				Body: &body,
   273  				Side: &right,
   274  				Line: &line1,
   275  			}, {
   276  				Path: &path,
   277  				Body: &body,
   278  				Side: &left,
   279  				Line: &line2,
   280  			}, {
   281  				Path: &path,
   282  				Body: &body,
   283  				Side: &right,
   284  				Line: &line3,
   285  			}},
   286  		},
   287  		wantBool: true,
   288  	}, {
   289  		name: "blended comment",
   290  		review: &PullRequestReviewRequest{
   291  			Comments: []*DraftReviewComment{{
   292  				Path:     &path,
   293  				Body:     &body,
   294  				Position: &pos1, // can't have both styles.
   295  				Side:     &right,
   296  				Line:     &line1,
   297  			}},
   298  		},
   299  		wantErr: ErrMixedCommentStyles,
   300  	}, {
   301  		name: "position then line",
   302  		review: &PullRequestReviewRequest{
   303  			Comments: []*DraftReviewComment{{
   304  				Path:     &path,
   305  				Body:     &body,
   306  				Position: &pos1,
   307  			}, {
   308  				Path: &path,
   309  				Body: &body,
   310  				Side: &right,
   311  				Line: &line1,
   312  			}},
   313  		},
   314  		wantErr: ErrMixedCommentStyles,
   315  	}, {
   316  		name: "line then position",
   317  		review: &PullRequestReviewRequest{
   318  			Comments: []*DraftReviewComment{{
   319  				Path: &path,
   320  				Body: &body,
   321  				Side: &right,
   322  				Line: &line1,
   323  			}, {
   324  				Path:     &path,
   325  				Body:     &body,
   326  				Position: &pos1,
   327  			}},
   328  		},
   329  		wantErr: ErrMixedCommentStyles,
   330  	}}
   331  
   332  	for _, tc := range tests {
   333  		tc := tc
   334  		t.Run(tc.name, func(t *testing.T) {
   335  			t.Parallel()
   336  			gotBool, gotErr := tc.review.isComfortFadePreview()
   337  			if tc.wantErr != nil {
   338  				if gotErr != tc.wantErr {
   339  					t.Errorf("isComfortFadePreview() = %v, wanted %v", gotErr, tc.wantErr)
   340  				}
   341  			} else {
   342  				if gotBool != tc.wantBool {
   343  					t.Errorf("isComfortFadePreview() = %v, wanted %v", gotBool, tc.wantBool)
   344  				}
   345  			}
   346  		})
   347  	}
   348  }
   349  
   350  func TestPullRequestsService_ListReviewComments_invalidOwner(t *testing.T) {
   351  	t.Parallel()
   352  	client, _, _ := setup(t)
   353  
   354  	ctx := context.Background()
   355  	_, _, err := client.PullRequests.ListReviewComments(ctx, "%", "r", 1, 1, nil)
   356  	testURLParseError(t, err)
   357  }
   358  
   359  func TestPullRequestsService_CreateReview(t *testing.T) {
   360  	t.Parallel()
   361  	client, mux, _ := setup(t)
   362  
   363  	input := &PullRequestReviewRequest{
   364  		CommitID: Ptr("commit_id"),
   365  		Body:     Ptr("b"),
   366  		Event:    Ptr("APPROVE"),
   367  	}
   368  
   369  	mux.HandleFunc("/repos/o/r/pulls/1/reviews", func(w http.ResponseWriter, r *http.Request) {
   370  		v := new(PullRequestReviewRequest)
   371  		assertNilError(t, json.NewDecoder(r.Body).Decode(v))
   372  
   373  		testMethod(t, r, "POST")
   374  		if !cmp.Equal(v, input) {
   375  			t.Errorf("Request body = %+v, want %+v", v, input)
   376  		}
   377  
   378  		fmt.Fprint(w, `{"id":1}`)
   379  	})
   380  
   381  	ctx := context.Background()
   382  	review, _, err := client.PullRequests.CreateReview(ctx, "o", "r", 1, input)
   383  	if err != nil {
   384  		t.Errorf("PullRequests.CreateReview returned error: %v", err)
   385  	}
   386  
   387  	want := &PullRequestReview{ID: Ptr(int64(1))}
   388  	if !cmp.Equal(review, want) {
   389  		t.Errorf("PullRequests.CreateReview returned %+v, want %+v", review, want)
   390  	}
   391  
   392  	const methodName = "CreateReview"
   393  	testBadOptions(t, methodName, func() (err error) {
   394  		_, _, err = client.PullRequests.CreateReview(ctx, "\n", "\n", -1, input)
   395  		return err
   396  	})
   397  
   398  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   399  		got, resp, err := client.PullRequests.CreateReview(ctx, "o", "r", 1, input)
   400  		if got != nil {
   401  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   402  		}
   403  		return resp, err
   404  	})
   405  }
   406  
   407  func TestPullRequestsService_CreateReview_invalidOwner(t *testing.T) {
   408  	t.Parallel()
   409  	client, _, _ := setup(t)
   410  
   411  	ctx := context.Background()
   412  	_, _, err := client.PullRequests.CreateReview(ctx, "%", "r", 1, &PullRequestReviewRequest{})
   413  	testURLParseError(t, err)
   414  }
   415  
   416  func TestPullRequestsService_CreateReview_badReview(t *testing.T) {
   417  	t.Parallel()
   418  	client, _, _ := setup(t)
   419  
   420  	ctx := context.Background()
   421  
   422  	path := "path/to/file.go"
   423  	body := "this is a comment body"
   424  	right := "RIGHT"
   425  	pos1 := 1
   426  	line1 := 11
   427  	badReview := &PullRequestReviewRequest{
   428  		Comments: []*DraftReviewComment{{
   429  			Path: &path,
   430  			Body: &body,
   431  			Side: &right,
   432  			Line: &line1,
   433  		}, {
   434  			Path:     &path,
   435  			Body:     &body,
   436  			Position: &pos1,
   437  		}}}
   438  
   439  	_, _, err := client.PullRequests.CreateReview(ctx, "o", "r", 1, badReview)
   440  	if err == nil {
   441  		t.Errorf("CreateReview badReview err = nil, want err")
   442  	}
   443  }
   444  
   445  func TestPullRequestsService_CreateReview_addHeader(t *testing.T) {
   446  	t.Parallel()
   447  	client, mux, _ := setup(t)
   448  
   449  	path := "path/to/file.go"
   450  	body := "this is a comment body"
   451  	left, right := "LEFT", "RIGHT"
   452  	line1, line2, line3 := 11, 22, 33
   453  	input := &PullRequestReviewRequest{
   454  		Comments: []*DraftReviewComment{{
   455  			Path: &path,
   456  			Body: &body,
   457  			Side: &right,
   458  			Line: &line1,
   459  		}, {
   460  			Path: &path,
   461  			Body: &body,
   462  			Side: &left,
   463  			Line: &line2,
   464  		}, {
   465  			Path: &path,
   466  			Body: &body,
   467  			Side: &right,
   468  			Line: &line3,
   469  		}},
   470  	}
   471  
   472  	mux.HandleFunc("/repos/o/r/pulls/1/reviews", func(w http.ResponseWriter, r *http.Request) {
   473  		v := new(PullRequestReviewRequest)
   474  		assertNilError(t, json.NewDecoder(r.Body).Decode(v))
   475  
   476  		testMethod(t, r, "POST")
   477  		if !cmp.Equal(v, input) {
   478  			t.Errorf("Request body = %+v, want %+v", v, input)
   479  		}
   480  
   481  		fmt.Fprint(w, `{"id":1}`)
   482  	})
   483  
   484  	ctx := context.Background()
   485  
   486  	_, _, err := client.PullRequests.CreateReview(ctx, "o", "r", 1, input)
   487  	if err != nil {
   488  		t.Errorf("CreateReview addHeader err = %v, want nil", err)
   489  	}
   490  }
   491  
   492  func TestPullRequestsService_UpdateReview(t *testing.T) {
   493  	t.Parallel()
   494  	client, mux, _ := setup(t)
   495  
   496  	mux.HandleFunc("/repos/o/r/pulls/1/reviews/1", func(w http.ResponseWriter, r *http.Request) {
   497  		testMethod(t, r, "PUT")
   498  		fmt.Fprintf(w, `{"id":1}`)
   499  	})
   500  
   501  	ctx := context.Background()
   502  	got, _, err := client.PullRequests.UpdateReview(ctx, "o", "r", 1, 1, "updated_body")
   503  	if err != nil {
   504  		t.Errorf("PullRequests.UpdateReview returned error: %v", err)
   505  	}
   506  
   507  	want := &PullRequestReview{ID: Ptr(int64(1))}
   508  	if !cmp.Equal(got, want) {
   509  		t.Errorf("PullRequests.UpdateReview = %+v, want %+v", got, want)
   510  	}
   511  
   512  	const methodName = "UpdateReview"
   513  	testBadOptions(t, methodName, func() (err error) {
   514  		_, _, err = client.PullRequests.UpdateReview(ctx, "\n", "\n", -1, -1, "updated_body")
   515  		return err
   516  	})
   517  
   518  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   519  		got, resp, err := client.PullRequests.UpdateReview(ctx, "o", "r", 1, 1, "updated_body")
   520  		if got != nil {
   521  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   522  		}
   523  		return resp, err
   524  	})
   525  }
   526  
   527  func TestPullRequestsService_SubmitReview(t *testing.T) {
   528  	t.Parallel()
   529  	client, mux, _ := setup(t)
   530  
   531  	input := &PullRequestReviewRequest{
   532  		Body:  Ptr("b"),
   533  		Event: Ptr("APPROVE"),
   534  	}
   535  
   536  	mux.HandleFunc("/repos/o/r/pulls/1/reviews/1/events", func(w http.ResponseWriter, r *http.Request) {
   537  		v := new(PullRequestReviewRequest)
   538  		assertNilError(t, json.NewDecoder(r.Body).Decode(v))
   539  
   540  		testMethod(t, r, "POST")
   541  		if !cmp.Equal(v, input) {
   542  			t.Errorf("Request body = %+v, want %+v", v, input)
   543  		}
   544  
   545  		fmt.Fprint(w, `{"id":1}`)
   546  	})
   547  
   548  	ctx := context.Background()
   549  	review, _, err := client.PullRequests.SubmitReview(ctx, "o", "r", 1, 1, input)
   550  	if err != nil {
   551  		t.Errorf("PullRequests.SubmitReview returned error: %v", err)
   552  	}
   553  
   554  	want := &PullRequestReview{ID: Ptr(int64(1))}
   555  	if !cmp.Equal(review, want) {
   556  		t.Errorf("PullRequests.SubmitReview returned %+v, want %+v", review, want)
   557  	}
   558  
   559  	const methodName = "SubmitReview"
   560  	testBadOptions(t, methodName, func() (err error) {
   561  		_, _, err = client.PullRequests.SubmitReview(ctx, "\n", "\n", -1, -1, input)
   562  		return err
   563  	})
   564  
   565  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   566  		got, resp, err := client.PullRequests.SubmitReview(ctx, "o", "r", 1, 1, input)
   567  		if got != nil {
   568  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   569  		}
   570  		return resp, err
   571  	})
   572  }
   573  
   574  func TestPullRequestsService_SubmitReview_invalidOwner(t *testing.T) {
   575  	t.Parallel()
   576  	client, _, _ := setup(t)
   577  
   578  	ctx := context.Background()
   579  	_, _, err := client.PullRequests.SubmitReview(ctx, "%", "r", 1, 1, &PullRequestReviewRequest{})
   580  	testURLParseError(t, err)
   581  }
   582  
   583  func TestPullRequestsService_DismissReview(t *testing.T) {
   584  	t.Parallel()
   585  	client, mux, _ := setup(t)
   586  
   587  	input := &PullRequestReviewDismissalRequest{Message: Ptr("m")}
   588  
   589  	mux.HandleFunc("/repos/o/r/pulls/1/reviews/1/dismissals", func(w http.ResponseWriter, r *http.Request) {
   590  		v := new(PullRequestReviewDismissalRequest)
   591  		assertNilError(t, json.NewDecoder(r.Body).Decode(v))
   592  
   593  		testMethod(t, r, "PUT")
   594  		if !cmp.Equal(v, input) {
   595  			t.Errorf("Request body = %+v, want %+v", v, input)
   596  		}
   597  
   598  		fmt.Fprint(w, `{"id":1}`)
   599  	})
   600  
   601  	ctx := context.Background()
   602  	review, _, err := client.PullRequests.DismissReview(ctx, "o", "r", 1, 1, input)
   603  	if err != nil {
   604  		t.Errorf("PullRequests.DismissReview returned error: %v", err)
   605  	}
   606  
   607  	want := &PullRequestReview{ID: Ptr(int64(1))}
   608  	if !cmp.Equal(review, want) {
   609  		t.Errorf("PullRequests.DismissReview returned %+v, want %+v", review, want)
   610  	}
   611  
   612  	const methodName = "ListReviews"
   613  	testBadOptions(t, methodName, func() (err error) {
   614  		_, _, err = client.PullRequests.DismissReview(ctx, "\n", "\n", -1, -1, input)
   615  		return err
   616  	})
   617  
   618  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   619  		got, resp, err := client.PullRequests.DismissReview(ctx, "o", "r", 1, 1, input)
   620  		if got != nil {
   621  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   622  		}
   623  		return resp, err
   624  	})
   625  }
   626  
   627  func TestPullRequestsService_DismissReview_invalidOwner(t *testing.T) {
   628  	t.Parallel()
   629  	client, _, _ := setup(t)
   630  
   631  	ctx := context.Background()
   632  	_, _, err := client.PullRequests.DismissReview(ctx, "%", "r", 1, 1, &PullRequestReviewDismissalRequest{})
   633  	testURLParseError(t, err)
   634  }
   635  
   636  func TestPullRequestReviewDismissalRequest_Marshal(t *testing.T) {
   637  	t.Parallel()
   638  	testJSONMarshal(t, &PullRequestReviewDismissalRequest{}, "{}")
   639  
   640  	u := &PullRequestReviewDismissalRequest{
   641  		Message: Ptr("msg"),
   642  	}
   643  
   644  	want := `{
   645  		"message": "msg"
   646  	}`
   647  
   648  	testJSONMarshal(t, u, want)
   649  }
   650  
   651  func TestDraftReviewComment_Marshal(t *testing.T) {
   652  	t.Parallel()
   653  	testJSONMarshal(t, &DraftReviewComment{}, "{}")
   654  
   655  	u := &DraftReviewComment{
   656  		Path:      Ptr("path"),
   657  		Position:  Ptr(1),
   658  		Body:      Ptr("body"),
   659  		StartSide: Ptr("ss"),
   660  		Side:      Ptr("side"),
   661  		StartLine: Ptr(1),
   662  		Line:      Ptr(1),
   663  	}
   664  
   665  	want := `{
   666  		"path": "path",
   667  		"position": 1,
   668  		"body": "body",
   669  		"start_side": "ss",
   670  		"side": "side",
   671  		"start_line": 1,
   672  		"line": 1
   673  	}`
   674  
   675  	testJSONMarshal(t, u, want)
   676  }
   677  
   678  func TestPullRequestReviewRequest_Marshal(t *testing.T) {
   679  	t.Parallel()
   680  	testJSONMarshal(t, &PullRequestReviewRequest{}, "{}")
   681  
   682  	u := &PullRequestReviewRequest{
   683  		NodeID:   Ptr("nodeid"),
   684  		CommitID: Ptr("cid"),
   685  		Body:     Ptr("body"),
   686  		Event:    Ptr("event"),
   687  		Comments: []*DraftReviewComment{
   688  			{
   689  				Path:      Ptr("path"),
   690  				Position:  Ptr(1),
   691  				Body:      Ptr("body"),
   692  				StartSide: Ptr("ss"),
   693  				Side:      Ptr("side"),
   694  				StartLine: Ptr(1),
   695  				Line:      Ptr(1),
   696  			},
   697  		},
   698  	}
   699  
   700  	want := `{
   701  		"node_id": "nodeid",
   702  		"commit_id": "cid",
   703  		"body": "body",
   704  		"event": "event",
   705  		"comments": [
   706  			{
   707  				"path": "path",
   708  				"position": 1,
   709  				"body": "body",
   710  				"start_side": "ss",
   711  				"side": "side",
   712  				"start_line": 1,
   713  				"line": 1
   714  			}
   715  		]
   716  	}`
   717  
   718  	testJSONMarshal(t, u, want)
   719  }
   720  
   721  func TestPullRequestReview_Marshal(t *testing.T) {
   722  	t.Parallel()
   723  	testJSONMarshal(t, &PullRequestReview{}, "{}")
   724  
   725  	u := &PullRequestReview{
   726  		ID:     Ptr(int64(1)),
   727  		NodeID: Ptr("nid"),
   728  		User: &User{
   729  			Login:           Ptr("l"),
   730  			ID:              Ptr(int64(1)),
   731  			URL:             Ptr("u"),
   732  			AvatarURL:       Ptr("a"),
   733  			GravatarID:      Ptr("g"),
   734  			Name:            Ptr("n"),
   735  			Company:         Ptr("c"),
   736  			Blog:            Ptr("b"),
   737  			Location:        Ptr("l"),
   738  			Email:           Ptr("e"),
   739  			Hireable:        Ptr(true),
   740  			Bio:             Ptr("b"),
   741  			TwitterUsername: Ptr("t"),
   742  			PublicRepos:     Ptr(1),
   743  			Followers:       Ptr(1),
   744  			Following:       Ptr(1),
   745  			CreatedAt:       &Timestamp{referenceTime},
   746  			SuspendedAt:     &Timestamp{referenceTime},
   747  		},
   748  		Body:              Ptr("body"),
   749  		SubmittedAt:       &Timestamp{referenceTime},
   750  		CommitID:          Ptr("cid"),
   751  		HTMLURL:           Ptr("hurl"),
   752  		PullRequestURL:    Ptr("prurl"),
   753  		State:             Ptr("state"),
   754  		AuthorAssociation: Ptr("aa"),
   755  	}
   756  
   757  	want := `{
   758  		"id": 1,
   759  		"node_id": "nid",
   760  		"user": {
   761  			"login": "l",
   762  			"id": 1,
   763  			"avatar_url": "a",
   764  			"gravatar_id": "g",
   765  			"name": "n",
   766  			"company": "c",
   767  			"blog": "b",
   768  			"location": "l",
   769  			"email": "e",
   770  			"hireable": true,
   771  			"bio": "b",
   772  			"twitter_username": "t",
   773  			"public_repos": 1,
   774  			"followers": 1,
   775  			"following": 1,
   776  			"created_at": ` + referenceTimeStr + `,
   777  			"suspended_at": ` + referenceTimeStr + `,
   778  			"url": "u"
   779  		},
   780  		"body": "body",
   781  		"submitted_at": ` + referenceTimeStr + `,
   782  		"commit_id": "cid",
   783  		"html_url": "hurl",
   784  		"pull_request_url": "prurl",
   785  		"state": "state",
   786  		"author_association": "aa"
   787  	}`
   788  
   789  	testJSONMarshal(t, u, want)
   790  }