github.com/google/go-github/v57@v57.0.0/github/repos_commits_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  	"fmt"
    11  	"net/http"
    12  	"net/url"
    13  	"strings"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/google/go-cmp/cmp"
    18  )
    19  
    20  func TestRepositoriesService_ListCommits(t *testing.T) {
    21  	client, mux, _, teardown := setup()
    22  	defer teardown()
    23  
    24  	// given
    25  	mux.HandleFunc("/repos/o/r/commits", func(w http.ResponseWriter, r *http.Request) {
    26  		testMethod(t, r, "GET")
    27  		testFormValues(t, r,
    28  			values{
    29  				"sha":    "s",
    30  				"path":   "p",
    31  				"author": "a",
    32  				"since":  "2013-08-01T00:00:00Z",
    33  				"until":  "2013-09-03T00:00:00Z",
    34  			})
    35  		fmt.Fprintf(w, `[{"sha": "s"}]`)
    36  	})
    37  
    38  	opt := &CommitsListOptions{
    39  		SHA:    "s",
    40  		Path:   "p",
    41  		Author: "a",
    42  		Since:  time.Date(2013, time.August, 1, 0, 0, 0, 0, time.UTC),
    43  		Until:  time.Date(2013, time.September, 3, 0, 0, 0, 0, time.UTC),
    44  	}
    45  	ctx := context.Background()
    46  	commits, _, err := client.Repositories.ListCommits(ctx, "o", "r", opt)
    47  	if err != nil {
    48  		t.Errorf("Repositories.ListCommits returned error: %v", err)
    49  	}
    50  
    51  	want := []*RepositoryCommit{{SHA: String("s")}}
    52  	if !cmp.Equal(commits, want) {
    53  		t.Errorf("Repositories.ListCommits returned %+v, want %+v", commits, want)
    54  	}
    55  
    56  	const methodName = "ListCommits"
    57  	testBadOptions(t, methodName, func() (err error) {
    58  		_, _, err = client.Repositories.ListCommits(ctx, "\n", "\n", opt)
    59  		return err
    60  	})
    61  
    62  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
    63  		got, resp, err := client.Repositories.ListCommits(ctx, "o", "r", opt)
    64  		if got != nil {
    65  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
    66  		}
    67  		return resp, err
    68  	})
    69  }
    70  
    71  func TestRepositoriesService_GetCommit(t *testing.T) {
    72  	client, mux, _, teardown := setup()
    73  	defer teardown()
    74  
    75  	mux.HandleFunc("/repos/o/r/commits/s", func(w http.ResponseWriter, r *http.Request) {
    76  		testMethod(t, r, "GET")
    77  		testFormValues(t, r, values{"per_page": "2", "page": "2"})
    78  		fmt.Fprintf(w, `{
    79  		  "sha": "s",
    80  		  "commit": { "message": "m" },
    81  		  "author": { "login": "l" },
    82  		  "committer": { "login": "l" },
    83  		  "parents": [ { "sha": "s" } ],
    84  		  "stats": { "additions": 104, "deletions": 4, "total": 108 },
    85  		  "files": [
    86  		    {
    87  		      "filename": "f",
    88  		      "additions": 10,
    89  		      "deletions": 2,
    90  		      "changes": 12,
    91  		      "status": "s",
    92  		      "patch": "p",
    93  		      "blob_url": "b",
    94  		      "raw_url": "r",
    95  		      "contents_url": "c"
    96  		    }
    97  		  ]
    98  		}`)
    99  	})
   100  
   101  	opts := &ListOptions{Page: 2, PerPage: 2}
   102  	ctx := context.Background()
   103  	commit, _, err := client.Repositories.GetCommit(ctx, "o", "r", "s", opts)
   104  	if err != nil {
   105  		t.Errorf("Repositories.GetCommit returned error: %v", err)
   106  	}
   107  
   108  	want := &RepositoryCommit{
   109  		SHA: String("s"),
   110  		Commit: &Commit{
   111  			Message: String("m"),
   112  		},
   113  		Author: &User{
   114  			Login: String("l"),
   115  		},
   116  		Committer: &User{
   117  			Login: String("l"),
   118  		},
   119  		Parents: []*Commit{
   120  			{
   121  				SHA: String("s"),
   122  			},
   123  		},
   124  		Stats: &CommitStats{
   125  			Additions: Int(104),
   126  			Deletions: Int(4),
   127  			Total:     Int(108),
   128  		},
   129  		Files: []*CommitFile{
   130  			{
   131  				Filename:    String("f"),
   132  				Additions:   Int(10),
   133  				Deletions:   Int(2),
   134  				Changes:     Int(12),
   135  				Status:      String("s"),
   136  				Patch:       String("p"),
   137  				BlobURL:     String("b"),
   138  				RawURL:      String("r"),
   139  				ContentsURL: String("c"),
   140  			},
   141  		},
   142  	}
   143  	if !cmp.Equal(commit, want) {
   144  		t.Errorf("Repositories.GetCommit returned \n%+v, want \n%+v", commit, want)
   145  	}
   146  
   147  	const methodName = "GetCommit"
   148  	testBadOptions(t, methodName, func() (err error) {
   149  		_, _, err = client.Repositories.GetCommit(ctx, "\n", "\n", "\n", opts)
   150  		return err
   151  	})
   152  
   153  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   154  		got, resp, err := client.Repositories.GetCommit(ctx, "o", "r", "s", opts)
   155  		if got != nil {
   156  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   157  		}
   158  		return resp, err
   159  	})
   160  }
   161  
   162  func TestRepositoriesService_GetCommitRaw_diff(t *testing.T) {
   163  	client, mux, _, teardown := setup()
   164  	defer teardown()
   165  
   166  	const rawStr = "@@diff content"
   167  
   168  	mux.HandleFunc("/repos/o/r/commits/s", func(w http.ResponseWriter, r *http.Request) {
   169  		testMethod(t, r, "GET")
   170  		testHeader(t, r, "Accept", mediaTypeV3Diff)
   171  		fmt.Fprint(w, rawStr)
   172  	})
   173  
   174  	ctx := context.Background()
   175  	got, _, err := client.Repositories.GetCommitRaw(ctx, "o", "r", "s", RawOptions{Type: Diff})
   176  	if err != nil {
   177  		t.Fatalf("Repositories.GetCommitRaw returned error: %v", err)
   178  	}
   179  	want := rawStr
   180  	if got != want {
   181  		t.Errorf("Repositories.GetCommitRaw returned %s want %s", got, want)
   182  	}
   183  
   184  	const methodName = "GetCommitRaw"
   185  	testBadOptions(t, methodName, func() (err error) {
   186  		_, _, err = client.Repositories.GetCommitRaw(ctx, "\n", "\n", "\n", RawOptions{Type: Diff})
   187  		return err
   188  	})
   189  
   190  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   191  		got, resp, err := client.Repositories.GetCommitRaw(ctx, "o", "r", "s", RawOptions{Type: Diff})
   192  		if got != "" {
   193  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want ''", methodName, got)
   194  		}
   195  		return resp, err
   196  	})
   197  }
   198  
   199  func TestRepositoriesService_GetCommitRaw_patch(t *testing.T) {
   200  	client, mux, _, teardown := setup()
   201  	defer teardown()
   202  
   203  	const rawStr = "@@patch content"
   204  
   205  	mux.HandleFunc("/repos/o/r/commits/s", func(w http.ResponseWriter, r *http.Request) {
   206  		testMethod(t, r, "GET")
   207  		testHeader(t, r, "Accept", mediaTypeV3Patch)
   208  		fmt.Fprint(w, rawStr)
   209  	})
   210  
   211  	ctx := context.Background()
   212  	got, _, err := client.Repositories.GetCommitRaw(ctx, "o", "r", "s", RawOptions{Type: Patch})
   213  	if err != nil {
   214  		t.Fatalf("Repositories.GetCommitRaw returned error: %v", err)
   215  	}
   216  	want := rawStr
   217  	if got != want {
   218  		t.Errorf("Repositories.GetCommitRaw returned %s want %s", got, want)
   219  	}
   220  }
   221  
   222  func TestRepositoriesService_GetCommitRaw_invalid(t *testing.T) {
   223  	client, _, _, teardown := setup()
   224  	defer teardown()
   225  
   226  	ctx := context.Background()
   227  	_, _, err := client.Repositories.GetCommitRaw(ctx, "o", "r", "s", RawOptions{100})
   228  	if err == nil {
   229  		t.Fatal("Repositories.GetCommitRaw should return error")
   230  	}
   231  	if !strings.Contains(err.Error(), "unsupported raw type") {
   232  		t.Error("Repositories.GetCommitRaw should return unsupported raw type error")
   233  	}
   234  }
   235  
   236  func TestRepositoriesService_GetCommitSHA1(t *testing.T) {
   237  	client, mux, _, teardown := setup()
   238  	defer teardown()
   239  	const sha1 = "01234abcde"
   240  
   241  	mux.HandleFunc("/repos/o/r/commits/master", func(w http.ResponseWriter, r *http.Request) {
   242  		testMethod(t, r, "GET")
   243  		testHeader(t, r, "Accept", mediaTypeV3SHA)
   244  
   245  		fmt.Fprint(w, sha1)
   246  	})
   247  
   248  	ctx := context.Background()
   249  	got, _, err := client.Repositories.GetCommitSHA1(ctx, "o", "r", "master", "")
   250  	if err != nil {
   251  		t.Errorf("Repositories.GetCommitSHA1 returned error: %v", err)
   252  	}
   253  
   254  	want := sha1
   255  	if got != want {
   256  		t.Errorf("Repositories.GetCommitSHA1 = %v, want %v", got, want)
   257  	}
   258  
   259  	mux.HandleFunc("/repos/o/r/commits/tag", func(w http.ResponseWriter, r *http.Request) {
   260  		testMethod(t, r, "GET")
   261  		testHeader(t, r, "Accept", mediaTypeV3SHA)
   262  		testHeader(t, r, "If-None-Match", `"`+sha1+`"`)
   263  
   264  		w.WriteHeader(http.StatusNotModified)
   265  	})
   266  
   267  	got, _, err = client.Repositories.GetCommitSHA1(ctx, "o", "r", "tag", sha1)
   268  	if err == nil {
   269  		t.Errorf("Expected HTTP 304 response")
   270  	}
   271  
   272  	want = ""
   273  	if got != want {
   274  		t.Errorf("Repositories.GetCommitSHA1 = %v, want %v", got, want)
   275  	}
   276  
   277  	const methodName = "GetCommitSHA1"
   278  	testBadOptions(t, methodName, func() (err error) {
   279  		_, _, err = client.Repositories.GetCommitSHA1(ctx, "\n", "\n", "\n", "\n")
   280  		return err
   281  	})
   282  
   283  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   284  		got, resp, err := client.Repositories.GetCommitSHA1(ctx, "o", "r", "master", "")
   285  		if got != "" {
   286  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want ''", methodName, got)
   287  		}
   288  		return resp, err
   289  	})
   290  }
   291  
   292  func TestRepositoriesService_NonAlphabetCharacter_GetCommitSHA1(t *testing.T) {
   293  	client, mux, _, teardown := setup()
   294  	defer teardown()
   295  	const sha1 = "01234abcde"
   296  
   297  	mux.HandleFunc("/repos/o/r/commits/master%20hash", func(w http.ResponseWriter, r *http.Request) {
   298  		testMethod(t, r, "GET")
   299  		testHeader(t, r, "Accept", mediaTypeV3SHA)
   300  
   301  		fmt.Fprint(w, sha1)
   302  	})
   303  
   304  	ctx := context.Background()
   305  	got, _, err := client.Repositories.GetCommitSHA1(ctx, "o", "r", "master%20hash", "")
   306  	if err != nil {
   307  		t.Errorf("Repositories.GetCommitSHA1 returned error: %v", err)
   308  	}
   309  
   310  	if want := sha1; got != want {
   311  		t.Errorf("Repositories.GetCommitSHA1 = %v, want %v", got, want)
   312  	}
   313  
   314  	mux.HandleFunc("/repos/o/r/commits/tag", func(w http.ResponseWriter, r *http.Request) {
   315  		testMethod(t, r, "GET")
   316  		testHeader(t, r, "Accept", mediaTypeV3SHA)
   317  		testHeader(t, r, "If-None-Match", `"`+sha1+`"`)
   318  
   319  		w.WriteHeader(http.StatusNotModified)
   320  	})
   321  
   322  	got, _, err = client.Repositories.GetCommitSHA1(ctx, "o", "r", "tag", sha1)
   323  	if err == nil {
   324  		t.Errorf("Expected HTTP 304 response")
   325  	}
   326  
   327  	if want := ""; got != want {
   328  		t.Errorf("Repositories.GetCommitSHA1 = %v, want %v", got, want)
   329  	}
   330  }
   331  
   332  func TestRepositoriesService_TrailingPercent_GetCommitSHA1(t *testing.T) {
   333  	client, mux, _, teardown := setup()
   334  	defer teardown()
   335  	const sha1 = "01234abcde"
   336  
   337  	mux.HandleFunc("/repos/o/r/commits/comm%", func(w http.ResponseWriter, r *http.Request) {
   338  		testMethod(t, r, "GET")
   339  		testHeader(t, r, "Accept", mediaTypeV3SHA)
   340  
   341  		fmt.Fprint(w, sha1)
   342  	})
   343  
   344  	ctx := context.Background()
   345  	got, _, err := client.Repositories.GetCommitSHA1(ctx, "o", "r", "comm%", "")
   346  	if err != nil {
   347  		t.Errorf("Repositories.GetCommitSHA1 returned error: %v", err)
   348  	}
   349  
   350  	if want := sha1; got != want {
   351  		t.Errorf("Repositories.GetCommitSHA1 = %v, want %v", got, want)
   352  	}
   353  
   354  	mux.HandleFunc("/repos/o/r/commits/tag", func(w http.ResponseWriter, r *http.Request) {
   355  		testMethod(t, r, "GET")
   356  		testHeader(t, r, "Accept", mediaTypeV3SHA)
   357  		testHeader(t, r, "If-None-Match", `"`+sha1+`"`)
   358  
   359  		w.WriteHeader(http.StatusNotModified)
   360  	})
   361  
   362  	got, _, err = client.Repositories.GetCommitSHA1(ctx, "o", "r", "tag", sha1)
   363  	if err == nil {
   364  		t.Errorf("Expected HTTP 304 response")
   365  	}
   366  
   367  	if want := ""; got != want {
   368  		t.Errorf("Repositories.GetCommitSHA1 = %v, want %v", got, want)
   369  	}
   370  }
   371  
   372  func TestRepositoriesService_CompareCommits(t *testing.T) {
   373  	testCases := []struct {
   374  		base string
   375  		head string
   376  	}{
   377  		{base: "b", head: "h"},
   378  		{base: "123base", head: "head123"},
   379  		{base: "`~!@#$%^&*()_+-=[]\\{}|;':\",./<>?/*-+123base", head: "head123`~!@#$%^&*()_+-=[]\\{}|;':\",./<>?/*-+"},
   380  	}
   381  
   382  	for _, sample := range testCases {
   383  		client, mux, _, teardown := setup()
   384  
   385  		base := sample.base
   386  		head := sample.head
   387  		escapedBase := url.QueryEscape(base)
   388  		escapedHead := url.QueryEscape(head)
   389  
   390  		pattern := fmt.Sprintf("/repos/o/r/compare/%v...%v", base, head)
   391  
   392  		mux.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
   393  			testMethod(t, r, "GET")
   394  			testFormValues(t, r, values{"per_page": "2", "page": "2"})
   395  			fmt.Fprintf(w, `{
   396  		  "base_commit": {
   397  		    "sha": "s",
   398  		    "commit": {
   399  		      "author": { "name": "n" },
   400  		      "committer": { "name": "n" },
   401  		      "message": "m",
   402  		      "tree": { "sha": "t" }
   403  		    },
   404  		    "author": { "login": "l" },
   405  		    "committer": { "login": "l" },
   406  		    "parents": [ { "sha": "s" } ]
   407  		  },
   408  		  "status": "s",
   409  		  "ahead_by": 1,
   410  		  "behind_by": 2,
   411  		  "total_commits": 1,
   412  		  "commits": [
   413  		    {
   414  		      "sha": "s",
   415  		      "commit": { "author": { "name": "n" } },
   416  		      "author": { "login": "l" },
   417  		      "committer": { "login": "l" },
   418  		      "parents": [ { "sha": "s" } ]
   419  		    }
   420  		  ],
   421  		  "files": [ { "filename": "f" } ],
   422  		  "html_url":      "https://github.com/o/r/compare/%[1]v...%[2]v",
   423  		  "permalink_url": "https://github.com/o/r/compare/o:bbcd538c8e72b8c175046e27cc8f907076331401...o:0328041d1152db8ae77652d1618a02e57f745f17",
   424  		  "diff_url":      "https://github.com/o/r/compare/%[1]v...%[2]v.diff",
   425  		  "patch_url":     "https://github.com/o/r/compare/%[1]v...%[2]v.patch",
   426  		  "url":           "https://api.github.com/repos/o/r/compare/%[1]v...%[2]v"
   427  		}`, escapedBase, escapedHead)
   428  		})
   429  
   430  		opts := &ListOptions{Page: 2, PerPage: 2}
   431  		ctx := context.Background()
   432  		got, _, err := client.Repositories.CompareCommits(ctx, "o", "r", base, head, opts)
   433  		if err != nil {
   434  			t.Errorf("Repositories.CompareCommits returned error: %v", err)
   435  		}
   436  
   437  		want := &CommitsComparison{
   438  			BaseCommit: &RepositoryCommit{
   439  				SHA: String("s"),
   440  				Commit: &Commit{
   441  					Author:    &CommitAuthor{Name: String("n")},
   442  					Committer: &CommitAuthor{Name: String("n")},
   443  					Message:   String("m"),
   444  					Tree:      &Tree{SHA: String("t")},
   445  				},
   446  				Author:    &User{Login: String("l")},
   447  				Committer: &User{Login: String("l")},
   448  				Parents: []*Commit{
   449  					{
   450  						SHA: String("s"),
   451  					},
   452  				},
   453  			},
   454  			Status:       String("s"),
   455  			AheadBy:      Int(1),
   456  			BehindBy:     Int(2),
   457  			TotalCommits: Int(1),
   458  			Commits: []*RepositoryCommit{
   459  				{
   460  					SHA: String("s"),
   461  					Commit: &Commit{
   462  						Author: &CommitAuthor{Name: String("n")},
   463  					},
   464  					Author:    &User{Login: String("l")},
   465  					Committer: &User{Login: String("l")},
   466  					Parents: []*Commit{
   467  						{
   468  							SHA: String("s"),
   469  						},
   470  					},
   471  				},
   472  			},
   473  			Files: []*CommitFile{
   474  				{
   475  					Filename: String("f"),
   476  				},
   477  			},
   478  			HTMLURL:      String(fmt.Sprintf("https://github.com/o/r/compare/%v...%v", escapedBase, escapedHead)),
   479  			PermalinkURL: String("https://github.com/o/r/compare/o:bbcd538c8e72b8c175046e27cc8f907076331401...o:0328041d1152db8ae77652d1618a02e57f745f17"),
   480  			DiffURL:      String(fmt.Sprintf("https://github.com/o/r/compare/%v...%v.diff", escapedBase, escapedHead)),
   481  			PatchURL:     String(fmt.Sprintf("https://github.com/o/r/compare/%v...%v.patch", escapedBase, escapedHead)),
   482  			URL:          String(fmt.Sprintf("https://api.github.com/repos/o/r/compare/%v...%v", escapedBase, escapedHead)),
   483  		}
   484  
   485  		if !cmp.Equal(got, want) {
   486  			t.Errorf("Repositories.CompareCommits returned \n%+v, want \n%+v", got, want)
   487  		}
   488  
   489  		const methodName = "CompareCommits"
   490  		testBadOptions(t, methodName, func() (err error) {
   491  			_, _, err = client.Repositories.CompareCommits(ctx, "\n", "\n", "\n", "\n", opts)
   492  			return err
   493  		})
   494  
   495  		testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   496  			got, resp, err := client.Repositories.CompareCommits(ctx, "o", "r", base, head, opts)
   497  			if got != nil {
   498  				t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   499  			}
   500  			return resp, err
   501  		})
   502  
   503  		teardown()
   504  	}
   505  }
   506  
   507  func TestRepositoriesService_CompareCommitsRaw_diff(t *testing.T) {
   508  	testCases := []struct {
   509  		base string
   510  		head string
   511  	}{
   512  		{base: "b", head: "h"},
   513  		{base: "123base", head: "head123"},
   514  		{base: "`~!@#$%^&*()_+-=[]\\{}|;':\",./<>?/*-+123base", head: "head123`~!@#$%^&*()_+-=[]\\{}|;':\",./<>?/*-+"},
   515  	}
   516  
   517  	for _, sample := range testCases {
   518  		client, mux, _, teardown := setup()
   519  
   520  		base := sample.base
   521  		head := sample.head
   522  		pattern := fmt.Sprintf("/repos/o/r/compare/%v...%v", base, head)
   523  		const rawStr = "@@diff content"
   524  
   525  		mux.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
   526  			testMethod(t, r, "GET")
   527  			testHeader(t, r, "Accept", mediaTypeV3Diff)
   528  			fmt.Fprint(w, rawStr)
   529  		})
   530  
   531  		ctx := context.Background()
   532  		got, _, err := client.Repositories.CompareCommitsRaw(ctx, "o", "r", base, head, RawOptions{Type: Diff})
   533  		if err != nil {
   534  			t.Fatalf("Repositories.GetCommitRaw returned error: %v", err)
   535  		}
   536  		want := rawStr
   537  		if got != want {
   538  			t.Errorf("Repositories.GetCommitRaw returned %s want %s", got, want)
   539  		}
   540  
   541  		const methodName = "CompareCommitsRaw"
   542  		testBadOptions(t, methodName, func() (err error) {
   543  			_, _, err = client.Repositories.CompareCommitsRaw(ctx, "\n", "\n", "\n", "\n", RawOptions{Type: Diff})
   544  			return err
   545  		})
   546  
   547  		testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   548  			got, resp, err := client.Repositories.CompareCommitsRaw(ctx, "o", "r", base, head, RawOptions{Type: Diff})
   549  			if got != "" {
   550  				t.Errorf("testNewRequestAndDoFailure %v = %#v, want ''", methodName, got)
   551  			}
   552  			return resp, err
   553  		})
   554  
   555  		teardown()
   556  	}
   557  }
   558  
   559  func TestRepositoriesService_CompareCommitsRaw_patch(t *testing.T) {
   560  	testCases := []struct {
   561  		base string
   562  		head string
   563  	}{
   564  		{base: "b", head: "h"},
   565  		{base: "123base", head: "head123"},
   566  		{base: "`~!@#$%^&*()_+-=[]\\{}|;':\",./<>?/*-+123base", head: "head123`~!@#$%^&*()_+-=[]\\{}|;':\",./<>?/*-+"},
   567  	}
   568  
   569  	for _, sample := range testCases {
   570  		client, mux, _, teardown := setup()
   571  
   572  		base := sample.base
   573  		head := sample.head
   574  		pattern := fmt.Sprintf("/repos/o/r/compare/%v...%v", base, head)
   575  		const rawStr = "@@patch content"
   576  
   577  		mux.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
   578  			testMethod(t, r, "GET")
   579  			testHeader(t, r, "Accept", mediaTypeV3Patch)
   580  			fmt.Fprint(w, rawStr)
   581  		})
   582  
   583  		ctx := context.Background()
   584  		got, _, err := client.Repositories.CompareCommitsRaw(ctx, "o", "r", base, head, RawOptions{Type: Patch})
   585  		if err != nil {
   586  			t.Fatalf("Repositories.GetCommitRaw returned error: %v", err)
   587  		}
   588  		want := rawStr
   589  		if got != want {
   590  			t.Errorf("Repositories.GetCommitRaw returned %s want %s", got, want)
   591  		}
   592  
   593  		teardown()
   594  	}
   595  }
   596  
   597  func TestRepositoriesService_CompareCommitsRaw_invalid(t *testing.T) {
   598  	ctx := context.Background()
   599  
   600  	testCases := []struct {
   601  		base string
   602  		head string
   603  	}{
   604  		{base: "b", head: "h"},
   605  		{base: "123base", head: "head123"},
   606  		{base: "`~!@#$%^&*()_+-=[]\\{}|;':\",./<>?/*-+123base", head: "head123`~!@#$%^&*()_+-=[]\\{}|;':\",./<>?/*-+"},
   607  	}
   608  
   609  	for _, sample := range testCases {
   610  		client, _, _, teardown := setup()
   611  		_, _, err := client.Repositories.CompareCommitsRaw(ctx, "o", "r", sample.base, sample.head, RawOptions{100})
   612  		if err == nil {
   613  			t.Fatal("Repositories.GetCommitRaw should return error")
   614  		}
   615  		if !strings.Contains(err.Error(), "unsupported raw type") {
   616  			t.Error("Repositories.GetCommitRaw should return unsupported raw type error")
   617  		}
   618  		teardown()
   619  	}
   620  }
   621  
   622  func TestRepositoriesService_ListBranchesHeadCommit(t *testing.T) {
   623  	client, mux, _, teardown := setup()
   624  	defer teardown()
   625  
   626  	mux.HandleFunc("/repos/o/r/commits/s/branches-where-head", func(w http.ResponseWriter, r *http.Request) {
   627  		testMethod(t, r, "GET")
   628  		fmt.Fprintf(w, `[{"name": "b","commit":{"sha":"2e90302801c870f17b6152327d9b9a03c8eca0e2","url":"https://api.github.com/repos/google/go-github/commits/2e90302801c870f17b6152327d9b9a03c8eca0e2"},"protected":true}]`)
   629  	})
   630  
   631  	ctx := context.Background()
   632  	branches, _, err := client.Repositories.ListBranchesHeadCommit(ctx, "o", "r", "s")
   633  	if err != nil {
   634  		t.Errorf("Repositories.ListBranchesHeadCommit returned error: %v", err)
   635  	}
   636  
   637  	want := []*BranchCommit{
   638  		{
   639  			Name: String("b"),
   640  			Commit: &Commit{
   641  				SHA: String("2e90302801c870f17b6152327d9b9a03c8eca0e2"),
   642  				URL: String("https://api.github.com/repos/google/go-github/commits/2e90302801c870f17b6152327d9b9a03c8eca0e2"),
   643  			},
   644  			Protected: Bool(true),
   645  		},
   646  	}
   647  	if !cmp.Equal(branches, want) {
   648  		t.Errorf("Repositories.ListBranchesHeadCommit returned %+v, want %+v", branches, want)
   649  	}
   650  
   651  	const methodName = "ListBranchesHeadCommit"
   652  	testBadOptions(t, methodName, func() (err error) {
   653  		_, _, err = client.Repositories.ListBranchesHeadCommit(ctx, "\n", "\n", "\n")
   654  		return err
   655  	})
   656  
   657  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   658  		got, resp, err := client.Repositories.ListBranchesHeadCommit(ctx, "o", "r", "s")
   659  		if got != nil {
   660  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   661  		}
   662  		return resp, err
   663  	})
   664  }
   665  
   666  func TestBranchCommit_Marshal(t *testing.T) {
   667  	testJSONMarshal(t, &BranchCommit{}, "{}")
   668  
   669  	r := &BranchCommit{
   670  		Name: String("n"),
   671  		Commit: &Commit{
   672  			SHA: String("s"),
   673  			Author: &CommitAuthor{
   674  				Date:  &Timestamp{referenceTime},
   675  				Name:  String("n"),
   676  				Email: String("e"),
   677  				Login: String("u"),
   678  			},
   679  			Committer: &CommitAuthor{
   680  				Date:  &Timestamp{referenceTime},
   681  				Name:  String("n"),
   682  				Email: String("e"),
   683  				Login: String("u"),
   684  			},
   685  			Message: String("m"),
   686  			Tree: &Tree{
   687  				SHA: String("s"),
   688  				Entries: []*TreeEntry{{
   689  					SHA:     String("s"),
   690  					Path:    String("p"),
   691  					Mode:    String("m"),
   692  					Type:    String("t"),
   693  					Size:    Int(1),
   694  					Content: String("c"),
   695  					URL:     String("u"),
   696  				}},
   697  				Truncated: Bool(false),
   698  			},
   699  			Parents: nil,
   700  			Stats: &CommitStats{
   701  				Additions: Int(1),
   702  				Deletions: Int(1),
   703  				Total:     Int(1),
   704  			},
   705  			HTMLURL: String("h"),
   706  			URL:     String("u"),
   707  			Verification: &SignatureVerification{
   708  				Verified:  Bool(false),
   709  				Reason:    String("r"),
   710  				Signature: String("s"),
   711  				Payload:   String("p"),
   712  			},
   713  			NodeID:       String("n"),
   714  			CommentCount: Int(1),
   715  		},
   716  		Protected: Bool(false),
   717  	}
   718  
   719  	want := `{
   720  		"name": "n",
   721  		"commit": {
   722  			"sha": "s",
   723  			"author": {
   724  				"date": ` + referenceTimeStr + `,
   725  				"name": "n",
   726  				"email": "e",
   727  				"username": "u"
   728  			},
   729  			"committer": {
   730  				"date": ` + referenceTimeStr + `,
   731  				"name": "n",
   732  				"email": "e",
   733  				"username": "u"
   734  			},
   735  			"message": "m",
   736  			"tree": {
   737  				"sha": "s",
   738  				"tree": [
   739  					{
   740  						"sha": "s",
   741  						"path": "p",
   742  						"mode": "m",
   743  						"type": "t",
   744  						"size": 1,
   745  						"content": "c",
   746  						"url": "u"
   747  					}
   748  				],
   749  				"truncated": false
   750  			},
   751  			"stats": {
   752  				"additions": 1,
   753  				"deletions": 1,
   754  				"total": 1
   755  			},
   756  			"html_url": "h",
   757  			"url": "u",
   758  			"verification": {
   759  				"verified": false,
   760  				"reason": "r",
   761  				"signature": "s",
   762  				"payload": "p"
   763  			},
   764  			"node_id": "n",
   765  			"comment_count": 1
   766  		},
   767  		"protected": false
   768  	}`
   769  
   770  	testJSONMarshal(t, r, want)
   771  }
   772  
   773  func TestCommitsComparison_Marshal(t *testing.T) {
   774  	testJSONMarshal(t, &CommitsComparison{}, "{}")
   775  
   776  	r := &CommitsComparison{
   777  		BaseCommit:      &RepositoryCommit{NodeID: String("nid")},
   778  		MergeBaseCommit: &RepositoryCommit{NodeID: String("nid")},
   779  		Status:          String("status"),
   780  		AheadBy:         Int(1),
   781  		BehindBy:        Int(1),
   782  		TotalCommits:    Int(1),
   783  		Commits: []*RepositoryCommit{
   784  			{
   785  				NodeID: String("nid"),
   786  			},
   787  		},
   788  		Files: []*CommitFile{
   789  			{
   790  				SHA: String("sha"),
   791  			},
   792  		},
   793  		HTMLURL:      String("hurl"),
   794  		PermalinkURL: String("purl"),
   795  		DiffURL:      String("durl"),
   796  		PatchURL:     String("purl"),
   797  		URL:          String("url"),
   798  	}
   799  
   800  	want := `{
   801  		"base_commit": {
   802  			"node_id": "nid"
   803  		},
   804  		"merge_base_commit": {
   805  			"node_id": "nid"
   806  		},
   807  		"status": "status",
   808  		"ahead_by": 1,
   809  		"behind_by": 1,
   810  		"total_commits": 1,
   811  		"commits": [
   812  			{
   813  				"node_id": "nid"
   814  			}
   815  		],
   816  		"files": [
   817  			{
   818  				"sha": "sha"
   819  			}
   820  		],
   821  		"html_url": "hurl",
   822  		"permalink_url": "purl",
   823  		"diff_url": "durl",
   824  		"patch_url": "purl",
   825  		"url": "url"
   826  	}`
   827  
   828  	testJSONMarshal(t, r, want)
   829  }
   830  
   831  func TestCommitFile_Marshal(t *testing.T) {
   832  	testJSONMarshal(t, &CommitFile{}, "{}")
   833  
   834  	r := &CommitFile{
   835  		SHA:              String("sha"),
   836  		Filename:         String("fn"),
   837  		Additions:        Int(1),
   838  		Deletions:        Int(1),
   839  		Changes:          Int(1),
   840  		Status:           String("status"),
   841  		Patch:            String("patch"),
   842  		BlobURL:          String("burl"),
   843  		RawURL:           String("rurl"),
   844  		ContentsURL:      String("curl"),
   845  		PreviousFilename: String("pf"),
   846  	}
   847  
   848  	want := `{
   849  		"sha": "sha",
   850  		"filename": "fn",
   851  		"additions": 1,
   852  		"deletions": 1,
   853  		"changes": 1,
   854  		"status": "status",
   855  		"patch": "patch",
   856  		"blob_url": "burl",
   857  		"raw_url": "rurl",
   858  		"contents_url": "curl",
   859  		"previous_filename": "pf"
   860  	}`
   861  
   862  	testJSONMarshal(t, r, want)
   863  }
   864  
   865  func TestCommitStats_Marshal(t *testing.T) {
   866  	testJSONMarshal(t, &CommitStats{}, "{}")
   867  
   868  	r := &CommitStats{
   869  		Additions: Int(1),
   870  		Deletions: Int(1),
   871  		Total:     Int(1),
   872  	}
   873  
   874  	want := `{
   875  		"additions": 1,
   876  		"deletions": 1,
   877  		"total": 1
   878  	}`
   879  
   880  	testJSONMarshal(t, r, want)
   881  }
   882  
   883  func TestRepositoryCommit_Marshal(t *testing.T) {
   884  	testJSONMarshal(t, &RepositoryCommit{}, "{}")
   885  
   886  	r := &RepositoryCommit{
   887  		NodeID: String("nid"),
   888  		SHA:    String("sha"),
   889  		Commit: &Commit{
   890  			Message: String("m"),
   891  		},
   892  		Author: &User{
   893  			Login: String("l"),
   894  		},
   895  		Committer: &User{
   896  			Login: String("l"),
   897  		},
   898  		Parents: []*Commit{
   899  			{
   900  				SHA: String("s"),
   901  			},
   902  		},
   903  		HTMLURL:     String("hurl"),
   904  		URL:         String("url"),
   905  		CommentsURL: String("curl"),
   906  		Stats: &CommitStats{
   907  			Additions: Int(104),
   908  			Deletions: Int(4),
   909  			Total:     Int(108),
   910  		},
   911  		Files: []*CommitFile{
   912  			{
   913  				Filename:    String("f"),
   914  				Additions:   Int(10),
   915  				Deletions:   Int(2),
   916  				Changes:     Int(12),
   917  				Status:      String("s"),
   918  				Patch:       String("p"),
   919  				BlobURL:     String("b"),
   920  				RawURL:      String("r"),
   921  				ContentsURL: String("c"),
   922  			},
   923  		},
   924  	}
   925  
   926  	want := `{
   927  		"node_id": "nid",
   928  		"sha": "sha",
   929  		"commit": {
   930  			"message": "m"
   931  		},
   932  		"author": {
   933  			"login": "l"
   934  		},
   935  		"committer": {
   936  			"login": "l"
   937  		},
   938  		"parents": [
   939  			{
   940  				"sha": "s"
   941  			}
   942  		],
   943  		"html_url": "hurl",
   944  		"url": "url",
   945  		"comments_url": "curl",
   946  		"stats": {
   947  			"additions": 104,
   948  			"deletions": 4,
   949  			"total": 108
   950  		},
   951  		"files": [
   952  			{
   953  				"filename": "f",
   954  				"additions": 10,
   955  				"deletions": 2,
   956  				"changes": 12,
   957  				"status": "s",
   958  				"patch": "p",
   959  				"blob_url": "b",
   960  				"raw_url": "r",
   961  				"contents_url": "c"
   962  			}
   963  		]
   964  	}`
   965  
   966  	testJSONMarshal(t, r, want)
   967  }