github.com/google/go-github/v74@v74.0.0/github/search_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  	"strings"
    13  	"testing"
    14  
    15  	"github.com/google/go-cmp/cmp"
    16  )
    17  
    18  func TestSearchService_Repositories(t *testing.T) {
    19  	t.Parallel()
    20  	client, mux, _ := setup(t)
    21  
    22  	mux.HandleFunc("/search/repositories", func(w http.ResponseWriter, r *http.Request) {
    23  		testMethod(t, r, "GET")
    24  		testFormValues(t, r, values{
    25  			"q":        "blah",
    26  			"sort":     "forks",
    27  			"order":    "desc",
    28  			"page":     "2",
    29  			"per_page": "2",
    30  		})
    31  
    32  		fmt.Fprint(w, `{"total_count": 4, "incomplete_results": false, "items": [{"id":1},{"id":2}]}`)
    33  	})
    34  
    35  	opts := &SearchOptions{Sort: "forks", Order: "desc", ListOptions: ListOptions{Page: 2, PerPage: 2}}
    36  	ctx := context.Background()
    37  	result, _, err := client.Search.Repositories(ctx, "blah", opts)
    38  	if err != nil {
    39  		t.Errorf("Search.Repositories returned error: %v", err)
    40  	}
    41  
    42  	want := &RepositoriesSearchResult{
    43  		Total:             Ptr(4),
    44  		IncompleteResults: Ptr(false),
    45  		Repositories:      []*Repository{{ID: Ptr(int64(1))}, {ID: Ptr(int64(2))}},
    46  	}
    47  	if !cmp.Equal(result, want) {
    48  		t.Errorf("Search.Repositories returned %+v, want %+v", result, want)
    49  	}
    50  }
    51  
    52  func TestSearchService_Repositories_coverage(t *testing.T) {
    53  	t.Parallel()
    54  	client, _, _ := setup(t)
    55  
    56  	ctx := context.Background()
    57  
    58  	const methodName = "Repositories"
    59  	testBadOptions(t, methodName, func() (err error) {
    60  		_, _, err = client.Search.Repositories(ctx, "\n", nil)
    61  		return err
    62  	})
    63  }
    64  
    65  func TestSearchService_RepositoriesTextMatch(t *testing.T) {
    66  	t.Parallel()
    67  	client, mux, _ := setup(t)
    68  
    69  	mux.HandleFunc("/search/repositories", func(w http.ResponseWriter, r *http.Request) {
    70  		testMethod(t, r, "GET")
    71  		textMatchResponse := `
    72  			{
    73  				"total_count": 1,
    74  				"incomplete_results": false,
    75  				"items": [
    76  					{
    77  						"name":"gopher1"
    78  					}
    79  				]
    80  			}
    81  		`
    82  		list := strings.Split(r.Header.Get("Accept"), ",")
    83  		aMap := make(map[string]struct{})
    84  		for _, s := range list {
    85  			aMap[strings.TrimSpace(s)] = struct{}{}
    86  		}
    87  		if _, ok := aMap["application/vnd.github.v3.text-match+json"]; ok {
    88  			textMatchResponse = `
    89  					{
    90  						"total_count": 1,
    91  						"incomplete_results": false,
    92  						"items": [
    93  							{
    94  								"name":"gopher1",
    95  								"text_matches": [
    96  									{
    97  										"fragment": "I'm afraid my friend what you have found\nIs a gopher who lives to feed",
    98  										"matches": [
    99  											{
   100  												"text": "gopher",
   101  												"indices": [
   102  													14,
   103  													21
   104  											]
   105  											}
   106  									  ]
   107  								  }
   108  							  ]
   109  							}
   110  						]
   111  					}
   112  				`
   113  		}
   114  
   115  		fmt.Fprint(w, textMatchResponse)
   116  	})
   117  
   118  	opts := &SearchOptions{Sort: "forks", Order: "desc", ListOptions: ListOptions{Page: 2, PerPage: 2}, TextMatch: true}
   119  	ctx := context.Background()
   120  	result, _, err := client.Search.Repositories(ctx, "blah", opts)
   121  	if err != nil {
   122  		t.Errorf("Search.Code returned error: %v", err)
   123  	}
   124  
   125  	wantedRepoResult := &Repository{
   126  		Name: Ptr("gopher1"),
   127  		TextMatches: []*TextMatch{{
   128  			Fragment: Ptr("I'm afraid my friend what you have found\nIs a gopher who lives to feed"),
   129  			Matches:  []*Match{{Text: Ptr("gopher"), Indices: []int{14, 21}}},
   130  		},
   131  		},
   132  	}
   133  
   134  	want := &RepositoriesSearchResult{
   135  		Total:             Ptr(1),
   136  		IncompleteResults: Ptr(false),
   137  		Repositories:      []*Repository{wantedRepoResult},
   138  	}
   139  	if !cmp.Equal(result, want) {
   140  		t.Errorf("Search.Repo returned %+v, want %+v", result, want)
   141  	}
   142  }
   143  
   144  func TestSearchService_Topics(t *testing.T) {
   145  	t.Parallel()
   146  	client, mux, _ := setup(t)
   147  
   148  	mux.HandleFunc("/search/topics", func(w http.ResponseWriter, r *http.Request) {
   149  		testMethod(t, r, "GET")
   150  		testFormValues(t, r, values{
   151  			"q":        "blah",
   152  			"page":     "2",
   153  			"per_page": "2",
   154  		})
   155  
   156  		fmt.Fprint(w, `{"total_count": 4, "incomplete_results": false, "items": [{"name":"blah"},{"name":"blahblah"}]}`)
   157  	})
   158  
   159  	opts := &SearchOptions{ListOptions: ListOptions{Page: 2, PerPage: 2}}
   160  	ctx := context.Background()
   161  	result, _, err := client.Search.Topics(ctx, "blah", opts)
   162  	if err != nil {
   163  		t.Errorf("Search.Topics returned error: %v", err)
   164  	}
   165  
   166  	want := &TopicsSearchResult{
   167  		Total:             Ptr(4),
   168  		IncompleteResults: Ptr(false),
   169  		Topics:            []*TopicResult{{Name: Ptr("blah")}, {Name: Ptr("blahblah")}},
   170  	}
   171  	if !cmp.Equal(result, want) {
   172  		t.Errorf("Search.Topics returned %+v, want %+v", result, want)
   173  	}
   174  }
   175  
   176  func TestSearchService_Topics_coverage(t *testing.T) {
   177  	t.Parallel()
   178  	client, _, _ := setup(t)
   179  
   180  	ctx := context.Background()
   181  
   182  	const methodName = "Topics"
   183  	testBadOptions(t, methodName, func() (err error) {
   184  		_, _, err = client.Search.Topics(ctx, "\n", nil)
   185  		return err
   186  	})
   187  }
   188  
   189  func TestSearchService_Commits(t *testing.T) {
   190  	t.Parallel()
   191  	client, mux, _ := setup(t)
   192  
   193  	mux.HandleFunc("/search/commits", func(w http.ResponseWriter, r *http.Request) {
   194  		testMethod(t, r, "GET")
   195  		testFormValues(t, r, values{
   196  			"q":     "blah",
   197  			"sort":  "author-date",
   198  			"order": "desc",
   199  		})
   200  
   201  		fmt.Fprint(w, `{"total_count": 4, "incomplete_results": false, "items": [{"sha":"random_hash1"},{"sha":"random_hash2"}]}`)
   202  	})
   203  
   204  	opts := &SearchOptions{Sort: "author-date", Order: "desc"}
   205  	ctx := context.Background()
   206  	result, _, err := client.Search.Commits(ctx, "blah", opts)
   207  	if err != nil {
   208  		t.Errorf("Search.Commits returned error: %v", err)
   209  	}
   210  
   211  	want := &CommitsSearchResult{
   212  		Total:             Ptr(4),
   213  		IncompleteResults: Ptr(false),
   214  		Commits:           []*CommitResult{{SHA: Ptr("random_hash1")}, {SHA: Ptr("random_hash2")}},
   215  	}
   216  	if !cmp.Equal(result, want) {
   217  		t.Errorf("Search.Commits returned %+v, want %+v", result, want)
   218  	}
   219  }
   220  
   221  func TestSearchService_Commits_coverage(t *testing.T) {
   222  	t.Parallel()
   223  	client, _, _ := setup(t)
   224  
   225  	ctx := context.Background()
   226  
   227  	const methodName = "Commits"
   228  	testBadOptions(t, methodName, func() (err error) {
   229  		_, _, err = client.Search.Commits(ctx, "\n", nil)
   230  		return err
   231  	})
   232  }
   233  
   234  func TestSearchService_Issues(t *testing.T) {
   235  	t.Parallel()
   236  	client, mux, _ := setup(t)
   237  
   238  	mux.HandleFunc("/search/issues", func(w http.ResponseWriter, r *http.Request) {
   239  		testMethod(t, r, "GET")
   240  		testFormValues(t, r, values{
   241  			"q":        "blah",
   242  			"sort":     "forks",
   243  			"order":    "desc",
   244  			"page":     "2",
   245  			"per_page": "2",
   246  		})
   247  
   248  		fmt.Fprint(w, `{"total_count": 4, "incomplete_results": true, "items": [{"number":1},{"number":2}]}`)
   249  	})
   250  
   251  	opts := &SearchOptions{Sort: "forks", Order: "desc", ListOptions: ListOptions{Page: 2, PerPage: 2}}
   252  	ctx := context.Background()
   253  	result, _, err := client.Search.Issues(ctx, "blah", opts)
   254  	if err != nil {
   255  		t.Errorf("Search.Issues returned error: %v", err)
   256  	}
   257  
   258  	want := &IssuesSearchResult{
   259  		Total:             Ptr(4),
   260  		IncompleteResults: Ptr(true),
   261  		Issues:            []*Issue{{Number: Ptr(1)}, {Number: Ptr(2)}},
   262  	}
   263  	if !cmp.Equal(result, want) {
   264  		t.Errorf("Search.Issues returned %+v, want %+v", result, want)
   265  	}
   266  }
   267  
   268  func TestSearchService_Issues_coverage(t *testing.T) {
   269  	t.Parallel()
   270  	client, _, _ := setup(t)
   271  
   272  	ctx := context.Background()
   273  
   274  	const methodName = "Issues"
   275  	testBadOptions(t, methodName, func() (err error) {
   276  		_, _, err = client.Search.Issues(ctx, "\n", nil)
   277  		return err
   278  	})
   279  }
   280  
   281  func TestSearchService_Issues_withQualifiersNoOpts(t *testing.T) {
   282  	t.Parallel()
   283  	client, mux, _ := setup(t)
   284  
   285  	const q = "gopher is:issue label:bug language:c++ pushed:>=2018-01-01 stars:>=200"
   286  
   287  	var requestURI string
   288  	mux.HandleFunc("/search/issues", func(w http.ResponseWriter, r *http.Request) {
   289  		testMethod(t, r, "GET")
   290  		testFormValues(t, r, values{
   291  			"q": q,
   292  		})
   293  		requestURI = r.RequestURI
   294  
   295  		fmt.Fprint(w, `{"total_count": 4, "incomplete_results": true, "items": [{"number":1},{"number":2}]}`)
   296  	})
   297  
   298  	opts := &SearchOptions{}
   299  	ctx := context.Background()
   300  	result, _, err := client.Search.Issues(ctx, q, opts)
   301  	if err != nil {
   302  		t.Errorf("Search.Issues returned error: %v", err)
   303  	}
   304  
   305  	if want := "/api-v3/search/issues?q=gopher+is%3Aissue+label%3Abug+language%3Ac%2B%2B+pushed%3A%3E%3D2018-01-01+stars%3A%3E%3D200"; requestURI != want {
   306  		t.Fatalf("URI encoding failed: got %v, want %v", requestURI, want)
   307  	}
   308  
   309  	want := &IssuesSearchResult{
   310  		Total:             Ptr(4),
   311  		IncompleteResults: Ptr(true),
   312  		Issues:            []*Issue{{Number: Ptr(1)}, {Number: Ptr(2)}},
   313  	}
   314  	if !cmp.Equal(result, want) {
   315  		t.Errorf("Search.Issues returned %+v, want %+v", result, want)
   316  	}
   317  }
   318  
   319  func TestSearchService_Issues_withQualifiersAndOpts(t *testing.T) {
   320  	t.Parallel()
   321  	client, mux, _ := setup(t)
   322  
   323  	const q = "gopher is:issue label:bug language:c++ pushed:>=2018-01-01 stars:>=200"
   324  
   325  	var requestURI string
   326  	mux.HandleFunc("/search/issues", func(w http.ResponseWriter, r *http.Request) {
   327  		testMethod(t, r, "GET")
   328  		testFormValues(t, r, values{
   329  			"q":    q,
   330  			"sort": "forks",
   331  		})
   332  		requestURI = r.RequestURI
   333  
   334  		fmt.Fprint(w, `{"total_count": 4, "incomplete_results": true, "items": [{"number":1},{"number":2}]}`)
   335  	})
   336  
   337  	opts := &SearchOptions{Sort: "forks"}
   338  	ctx := context.Background()
   339  	result, _, err := client.Search.Issues(ctx, q, opts)
   340  	if err != nil {
   341  		t.Errorf("Search.Issues returned error: %v", err)
   342  	}
   343  
   344  	if want := "/api-v3/search/issues?q=gopher+is%3Aissue+label%3Abug+language%3Ac%2B%2B+pushed%3A%3E%3D2018-01-01+stars%3A%3E%3D200&sort=forks"; requestURI != want {
   345  		t.Fatalf("URI encoding failed: got %v, want %v", requestURI, want)
   346  	}
   347  
   348  	want := &IssuesSearchResult{
   349  		Total:             Ptr(4),
   350  		IncompleteResults: Ptr(true),
   351  		Issues:            []*Issue{{Number: Ptr(1)}, {Number: Ptr(2)}},
   352  	}
   353  	if !cmp.Equal(result, want) {
   354  		t.Errorf("Search.Issues returned %+v, want %+v", result, want)
   355  	}
   356  }
   357  
   358  func TestSearchService_Users(t *testing.T) {
   359  	t.Parallel()
   360  	client, mux, _ := setup(t)
   361  
   362  	mux.HandleFunc("/search/users", func(w http.ResponseWriter, r *http.Request) {
   363  		testMethod(t, r, "GET")
   364  		testFormValues(t, r, values{
   365  			"q":        "blah",
   366  			"sort":     "forks",
   367  			"order":    "desc",
   368  			"page":     "2",
   369  			"per_page": "2",
   370  		})
   371  
   372  		fmt.Fprint(w, `{"total_count": 4, "incomplete_results": false, "items": [{"id":1},{"id":2}]}`)
   373  	})
   374  
   375  	opts := &SearchOptions{Sort: "forks", Order: "desc", ListOptions: ListOptions{Page: 2, PerPage: 2}}
   376  	ctx := context.Background()
   377  	result, _, err := client.Search.Users(ctx, "blah", opts)
   378  	if err != nil {
   379  		t.Errorf("Search.Issues returned error: %v", err)
   380  	}
   381  
   382  	want := &UsersSearchResult{
   383  		Total:             Ptr(4),
   384  		IncompleteResults: Ptr(false),
   385  		Users:             []*User{{ID: Ptr(int64(1))}, {ID: Ptr(int64(2))}},
   386  	}
   387  	if !cmp.Equal(result, want) {
   388  		t.Errorf("Search.Users returned %+v, want %+v", result, want)
   389  	}
   390  }
   391  
   392  func TestSearchService_Users_coverage(t *testing.T) {
   393  	t.Parallel()
   394  	client, _, _ := setup(t)
   395  
   396  	ctx := context.Background()
   397  
   398  	const methodName = "Users"
   399  	testBadOptions(t, methodName, func() (err error) {
   400  		_, _, err = client.Search.Users(ctx, "\n", nil)
   401  		return err
   402  	})
   403  }
   404  
   405  func TestSearchService_Code(t *testing.T) {
   406  	t.Parallel()
   407  	client, mux, _ := setup(t)
   408  
   409  	mux.HandleFunc("/search/code", func(w http.ResponseWriter, r *http.Request) {
   410  		testMethod(t, r, "GET")
   411  		testFormValues(t, r, values{
   412  			"q":        "blah",
   413  			"sort":     "forks",
   414  			"order":    "desc",
   415  			"page":     "2",
   416  			"per_page": "2",
   417  		})
   418  
   419  		fmt.Fprint(w, `{"total_count": 4, "incomplete_results": false, "items": [{"name":"1"},{"name":"2"}]}`)
   420  	})
   421  
   422  	opts := &SearchOptions{Sort: "forks", Order: "desc", ListOptions: ListOptions{Page: 2, PerPage: 2}}
   423  	ctx := context.Background()
   424  	result, _, err := client.Search.Code(ctx, "blah", opts)
   425  	if err != nil {
   426  		t.Errorf("Search.Code returned error: %v", err)
   427  	}
   428  
   429  	want := &CodeSearchResult{
   430  		Total:             Ptr(4),
   431  		IncompleteResults: Ptr(false),
   432  		CodeResults:       []*CodeResult{{Name: Ptr("1")}, {Name: Ptr("2")}},
   433  	}
   434  	if !cmp.Equal(result, want) {
   435  		t.Errorf("Search.Code returned %+v, want %+v", result, want)
   436  	}
   437  }
   438  
   439  func TestSearchService_Code_coverage(t *testing.T) {
   440  	t.Parallel()
   441  	client, _, _ := setup(t)
   442  
   443  	ctx := context.Background()
   444  
   445  	const methodName = "Code"
   446  	testBadOptions(t, methodName, func() (err error) {
   447  		_, _, err = client.Search.Code(ctx, "\n", nil)
   448  		return err
   449  	})
   450  }
   451  
   452  func TestSearchService_CodeTextMatch(t *testing.T) {
   453  	t.Parallel()
   454  	client, mux, _ := setup(t)
   455  
   456  	mux.HandleFunc("/search/code", func(w http.ResponseWriter, r *http.Request) {
   457  		testMethod(t, r, "GET")
   458  
   459  		textMatchResponse := `
   460  		{
   461  			"total_count": 1,
   462  			"incomplete_results": false,
   463  			"items": [
   464  				{
   465  					"name":"gopher1",
   466  					"text_matches": [
   467  						{
   468  							"fragment": "I'm afraid my friend what you have found\nIs a gopher who lives to feed",
   469  							"matches": [
   470  								{
   471  									"text": "gopher",
   472  									"indices": [
   473  										14,
   474  										21
   475  							  	]
   476  								}
   477  						  ]
   478  					  }
   479  				  ]
   480  				}
   481  			]
   482  		}
   483      `
   484  
   485  		fmt.Fprint(w, textMatchResponse)
   486  	})
   487  
   488  	opts := &SearchOptions{Sort: "forks", Order: "desc", ListOptions: ListOptions{Page: 2, PerPage: 2}, TextMatch: true}
   489  	ctx := context.Background()
   490  	result, _, err := client.Search.Code(ctx, "blah", opts)
   491  	if err != nil {
   492  		t.Errorf("Search.Code returned error: %v", err)
   493  	}
   494  
   495  	wantedCodeResult := &CodeResult{
   496  		Name: Ptr("gopher1"),
   497  		TextMatches: []*TextMatch{{
   498  			Fragment: Ptr("I'm afraid my friend what you have found\nIs a gopher who lives to feed"),
   499  			Matches:  []*Match{{Text: Ptr("gopher"), Indices: []int{14, 21}}},
   500  		},
   501  		},
   502  	}
   503  
   504  	want := &CodeSearchResult{
   505  		Total:             Ptr(1),
   506  		IncompleteResults: Ptr(false),
   507  		CodeResults:       []*CodeResult{wantedCodeResult},
   508  	}
   509  	if !cmp.Equal(result, want) {
   510  		t.Errorf("Search.Code returned %+v, want %+v", result, want)
   511  	}
   512  }
   513  
   514  func TestSearchService_Labels(t *testing.T) {
   515  	t.Parallel()
   516  	client, mux, _ := setup(t)
   517  
   518  	mux.HandleFunc("/search/labels", func(w http.ResponseWriter, r *http.Request) {
   519  		testMethod(t, r, "GET")
   520  		testFormValues(t, r, values{
   521  			"repository_id": "1234",
   522  			"q":             "blah",
   523  			"sort":          "updated",
   524  			"order":         "desc",
   525  			"page":          "2",
   526  			"per_page":      "2",
   527  		})
   528  
   529  		fmt.Fprint(w, `{"total_count": 4, "incomplete_results": false, "items": [{"id": 1234, "name":"bug", "description": "some text"},{"id": 4567, "name":"feature"}]}`)
   530  	})
   531  
   532  	opts := &SearchOptions{Sort: "updated", Order: "desc", ListOptions: ListOptions{Page: 2, PerPage: 2}}
   533  	ctx := context.Background()
   534  	result, _, err := client.Search.Labels(ctx, 1234, "blah", opts)
   535  	if err != nil {
   536  		t.Errorf("Search.Code returned error: %v", err)
   537  	}
   538  
   539  	want := &LabelsSearchResult{
   540  		Total:             Ptr(4),
   541  		IncompleteResults: Ptr(false),
   542  		Labels: []*LabelResult{
   543  			{ID: Ptr(int64(1234)), Name: Ptr("bug"), Description: Ptr("some text")},
   544  			{ID: Ptr(int64(4567)), Name: Ptr("feature")},
   545  		},
   546  	}
   547  	if !cmp.Equal(result, want) {
   548  		t.Errorf("Search.Labels returned %+v, want %+v", result, want)
   549  	}
   550  }
   551  
   552  func TestSearchService_Labels_coverage(t *testing.T) {
   553  	t.Parallel()
   554  	client, _, _ := setup(t)
   555  
   556  	ctx := context.Background()
   557  
   558  	const methodName = "Labels"
   559  	testBadOptions(t, methodName, func() (err error) {
   560  		_, _, err = client.Search.Labels(ctx, -1234, "\n", nil)
   561  		return err
   562  	})
   563  }
   564  
   565  func TestMatch_Marshal(t *testing.T) {
   566  	t.Parallel()
   567  	testJSONMarshal(t, &Match{}, "{}")
   568  
   569  	u := &Match{
   570  		Text:    Ptr("txt"),
   571  		Indices: []int{1},
   572  	}
   573  
   574  	want := `{
   575  		"text": "txt",
   576  		"indices": [1]
   577  	}`
   578  
   579  	testJSONMarshal(t, u, want)
   580  }
   581  
   582  func TestTextMatch_Marshal(t *testing.T) {
   583  	t.Parallel()
   584  	testJSONMarshal(t, &TextMatch{}, "{}")
   585  
   586  	u := &TextMatch{
   587  		ObjectURL:  Ptr("ourl"),
   588  		ObjectType: Ptr("otype"),
   589  		Property:   Ptr("prop"),
   590  		Fragment:   Ptr("fragment"),
   591  		Matches: []*Match{
   592  			{
   593  				Text:    Ptr("txt"),
   594  				Indices: []int{1},
   595  			},
   596  		},
   597  	}
   598  
   599  	want := `{
   600  		"object_url": "ourl",
   601  		"object_type": "otype",
   602  		"property": "prop",
   603  		"fragment": "fragment",
   604  		"matches": [{
   605  			"text": "txt",
   606  			"indices": [1]
   607  		}]
   608  	}`
   609  
   610  	testJSONMarshal(t, u, want)
   611  }
   612  
   613  func TestTopicResult_Marshal(t *testing.T) {
   614  	t.Parallel()
   615  	testJSONMarshal(t, &TopicResult{}, "{}")
   616  
   617  	u := &TopicResult{
   618  		Name:             Ptr("name"),
   619  		DisplayName:      Ptr("displayName"),
   620  		ShortDescription: Ptr("shortDescription"),
   621  		Description:      Ptr("description"),
   622  		CreatedBy:        Ptr("createdBy"),
   623  		UpdatedAt:        Ptr("2021-10-26"),
   624  		Featured:         Ptr(false),
   625  		Curated:          Ptr(true),
   626  		Score:            Ptr(99.9),
   627  	}
   628  
   629  	want := `{
   630  		"name": "name",
   631  		"display_name": "displayName",
   632  		"short_description": "shortDescription",
   633  		"description": "description",
   634  		"created_by": "createdBy",
   635  		"updated_at": "2021-10-26",
   636  		"featured": false,
   637  		"curated": true,
   638  		"score": 99.9
   639  	}`
   640  
   641  	testJSONMarshal(t, u, want)
   642  }
   643  
   644  func TestRepositoriesSearchResult_Marshal(t *testing.T) {
   645  	t.Parallel()
   646  	testJSONMarshal(t, &RepositoriesSearchResult{}, "{}")
   647  
   648  	u := &RepositoriesSearchResult{
   649  		Total:             Ptr(0),
   650  		IncompleteResults: Ptr(true),
   651  		Repositories:      []*Repository{{ID: Ptr(int64(1))}},
   652  	}
   653  
   654  	want := `{
   655  		"total_count" : 0,
   656  		"incomplete_results" : true,
   657  		"items" : [{"id":1}]
   658  	}`
   659  
   660  	testJSONMarshal(t, u, want)
   661  }
   662  
   663  func TestCommitsSearchResult_Marshal(t *testing.T) {
   664  	t.Parallel()
   665  	testJSONMarshal(t, &CommitsSearchResult{}, "{}")
   666  
   667  	c := &CommitsSearchResult{
   668  		Total:             Ptr(0),
   669  		IncompleteResults: Ptr(true),
   670  		Commits: []*CommitResult{{
   671  			SHA: Ptr("s"),
   672  		}},
   673  	}
   674  
   675  	want := `{
   676  		"total_count" : 0,
   677  		"incomplete_results" : true,
   678  		"items" : [{"sha" : "s"}]
   679  	}`
   680  
   681  	testJSONMarshal(t, c, want)
   682  }
   683  
   684  func TestTopicsSearchResult_Marshal(t *testing.T) {
   685  	t.Parallel()
   686  	testJSONMarshal(t, &TopicsSearchResult{}, "{}")
   687  
   688  	u := &TopicsSearchResult{
   689  		Total:             Ptr(2),
   690  		IncompleteResults: Ptr(false),
   691  		Topics: []*TopicResult{
   692  			{
   693  				Name:             Ptr("t1"),
   694  				DisplayName:      Ptr("tt"),
   695  				ShortDescription: Ptr("t desc"),
   696  				Description:      Ptr("desc"),
   697  				CreatedBy:        Ptr("mi"),
   698  				CreatedAt:        &Timestamp{referenceTime},
   699  				UpdatedAt:        Ptr("2006-01-02T15:04:05Z"),
   700  				Featured:         Ptr(true),
   701  				Curated:          Ptr(true),
   702  				Score:            Ptr(123.0),
   703  			},
   704  		},
   705  	}
   706  
   707  	want := `{
   708  		"total_count" : 2,
   709  		"incomplete_results" : false,
   710  		"items" : [
   711  			{
   712  				"name" : "t1",
   713  				"display_name":"tt",
   714  				"short_description":"t desc",
   715  				"description":"desc",
   716  				"created_by":"mi",
   717  				"created_at":` + referenceTimeStr + `,
   718  				"updated_at":"2006-01-02T15:04:05Z",
   719  				"featured":true,
   720  				"curated":true,
   721  				"score":123
   722  			}
   723  		]
   724  	}`
   725  
   726  	testJSONMarshal(t, u, want)
   727  }
   728  
   729  func TestLabelResult_Marshal(t *testing.T) {
   730  	t.Parallel()
   731  	testJSONMarshal(t, &LabelResult{}, "{}")
   732  
   733  	u := &LabelResult{
   734  		ID:          Ptr(int64(11)),
   735  		URL:         Ptr("url"),
   736  		Name:        Ptr("label"),
   737  		Color:       Ptr("green"),
   738  		Default:     Ptr(true),
   739  		Description: Ptr("desc"),
   740  		Score:       Ptr(123.0),
   741  	}
   742  
   743  	want := `{
   744  		"id":11,
   745  		"url":"url",
   746  		"name":"label",
   747  		"color":"green",
   748  		"default":true,
   749  		"description":"desc",
   750  		"score":123
   751  	}`
   752  
   753  	testJSONMarshal(t, u, want)
   754  }
   755  
   756  func TestSearchOptions_Marshal(t *testing.T) {
   757  	t.Parallel()
   758  	testJSONMarshal(t, &SearchOptions{}, "{}")
   759  
   760  	u := &SearchOptions{
   761  		Sort:      "author-date",
   762  		Order:     "asc",
   763  		TextMatch: false,
   764  		ListOptions: ListOptions{
   765  			Page:    int(1),
   766  			PerPage: int(10),
   767  		},
   768  	}
   769  
   770  	want := `{
   771  		"sort": "author-date",
   772  		"order": "asc",
   773  		"page": 1,
   774  		"perPage": 10
   775        }`
   776  
   777  	testJSONMarshal(t, u, want)
   778  }
   779  
   780  func TestIssuesSearchResult_Marshal(t *testing.T) {
   781  	t.Parallel()
   782  	testJSONMarshal(t, &IssuesSearchResult{}, "{}")
   783  
   784  	u := &IssuesSearchResult{
   785  		Total:             Ptr(48),
   786  		IncompleteResults: Ptr(false),
   787  		Issues: []*Issue{
   788  			{
   789  				ID:                Ptr(int64(1)),
   790  				Number:            Ptr(1),
   791  				State:             Ptr("s"),
   792  				Locked:            Ptr(false),
   793  				Title:             Ptr("title"),
   794  				Body:              Ptr("body"),
   795  				AuthorAssociation: Ptr("aa"),
   796  				User:              &User{ID: Ptr(int64(1))},
   797  				Labels:            []*Label{{ID: Ptr(int64(1))}},
   798  				Assignee:          &User{ID: Ptr(int64(1))},
   799  				Comments:          Ptr(1),
   800  				ClosedAt:          &Timestamp{referenceTime},
   801  				CreatedAt:         &Timestamp{referenceTime},
   802  				UpdatedAt:         &Timestamp{referenceTime},
   803  				ClosedBy:          &User{ID: Ptr(int64(1))},
   804  				URL:               Ptr("url"),
   805  				HTMLURL:           Ptr("hurl"),
   806  				CommentsURL:       Ptr("curl"),
   807  				EventsURL:         Ptr("eurl"),
   808  				LabelsURL:         Ptr("lurl"),
   809  				RepositoryURL:     Ptr("rurl"),
   810  				Milestone:         &Milestone{ID: Ptr(int64(1))},
   811  				PullRequestLinks:  &PullRequestLinks{URL: Ptr("url")},
   812  				Repository:        &Repository{ID: Ptr(int64(1))},
   813  				Reactions:         &Reactions{TotalCount: Ptr(1)},
   814  				Assignees:         []*User{{ID: Ptr(int64(1))}},
   815  				NodeID:            Ptr("nid"),
   816  				TextMatches:       []*TextMatch{{ObjectURL: Ptr("ourl")}},
   817  				ActiveLockReason:  Ptr("alr"),
   818  			},
   819  		},
   820  	}
   821  
   822  	want := `{
   823  		"total_count": 48,
   824  		"incomplete_results": false,
   825  		"items": [
   826  			{
   827  				"id": 1,
   828  				"number": 1,
   829  				"state": "s",
   830  				"locked": false,
   831  				"title": "title",
   832  				"body": "body",
   833  				"author_association": "aa",
   834  				"user": {
   835  					"id": 1
   836  				},
   837  				"labels": [
   838  					{
   839  						"id": 1
   840  					}
   841  				],
   842  				"assignee": {
   843  					"id": 1
   844  				},
   845  				"comments": 1,
   846  				"closed_at": ` + referenceTimeStr + `,
   847  				"created_at": ` + referenceTimeStr + `,
   848  				"updated_at": ` + referenceTimeStr + `,
   849  				"closed_by": {
   850  					"id": 1
   851  				},
   852  				"url": "url",
   853  				"html_url": "hurl",
   854  				"comments_url": "curl",
   855  				"events_url": "eurl",
   856  				"labels_url": "lurl",
   857  				"repository_url": "rurl",
   858  				"milestone": {
   859  					"id": 1
   860  				},
   861  				"pull_request": {
   862  					"url": "url"
   863  				},
   864  				"repository": {
   865  					"id": 1
   866  				},
   867  				"reactions": {
   868  					"total_count": 1
   869  				},
   870  				"assignees": [
   871  					{
   872  						"id": 1
   873  					}
   874  				],
   875  				"node_id": "nid",
   876  				"text_matches": [
   877  					{
   878  						"object_url": "ourl"
   879  					}
   880  				],
   881  				"active_lock_reason": "alr"
   882  			}
   883  		]
   884  	}`
   885  
   886  	testJSONMarshal(t, u, want)
   887  }
   888  
   889  func TestLabelsSearchResult_Marshal(t *testing.T) {
   890  	t.Parallel()
   891  	testJSONMarshal(t, &LabelsSearchResult{}, "{}")
   892  
   893  	u := &LabelsSearchResult{
   894  		Total:             Ptr(5),
   895  		IncompleteResults: Ptr(false),
   896  		Labels: []*LabelResult{
   897  			{
   898  				ID:          Ptr(int64(1)),
   899  				URL:         Ptr("https://www.test-url.com"),
   900  				Name:        Ptr("test name"),
   901  				Color:       Ptr("green"),
   902  				Default:     Ptr(true),
   903  				Description: Ptr("testDescription"),
   904  				Score:       Ptr(1.0),
   905  			},
   906  		},
   907  	}
   908  
   909  	want := `{
   910  		"total_count": 5,
   911  		"incomplete_results": false,
   912  		"items": [
   913  			{
   914  				"id": 1,
   915  				"url": "https://www.test-url.com",
   916  				"name": "test name",
   917  				"color": "green",
   918  				"default": true,
   919  				"description": "testDescription",
   920  				"score": 1
   921  			}
   922  		]
   923  	}`
   924  
   925  	testJSONMarshal(t, u, want)
   926  }
   927  
   928  func TestCommitResult_Marshal(t *testing.T) {
   929  	t.Parallel()
   930  	testJSONMarshal(t, &CommitResult{}, "{}")
   931  
   932  	c := &CommitResult{
   933  		SHA:         Ptr("test"),
   934  		HTMLURL:     Ptr("hurl"),
   935  		CommentsURL: Ptr("curl"),
   936  		URL:         Ptr("url"),
   937  		Repository:  &Repository{ID: Ptr(int64(1))},
   938  		Score:       Ptr(123.0),
   939  		Commit:      &Commit{SHA: Ptr("test")},
   940  		Author:      &User{ID: Ptr(int64(1))},
   941  		Committer:   &User{ID: Ptr(int64(1))},
   942  		Parents:     []*Commit{},
   943  	}
   944  
   945  	want := `{
   946  		"sha": "test",
   947  		"commit": {
   948  		   "sha": "test"
   949  		},
   950  		"author": {
   951  		   "id": 1
   952  		},
   953  		"committer": {
   954  		   "id": 1
   955  		},
   956  		"html_url": "hurl",
   957  		"url": "url",
   958  		"comments_url": "curl",
   959  		"repository": {
   960  		   "id": 1
   961  		},
   962  		"score": 123
   963  	 }`
   964  
   965  	testJSONMarshal(t, c, want)
   966  }
   967  
   968  func TestUsersSearchResult_Marshal(t *testing.T) {
   969  	t.Parallel()
   970  	testJSONMarshal(t, &UsersSearchResult{}, "{}")
   971  
   972  	u := &UsersSearchResult{
   973  		Total:             Ptr(2),
   974  		IncompleteResults: Ptr(false),
   975  		Users: []*User{{
   976  			Login:      Ptr("loginTest"),
   977  			ID:         Ptr(int64(1)),
   978  			NodeID:     Ptr("NodeTest"),
   979  			AvatarURL:  Ptr("AvatarURLTest"),
   980  			HTMLURL:    Ptr("Hurl"),
   981  			GravatarID: Ptr("gravatarIDTest"),
   982  			Name:       Ptr("nameTest"),
   983  		}},
   984  	}
   985  
   986  	want := `{
   987  		"total_count": 2,
   988  		"incomplete_results": false,
   989  		"items": [
   990  		   {
   991  			  "login": "loginTest",
   992  			  "id": 1,
   993  			  "node_id": "NodeTest",
   994  			  "avatar_url": "AvatarURLTest",
   995  			  "html_url": "Hurl",
   996  			  "gravatar_id": "gravatarIDTest",
   997  			  "name": "nameTest"
   998  		   }
   999  		]
  1000  	 }`
  1001  
  1002  	testJSONMarshal(t, u, want)
  1003  }
  1004  
  1005  func TestCodeSearchResult_Marshal(t *testing.T) {
  1006  	t.Parallel()
  1007  	testJSONMarshal(t, &CodeSearchResult{}, "{}")
  1008  
  1009  	u := &CodeSearchResult{
  1010  		Total:             Ptr(4),
  1011  		IncompleteResults: Ptr(false),
  1012  		CodeResults:       []*CodeResult{{Name: Ptr("n")}},
  1013  	}
  1014  
  1015  	want := `{
  1016  		"total_count" : 4,
  1017  		"incomplete_results" : false,
  1018  		"items" : [{"name": "n"}]
  1019  	}`
  1020  
  1021  	testJSONMarshal(t, u, want)
  1022  }