github.com/google/go-github/v64@v64.0.0/github/apps_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  	"time"
    15  
    16  	"github.com/google/go-cmp/cmp"
    17  )
    18  
    19  func TestAppsService_Get_authenticatedApp(t *testing.T) {
    20  	client, mux, _, teardown := setup()
    21  	defer teardown()
    22  
    23  	mux.HandleFunc("/app", func(w http.ResponseWriter, r *http.Request) {
    24  		testMethod(t, r, "GET")
    25  		fmt.Fprint(w, `{"id":1}`)
    26  	})
    27  
    28  	ctx := context.Background()
    29  	app, _, err := client.Apps.Get(ctx, "")
    30  	if err != nil {
    31  		t.Errorf("Apps.Get returned error: %v", err)
    32  	}
    33  
    34  	want := &App{ID: Int64(1)}
    35  	if !cmp.Equal(app, want) {
    36  		t.Errorf("Apps.Get returned %+v, want %+v", app, want)
    37  	}
    38  
    39  	const methodName = "Get"
    40  	testBadOptions(t, methodName, func() (err error) {
    41  		_, _, err = client.Apps.Get(ctx, "\n")
    42  		return err
    43  	})
    44  
    45  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
    46  		got, resp, err := client.Apps.Get(ctx, "")
    47  		if got != nil {
    48  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
    49  		}
    50  		return resp, err
    51  	})
    52  }
    53  
    54  func TestAppsService_Get_specifiedApp(t *testing.T) {
    55  	client, mux, _, teardown := setup()
    56  	defer teardown()
    57  
    58  	mux.HandleFunc("/apps/a", func(w http.ResponseWriter, r *http.Request) {
    59  		testMethod(t, r, "GET")
    60  		fmt.Fprint(w, `{"html_url":"https://github.com/apps/a"}`)
    61  	})
    62  
    63  	ctx := context.Background()
    64  	app, _, err := client.Apps.Get(ctx, "a")
    65  	if err != nil {
    66  		t.Errorf("Apps.Get returned error: %v", err)
    67  	}
    68  
    69  	want := &App{HTMLURL: String("https://github.com/apps/a")}
    70  	if !cmp.Equal(app, want) {
    71  		t.Errorf("Apps.Get returned %+v, want %+v", *app.HTMLURL, *want.HTMLURL)
    72  	}
    73  }
    74  
    75  func TestAppsService_ListInstallationRequests(t *testing.T) {
    76  	client, mux, _, teardown := setup()
    77  	defer teardown()
    78  
    79  	mux.HandleFunc("/app/installation-requests", func(w http.ResponseWriter, r *http.Request) {
    80  		testMethod(t, r, "GET")
    81  		testFormValues(t, r, values{
    82  			"page":     "1",
    83  			"per_page": "2",
    84  		})
    85  		fmt.Fprint(w, `[{
    86  			"id": 1,
    87  			"account": { "id": 2 },
    88  			"requester": { "id": 3 },
    89  			"created_at": "2018-01-01T00:00:00Z"
    90  		}]`,
    91  		)
    92  	})
    93  
    94  	opt := &ListOptions{Page: 1, PerPage: 2}
    95  	ctx := context.Background()
    96  	installationRequests, _, err := client.Apps.ListInstallationRequests(ctx, opt)
    97  	if err != nil {
    98  		t.Errorf("Apps.ListInstallations returned error: %v", err)
    99  	}
   100  
   101  	date := Timestamp{Time: time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)}
   102  	want := []*InstallationRequest{{
   103  		ID:        Int64(1),
   104  		Account:   &User{ID: Int64(2)},
   105  		Requester: &User{ID: Int64(3)},
   106  		CreatedAt: &date,
   107  	}}
   108  	if !cmp.Equal(installationRequests, want) {
   109  		t.Errorf("Apps.ListInstallationRequests returned %+v, want %+v", installationRequests, want)
   110  	}
   111  
   112  	const methodName = "ListInstallationRequests"
   113  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   114  		got, resp, err := client.Apps.ListInstallationRequests(ctx, opt)
   115  		if got != nil {
   116  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   117  		}
   118  		return resp, err
   119  	})
   120  }
   121  
   122  func TestAppsService_ListInstallations(t *testing.T) {
   123  	client, mux, _, teardown := setup()
   124  	defer teardown()
   125  
   126  	mux.HandleFunc("/app/installations", func(w http.ResponseWriter, r *http.Request) {
   127  		testMethod(t, r, "GET")
   128  		testFormValues(t, r, values{
   129  			"page":     "1",
   130  			"per_page": "2",
   131  		})
   132  		fmt.Fprint(w, `[{
   133                                     "id":1,
   134                                     "app_id":1,
   135                                     "target_id":1,
   136                                     "target_type": "Organization",
   137                                     "permissions": {
   138                                         "actions": "read",
   139                                         "administration": "read",
   140                                         "checks": "read",
   141                                         "contents": "read",
   142                                         "content_references": "read",
   143                                         "deployments": "read",
   144                                         "environments": "read",
   145                                         "issues": "write",
   146                                         "metadata": "read",
   147                                         "members": "read",
   148                                         "organization_administration": "write",
   149                                         "organization_custom_roles": "write",
   150                                         "organization_hooks": "write",
   151                                         "organization_packages": "write",
   152                                         "organization_plan": "read",
   153                                         "organization_pre_receive_hooks": "write",
   154                                         "organization_projects": "read",
   155                                         "organization_secrets": "read",
   156                                         "organization_self_hosted_runners": "read",
   157                                         "organization_user_blocking": "write",
   158                                         "packages": "read",
   159                                         "pages": "read",
   160                                         "pull_requests": "write",
   161                                         "repository_hooks": "write",
   162                                         "repository_projects": "read",
   163                                         "repository_pre_receive_hooks": "read",
   164                                         "secrets": "read",
   165                                         "secret_scanning_alerts": "read",
   166                                         "security_events": "read",
   167                                         "single_file": "write",
   168                                         "statuses": "write",
   169                                         "team_discussions": "read",
   170                                         "vulnerability_alerts": "read",
   171                                         "workflows": "write"
   172                                     },
   173                                    "events": [
   174                                        "push",
   175                                        "pull_request"
   176                                    ],
   177                                   "single_file_name": "config.yml",
   178                                   "repository_selection": "selected",
   179                                   "created_at": "2018-01-01T00:00:00Z",
   180                                   "updated_at": "2018-01-01T00:00:00Z"}]`,
   181  		)
   182  	})
   183  
   184  	opt := &ListOptions{Page: 1, PerPage: 2}
   185  	ctx := context.Background()
   186  	installations, _, err := client.Apps.ListInstallations(ctx, opt)
   187  	if err != nil {
   188  		t.Errorf("Apps.ListInstallations returned error: %v", err)
   189  	}
   190  
   191  	date := Timestamp{Time: time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)}
   192  	want := []*Installation{{
   193  		ID:                  Int64(1),
   194  		AppID:               Int64(1),
   195  		TargetID:            Int64(1),
   196  		TargetType:          String("Organization"),
   197  		SingleFileName:      String("config.yml"),
   198  		RepositorySelection: String("selected"),
   199  		Permissions: &InstallationPermissions{
   200  			Actions:                       String("read"),
   201  			Administration:                String("read"),
   202  			Checks:                        String("read"),
   203  			Contents:                      String("read"),
   204  			ContentReferences:             String("read"),
   205  			Deployments:                   String("read"),
   206  			Environments:                  String("read"),
   207  			Issues:                        String("write"),
   208  			Metadata:                      String("read"),
   209  			Members:                       String("read"),
   210  			OrganizationAdministration:    String("write"),
   211  			OrganizationCustomRoles:       String("write"),
   212  			OrganizationHooks:             String("write"),
   213  			OrganizationPackages:          String("write"),
   214  			OrganizationPlan:              String("read"),
   215  			OrganizationPreReceiveHooks:   String("write"),
   216  			OrganizationProjects:          String("read"),
   217  			OrganizationSecrets:           String("read"),
   218  			OrganizationSelfHostedRunners: String("read"),
   219  			OrganizationUserBlocking:      String("write"),
   220  			Packages:                      String("read"),
   221  			Pages:                         String("read"),
   222  			PullRequests:                  String("write"),
   223  			RepositoryHooks:               String("write"),
   224  			RepositoryProjects:            String("read"),
   225  			RepositoryPreReceiveHooks:     String("read"),
   226  			Secrets:                       String("read"),
   227  			SecretScanningAlerts:          String("read"),
   228  			SecurityEvents:                String("read"),
   229  			SingleFile:                    String("write"),
   230  			Statuses:                      String("write"),
   231  			TeamDiscussions:               String("read"),
   232  			VulnerabilityAlerts:           String("read"),
   233  			Workflows:                     String("write")},
   234  		Events:    []string{"push", "pull_request"},
   235  		CreatedAt: &date,
   236  		UpdatedAt: &date,
   237  	}}
   238  	if !cmp.Equal(installations, want) {
   239  		t.Errorf("Apps.ListInstallations returned %+v, want %+v", installations, want)
   240  	}
   241  
   242  	const methodName = "ListInstallations"
   243  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   244  		got, resp, err := client.Apps.ListInstallations(ctx, opt)
   245  		if got != nil {
   246  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   247  		}
   248  		return resp, err
   249  	})
   250  }
   251  
   252  func TestAppsService_GetInstallation(t *testing.T) {
   253  	client, mux, _, teardown := setup()
   254  	defer teardown()
   255  
   256  	mux.HandleFunc("/app/installations/1", func(w http.ResponseWriter, r *http.Request) {
   257  		testMethod(t, r, "GET")
   258  		fmt.Fprint(w, `{"id":1, "app_id":1, "target_id":1, "target_type": "Organization"}`)
   259  	})
   260  
   261  	ctx := context.Background()
   262  	installation, _, err := client.Apps.GetInstallation(ctx, 1)
   263  	if err != nil {
   264  		t.Errorf("Apps.GetInstallation returned error: %v", err)
   265  	}
   266  
   267  	want := &Installation{ID: Int64(1), AppID: Int64(1), TargetID: Int64(1), TargetType: String("Organization")}
   268  	if !cmp.Equal(installation, want) {
   269  		t.Errorf("Apps.GetInstallation returned %+v, want %+v", installation, want)
   270  	}
   271  
   272  	const methodName = "GetInstallation"
   273  	testBadOptions(t, methodName, func() (err error) {
   274  		_, _, err = client.Apps.GetInstallation(ctx, -1)
   275  		return err
   276  	})
   277  
   278  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   279  		got, resp, err := client.Apps.GetInstallation(ctx, 1)
   280  		if got != nil {
   281  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   282  		}
   283  		return resp, err
   284  	})
   285  }
   286  
   287  func TestAppsService_ListUserInstallations(t *testing.T) {
   288  	client, mux, _, teardown := setup()
   289  	defer teardown()
   290  
   291  	mux.HandleFunc("/user/installations", func(w http.ResponseWriter, r *http.Request) {
   292  		testMethod(t, r, "GET")
   293  		testFormValues(t, r, values{
   294  			"page":     "1",
   295  			"per_page": "2",
   296  		})
   297  		fmt.Fprint(w, `{"installations":[{"id":1, "app_id":1, "target_id":1, "target_type": "Organization"}]}`)
   298  	})
   299  
   300  	opt := &ListOptions{Page: 1, PerPage: 2}
   301  	ctx := context.Background()
   302  	installations, _, err := client.Apps.ListUserInstallations(ctx, opt)
   303  	if err != nil {
   304  		t.Errorf("Apps.ListUserInstallations returned error: %v", err)
   305  	}
   306  
   307  	want := []*Installation{{ID: Int64(1), AppID: Int64(1), TargetID: Int64(1), TargetType: String("Organization")}}
   308  	if !cmp.Equal(installations, want) {
   309  		t.Errorf("Apps.ListUserInstallations returned %+v, want %+v", installations, want)
   310  	}
   311  
   312  	const methodName = "ListUserInstallations"
   313  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   314  		got, resp, err := client.Apps.ListUserInstallations(ctx, opt)
   315  		if got != nil {
   316  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   317  		}
   318  		return resp, err
   319  	})
   320  }
   321  
   322  func TestAppsService_SuspendInstallation(t *testing.T) {
   323  	client, mux, _, teardown := setup()
   324  	defer teardown()
   325  
   326  	mux.HandleFunc("/app/installations/1/suspended", func(w http.ResponseWriter, r *http.Request) {
   327  		testMethod(t, r, "PUT")
   328  
   329  		w.WriteHeader(http.StatusNoContent)
   330  	})
   331  
   332  	ctx := context.Background()
   333  	if _, err := client.Apps.SuspendInstallation(ctx, 1); err != nil {
   334  		t.Errorf("Apps.SuspendInstallation returned error: %v", err)
   335  	}
   336  
   337  	const methodName = "SuspendInstallation"
   338  	testBadOptions(t, methodName, func() (err error) {
   339  		_, err = client.Apps.SuspendInstallation(ctx, -1)
   340  		return err
   341  	})
   342  
   343  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   344  		return client.Apps.SuspendInstallation(ctx, 1)
   345  	})
   346  }
   347  
   348  func TestAppsService_UnsuspendInstallation(t *testing.T) {
   349  	client, mux, _, teardown := setup()
   350  	defer teardown()
   351  
   352  	mux.HandleFunc("/app/installations/1/suspended", func(w http.ResponseWriter, r *http.Request) {
   353  		testMethod(t, r, "DELETE")
   354  
   355  		w.WriteHeader(http.StatusNoContent)
   356  	})
   357  
   358  	ctx := context.Background()
   359  	if _, err := client.Apps.UnsuspendInstallation(ctx, 1); err != nil {
   360  		t.Errorf("Apps.UnsuspendInstallation returned error: %v", err)
   361  	}
   362  
   363  	const methodName = "UnsuspendInstallation"
   364  	testBadOptions(t, methodName, func() (err error) {
   365  		_, err = client.Apps.UnsuspendInstallation(ctx, -1)
   366  		return err
   367  	})
   368  
   369  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   370  		return client.Apps.UnsuspendInstallation(ctx, 1)
   371  	})
   372  }
   373  
   374  func TestAppsService_DeleteInstallation(t *testing.T) {
   375  	client, mux, _, teardown := setup()
   376  	defer teardown()
   377  
   378  	mux.HandleFunc("/app/installations/1", func(w http.ResponseWriter, r *http.Request) {
   379  		testMethod(t, r, "DELETE")
   380  		w.WriteHeader(http.StatusNoContent)
   381  	})
   382  
   383  	ctx := context.Background()
   384  	_, err := client.Apps.DeleteInstallation(ctx, 1)
   385  	if err != nil {
   386  		t.Errorf("Apps.DeleteInstallation returned error: %v", err)
   387  	}
   388  
   389  	const methodName = "DeleteInstallation"
   390  	testBadOptions(t, methodName, func() (err error) {
   391  		_, err = client.Apps.DeleteInstallation(ctx, -1)
   392  		return err
   393  	})
   394  
   395  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   396  		return client.Apps.DeleteInstallation(ctx, 1)
   397  	})
   398  }
   399  
   400  func TestAppsService_CreateInstallationToken(t *testing.T) {
   401  	client, mux, _, teardown := setup()
   402  	defer teardown()
   403  
   404  	mux.HandleFunc("/app/installations/1/access_tokens", func(w http.ResponseWriter, r *http.Request) {
   405  		testMethod(t, r, "POST")
   406  		fmt.Fprint(w, `{"token":"t"}`)
   407  	})
   408  
   409  	ctx := context.Background()
   410  	token, _, err := client.Apps.CreateInstallationToken(ctx, 1, nil)
   411  	if err != nil {
   412  		t.Errorf("Apps.CreateInstallationToken returned error: %v", err)
   413  	}
   414  
   415  	want := &InstallationToken{Token: String("t")}
   416  	if !cmp.Equal(token, want) {
   417  		t.Errorf("Apps.CreateInstallationToken returned %+v, want %+v", token, want)
   418  	}
   419  
   420  	const methodName = "CreateInstallationToken"
   421  	testBadOptions(t, methodName, func() (err error) {
   422  		_, _, err = client.Apps.CreateInstallationToken(ctx, -1, nil)
   423  		return err
   424  	})
   425  
   426  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   427  		got, resp, err := client.Apps.CreateInstallationToken(ctx, 1, nil)
   428  		if got != nil {
   429  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   430  		}
   431  		return resp, err
   432  	})
   433  }
   434  
   435  func TestAppsService_CreateInstallationTokenWithOptions(t *testing.T) {
   436  	client, mux, _, teardown := setup()
   437  	defer teardown()
   438  
   439  	installationTokenOptions := &InstallationTokenOptions{
   440  		RepositoryIDs: []int64{1234},
   441  		Repositories:  []string{"foo"},
   442  		Permissions: &InstallationPermissions{
   443  			Contents: String("write"),
   444  			Issues:   String("read"),
   445  		},
   446  	}
   447  
   448  	mux.HandleFunc("/app/installations/1/access_tokens", func(w http.ResponseWriter, r *http.Request) {
   449  		v := new(InstallationTokenOptions)
   450  		assertNilError(t, json.NewDecoder(r.Body).Decode(v))
   451  
   452  		if !cmp.Equal(v, installationTokenOptions) {
   453  			t.Errorf("request sent %+v, want %+v", v, installationTokenOptions)
   454  		}
   455  
   456  		testMethod(t, r, "POST")
   457  		fmt.Fprint(w, `{"token":"t"}`)
   458  	})
   459  
   460  	ctx := context.Background()
   461  	token, _, err := client.Apps.CreateInstallationToken(ctx, 1, installationTokenOptions)
   462  	if err != nil {
   463  		t.Errorf("Apps.CreateInstallationToken returned error: %v", err)
   464  	}
   465  
   466  	want := &InstallationToken{Token: String("t")}
   467  	if !cmp.Equal(token, want) {
   468  		t.Errorf("Apps.CreateInstallationToken returned %+v, want %+v", token, want)
   469  	}
   470  }
   471  
   472  func TestAppsService_CreateInstallationTokenListReposWithOptions(t *testing.T) {
   473  	client, mux, _, teardown := setup()
   474  	defer teardown()
   475  
   476  	installationTokenListRepoOptions := &InstallationTokenListRepoOptions{
   477  		Repositories: []string{"foo"},
   478  		Permissions: &InstallationPermissions{
   479  			Contents: String("write"),
   480  			Issues:   String("read"),
   481  		},
   482  	}
   483  
   484  	mux.HandleFunc("/app/installations/1/access_tokens", func(w http.ResponseWriter, r *http.Request) {
   485  		v := new(InstallationTokenListRepoOptions)
   486  		assertNilError(t, json.NewDecoder(r.Body).Decode(v))
   487  
   488  		if !cmp.Equal(v, installationTokenListRepoOptions) {
   489  			t.Errorf("request sent %+v, want %+v", v, installationTokenListRepoOptions)
   490  		}
   491  
   492  		testMethod(t, r, "POST")
   493  		fmt.Fprint(w, `{"token":"t"}`)
   494  	})
   495  
   496  	ctx := context.Background()
   497  	token, _, err := client.Apps.CreateInstallationTokenListRepos(ctx, 1, installationTokenListRepoOptions)
   498  	if err != nil {
   499  		t.Errorf("Apps.CreateInstallationTokenListRepos returned error: %v", err)
   500  	}
   501  
   502  	want := &InstallationToken{Token: String("t")}
   503  	if !cmp.Equal(token, want) {
   504  		t.Errorf("Apps.CreateInstallationTokenListRepos returned %+v, want %+v", token, want)
   505  	}
   506  }
   507  
   508  func TestAppsService_CreateInstallationTokenListReposWithNoOptions(t *testing.T) {
   509  	client, mux, _, teardown := setup()
   510  	defer teardown()
   511  
   512  	mux.HandleFunc("/app/installations/1/access_tokens", func(w http.ResponseWriter, r *http.Request) {
   513  		testMethod(t, r, "POST")
   514  		fmt.Fprint(w, `{"token":"t"}`)
   515  	})
   516  
   517  	ctx := context.Background()
   518  	token, _, err := client.Apps.CreateInstallationTokenListRepos(ctx, 1, nil)
   519  	if err != nil {
   520  		t.Errorf("Apps.CreateInstallationTokenListRepos returned error: %v", err)
   521  	}
   522  
   523  	want := &InstallationToken{Token: String("t")}
   524  	if !cmp.Equal(token, want) {
   525  		t.Errorf("Apps.CreateInstallationTokenListRepos returned %+v, want %+v", token, want)
   526  	}
   527  
   528  	const methodName = "CreateInstallationTokenListRepos"
   529  	testBadOptions(t, methodName, func() (err error) {
   530  		_, _, err = client.Apps.CreateInstallationTokenListRepos(ctx, -1, nil)
   531  		return err
   532  	})
   533  
   534  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   535  		got, resp, err := client.Apps.CreateInstallationTokenListRepos(ctx, 1, nil)
   536  		if got != nil {
   537  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   538  		}
   539  		return resp, err
   540  	})
   541  }
   542  
   543  func TestAppsService_CreateAttachement(t *testing.T) {
   544  	client, mux, _, teardown := setup()
   545  	defer teardown()
   546  
   547  	mux.HandleFunc("/content_references/11/attachments", func(w http.ResponseWriter, r *http.Request) {
   548  		testMethod(t, r, "POST")
   549  		testHeader(t, r, "Accept", mediaTypeContentAttachmentsPreview)
   550  
   551  		w.WriteHeader(http.StatusOK)
   552  		assertWrite(t, w, []byte(`{"id":1,"title":"title1","body":"body1"}`))
   553  	})
   554  
   555  	ctx := context.Background()
   556  	got, _, err := client.Apps.CreateAttachment(ctx, 11, "title1", "body1")
   557  	if err != nil {
   558  		t.Errorf("CreateAttachment returned error: %v", err)
   559  	}
   560  
   561  	want := &Attachment{ID: Int64(1), Title: String("title1"), Body: String("body1")}
   562  	if !cmp.Equal(got, want) {
   563  		t.Errorf("CreateAttachment = %+v, want %+v", got, want)
   564  	}
   565  
   566  	const methodName = "CreateAttachment"
   567  	testBadOptions(t, methodName, func() (err error) {
   568  		_, _, err = client.Apps.CreateAttachment(ctx, -11, "\n", "\n")
   569  		return err
   570  	})
   571  
   572  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   573  		got, resp, err := client.Apps.CreateAttachment(ctx, 11, "title1", "body1")
   574  		if got != nil {
   575  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   576  		}
   577  		return resp, err
   578  	})
   579  }
   580  
   581  func TestAppsService_FindOrganizationInstallation(t *testing.T) {
   582  	client, mux, _, teardown := setup()
   583  	defer teardown()
   584  
   585  	mux.HandleFunc("/orgs/o/installation", func(w http.ResponseWriter, r *http.Request) {
   586  		testMethod(t, r, "GET")
   587  		fmt.Fprint(w, `{"id":1, "app_id":1, "target_id":1, "target_type": "Organization"}`)
   588  	})
   589  
   590  	ctx := context.Background()
   591  	installation, _, err := client.Apps.FindOrganizationInstallation(ctx, "o")
   592  	if err != nil {
   593  		t.Errorf("Apps.FindOrganizationInstallation returned error: %v", err)
   594  	}
   595  
   596  	want := &Installation{ID: Int64(1), AppID: Int64(1), TargetID: Int64(1), TargetType: String("Organization")}
   597  	if !cmp.Equal(installation, want) {
   598  		t.Errorf("Apps.FindOrganizationInstallation returned %+v, want %+v", installation, want)
   599  	}
   600  
   601  	const methodName = "FindOrganizationInstallation"
   602  	testBadOptions(t, methodName, func() (err error) {
   603  		_, _, err = client.Apps.FindOrganizationInstallation(ctx, "\n")
   604  		return err
   605  	})
   606  
   607  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   608  		got, resp, err := client.Apps.FindOrganizationInstallation(ctx, "o")
   609  		if got != nil {
   610  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   611  		}
   612  		return resp, err
   613  	})
   614  }
   615  
   616  func TestAppsService_FindRepositoryInstallation(t *testing.T) {
   617  	client, mux, _, teardown := setup()
   618  	defer teardown()
   619  
   620  	mux.HandleFunc("/repos/o/r/installation", func(w http.ResponseWriter, r *http.Request) {
   621  		testMethod(t, r, "GET")
   622  		fmt.Fprint(w, `{"id":1, "app_id":1, "target_id":1, "target_type": "Organization"}`)
   623  	})
   624  
   625  	ctx := context.Background()
   626  	installation, _, err := client.Apps.FindRepositoryInstallation(ctx, "o", "r")
   627  	if err != nil {
   628  		t.Errorf("Apps.FindRepositoryInstallation returned error: %v", err)
   629  	}
   630  
   631  	want := &Installation{ID: Int64(1), AppID: Int64(1), TargetID: Int64(1), TargetType: String("Organization")}
   632  	if !cmp.Equal(installation, want) {
   633  		t.Errorf("Apps.FindRepositoryInstallation returned %+v, want %+v", installation, want)
   634  	}
   635  
   636  	const methodName = "FindRepositoryInstallation"
   637  	testBadOptions(t, methodName, func() (err error) {
   638  		_, _, err = client.Apps.FindRepositoryInstallation(ctx, "\n", "\n")
   639  		return err
   640  	})
   641  
   642  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   643  		got, resp, err := client.Apps.FindRepositoryInstallation(ctx, "o", "r")
   644  		if got != nil {
   645  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   646  		}
   647  		return resp, err
   648  	})
   649  }
   650  
   651  func TestAppsService_FindRepositoryInstallationByID(t *testing.T) {
   652  	client, mux, _, teardown := setup()
   653  	defer teardown()
   654  
   655  	mux.HandleFunc("/repositories/1/installation", func(w http.ResponseWriter, r *http.Request) {
   656  		testMethod(t, r, "GET")
   657  		fmt.Fprint(w, `{"id":1, "app_id":1, "target_id":1, "target_type": "Organization"}`)
   658  	})
   659  
   660  	ctx := context.Background()
   661  	installation, _, err := client.Apps.FindRepositoryInstallationByID(ctx, 1)
   662  	if err != nil {
   663  		t.Errorf("Apps.FindRepositoryInstallationByID returned error: %v", err)
   664  	}
   665  
   666  	want := &Installation{ID: Int64(1), AppID: Int64(1), TargetID: Int64(1), TargetType: String("Organization")}
   667  	if !cmp.Equal(installation, want) {
   668  		t.Errorf("Apps.FindRepositoryInstallationByID returned %+v, want %+v", installation, want)
   669  	}
   670  
   671  	const methodName = "FindRepositoryInstallationByID"
   672  	testBadOptions(t, methodName, func() (err error) {
   673  		_, _, err = client.Apps.FindRepositoryInstallationByID(ctx, -1)
   674  		return err
   675  	})
   676  
   677  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   678  		got, resp, err := client.Apps.FindRepositoryInstallationByID(ctx, 1)
   679  		if got != nil {
   680  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   681  		}
   682  		return resp, err
   683  	})
   684  }
   685  
   686  func TestAppsService_FindUserInstallation(t *testing.T) {
   687  	client, mux, _, teardown := setup()
   688  	defer teardown()
   689  
   690  	mux.HandleFunc("/users/u/installation", func(w http.ResponseWriter, r *http.Request) {
   691  		testMethod(t, r, "GET")
   692  		fmt.Fprint(w, `{"id":1, "app_id":1, "target_id":1, "target_type": "User"}`)
   693  	})
   694  
   695  	ctx := context.Background()
   696  	installation, _, err := client.Apps.FindUserInstallation(ctx, "u")
   697  	if err != nil {
   698  		t.Errorf("Apps.FindUserInstallation returned error: %v", err)
   699  	}
   700  
   701  	want := &Installation{ID: Int64(1), AppID: Int64(1), TargetID: Int64(1), TargetType: String("User")}
   702  	if !cmp.Equal(installation, want) {
   703  		t.Errorf("Apps.FindUserInstallation returned %+v, want %+v", installation, want)
   704  	}
   705  
   706  	const methodName = "FindUserInstallation"
   707  	testBadOptions(t, methodName, func() (err error) {
   708  		_, _, err = client.Apps.FindUserInstallation(ctx, "\n")
   709  		return err
   710  	})
   711  
   712  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   713  		got, resp, err := client.Apps.FindUserInstallation(ctx, "u")
   714  		if got != nil {
   715  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   716  		}
   717  		return resp, err
   718  	})
   719  }
   720  
   721  func TestContentReference_Marshal(t *testing.T) {
   722  	testJSONMarshal(t, &ContentReference{}, "{}")
   723  
   724  	u := &ContentReference{
   725  		ID:        Int64(1),
   726  		NodeID:    String("nid"),
   727  		Reference: String("r"),
   728  	}
   729  
   730  	want := `{
   731  		"id": 1,
   732  		"node_id": "nid",
   733  		"reference": "r"
   734  	}`
   735  
   736  	testJSONMarshal(t, u, want)
   737  }
   738  
   739  func TestAttachment_Marshal(t *testing.T) {
   740  	testJSONMarshal(t, &Attachment{}, "{}")
   741  
   742  	u := &Attachment{
   743  		ID:    Int64(1),
   744  		Title: String("t"),
   745  		Body:  String("b"),
   746  	}
   747  
   748  	want := `{
   749  		"id": 1,
   750  		"title": "t",
   751  		"body": "b"
   752  	}`
   753  
   754  	testJSONMarshal(t, u, want)
   755  }
   756  
   757  func TestInstallationPermissions_Marshal(t *testing.T) {
   758  	testJSONMarshal(t, &InstallationPermissions{}, "{}")
   759  
   760  	u := &InstallationPermissions{
   761  		Actions:                       String("a"),
   762  		Administration:                String("ad"),
   763  		Checks:                        String("c"),
   764  		Contents:                      String("co"),
   765  		ContentReferences:             String("cr"),
   766  		Deployments:                   String("d"),
   767  		Environments:                  String("e"),
   768  		Issues:                        String("i"),
   769  		Metadata:                      String("md"),
   770  		Members:                       String("m"),
   771  		OrganizationAdministration:    String("oa"),
   772  		OrganizationCustomOrgRoles:    String("ocr"),
   773  		OrganizationHooks:             String("oh"),
   774  		OrganizationPlan:              String("op"),
   775  		OrganizationPreReceiveHooks:   String("opr"),
   776  		OrganizationProjects:          String("op"),
   777  		OrganizationSecrets:           String("os"),
   778  		OrganizationSelfHostedRunners: String("osh"),
   779  		OrganizationUserBlocking:      String("oub"),
   780  		Packages:                      String("pkg"),
   781  		Pages:                         String("pg"),
   782  		PullRequests:                  String("pr"),
   783  		RepositoryHooks:               String("rh"),
   784  		RepositoryProjects:            String("rp"),
   785  		RepositoryPreReceiveHooks:     String("rprh"),
   786  		Secrets:                       String("s"),
   787  		SecretScanningAlerts:          String("ssa"),
   788  		SecurityEvents:                String("se"),
   789  		SingleFile:                    String("sf"),
   790  		Statuses:                      String("s"),
   791  		TeamDiscussions:               String("td"),
   792  		VulnerabilityAlerts:           String("va"),
   793  		Workflows:                     String("w"),
   794  	}
   795  
   796  	want := `{
   797  		"actions": "a",
   798  		"administration": "ad",
   799  		"checks": "c",
   800  		"contents": "co",
   801  		"content_references": "cr",
   802  		"deployments": "d",
   803  		"environments": "e",
   804  		"issues": "i",
   805  		"metadata": "md",
   806  		"members": "m",
   807  		"organization_administration": "oa",
   808  		"organization_custom_org_roles": "ocr",
   809  		"organization_hooks": "oh",
   810  		"organization_plan": "op",
   811  		"organization_pre_receive_hooks": "opr",
   812  		"organization_projects": "op",
   813  		"organization_secrets": "os",
   814  		"organization_self_hosted_runners": "osh",
   815  		"organization_user_blocking": "oub",
   816  		"packages": "pkg",
   817  		"pages": "pg",
   818  		"pull_requests": "pr",
   819  		"repository_hooks": "rh",
   820  		"repository_projects": "rp",
   821  		"repository_pre_receive_hooks": "rprh",
   822  		"secrets": "s",
   823  		"secret_scanning_alerts": "ssa",
   824  		"security_events": "se",
   825  		"single_file": "sf",
   826  		"statuses": "s",
   827  		"team_discussions": "td",
   828  		"vulnerability_alerts":"va",
   829  		"workflows": "w"
   830  	}`
   831  
   832  	testJSONMarshal(t, u, want)
   833  }
   834  
   835  func TestInstallation_Marshal(t *testing.T) {
   836  	testJSONMarshal(t, &Installation{}, "{}")
   837  
   838  	u := &Installation{
   839  		ID:       Int64(1),
   840  		NodeID:   String("nid"),
   841  		AppID:    Int64(1),
   842  		AppSlug:  String("as"),
   843  		TargetID: Int64(1),
   844  		Account: &User{
   845  			Login:           String("l"),
   846  			ID:              Int64(1),
   847  			URL:             String("u"),
   848  			AvatarURL:       String("a"),
   849  			GravatarID:      String("g"),
   850  			Name:            String("n"),
   851  			Company:         String("c"),
   852  			Blog:            String("b"),
   853  			Location:        String("l"),
   854  			Email:           String("e"),
   855  			Hireable:        Bool(true),
   856  			Bio:             String("b"),
   857  			TwitterUsername: String("t"),
   858  			PublicRepos:     Int(1),
   859  			Followers:       Int(1),
   860  			Following:       Int(1),
   861  			CreatedAt:       &Timestamp{referenceTime},
   862  			SuspendedAt:     &Timestamp{referenceTime},
   863  		},
   864  		AccessTokensURL:     String("atu"),
   865  		RepositoriesURL:     String("ru"),
   866  		HTMLURL:             String("hu"),
   867  		TargetType:          String("tt"),
   868  		SingleFileName:      String("sfn"),
   869  		RepositorySelection: String("rs"),
   870  		Events:              []string{"e"},
   871  		SingleFilePaths:     []string{"s"},
   872  		Permissions: &InstallationPermissions{
   873  			Actions:                       String("a"),
   874  			ActionsVariables:              String("ac"),
   875  			Administration:                String("ad"),
   876  			Checks:                        String("c"),
   877  			Contents:                      String("co"),
   878  			ContentReferences:             String("cr"),
   879  			Deployments:                   String("d"),
   880  			Environments:                  String("e"),
   881  			Issues:                        String("i"),
   882  			Metadata:                      String("md"),
   883  			Members:                       String("m"),
   884  			OrganizationAdministration:    String("oa"),
   885  			OrganizationCustomOrgRoles:    String("ocr"),
   886  			OrganizationHooks:             String("oh"),
   887  			OrganizationPlan:              String("op"),
   888  			OrganizationPreReceiveHooks:   String("opr"),
   889  			OrganizationProjects:          String("op"),
   890  			OrganizationSecrets:           String("os"),
   891  			OrganizationSelfHostedRunners: String("osh"),
   892  			OrganizationUserBlocking:      String("oub"),
   893  			Packages:                      String("pkg"),
   894  			Pages:                         String("pg"),
   895  			PullRequests:                  String("pr"),
   896  			RepositoryHooks:               String("rh"),
   897  			RepositoryProjects:            String("rp"),
   898  			RepositoryPreReceiveHooks:     String("rprh"),
   899  			Secrets:                       String("s"),
   900  			SecretScanningAlerts:          String("ssa"),
   901  			SecurityEvents:                String("se"),
   902  			SingleFile:                    String("sf"),
   903  			Statuses:                      String("s"),
   904  			TeamDiscussions:               String("td"),
   905  			VulnerabilityAlerts:           String("va"),
   906  			Workflows:                     String("w"),
   907  		},
   908  		CreatedAt:              &Timestamp{referenceTime},
   909  		UpdatedAt:              &Timestamp{referenceTime},
   910  		HasMultipleSingleFiles: Bool(false),
   911  		SuspendedBy: &User{
   912  			Login:           String("l"),
   913  			ID:              Int64(1),
   914  			URL:             String("u"),
   915  			AvatarURL:       String("a"),
   916  			GravatarID:      String("g"),
   917  			Name:            String("n"),
   918  			Company:         String("c"),
   919  			Blog:            String("b"),
   920  			Location:        String("l"),
   921  			Email:           String("e"),
   922  			Hireable:        Bool(true),
   923  			Bio:             String("b"),
   924  			TwitterUsername: String("t"),
   925  			PublicRepos:     Int(1),
   926  			Followers:       Int(1),
   927  			Following:       Int(1),
   928  			CreatedAt:       &Timestamp{referenceTime},
   929  			SuspendedAt:     &Timestamp{referenceTime},
   930  		},
   931  		SuspendedAt: &Timestamp{referenceTime},
   932  	}
   933  
   934  	want := `{
   935  		"id": 1,
   936  		"node_id": "nid",
   937  		"app_id": 1,
   938  		"app_slug": "as",
   939  		"target_id": 1,
   940  		"account": {
   941  			"login": "l",
   942  			"id": 1,
   943  			"avatar_url": "a",
   944  			"gravatar_id": "g",
   945  			"name": "n",
   946  			"company": "c",
   947  			"blog": "b",
   948  			"location": "l",
   949  			"email": "e",
   950  			"hireable": true,
   951  			"bio": "b",
   952  			"twitter_username": "t",
   953  			"public_repos": 1,
   954  			"followers": 1,
   955  			"following": 1,
   956  			"created_at": ` + referenceTimeStr + `,
   957  			"suspended_at": ` + referenceTimeStr + `,
   958  			"url": "u"
   959  		},
   960  		"access_tokens_url": "atu",
   961  		"repositories_url": "ru",
   962  		"html_url": "hu",
   963  		"target_type": "tt",
   964  		"single_file_name": "sfn",
   965  		"repository_selection": "rs",
   966  		"events": [
   967  			"e"
   968  		],
   969  		"single_file_paths": [
   970  			"s"
   971  		],
   972  		"permissions": {
   973  			"actions": "a",
   974  			"actions_variables": "ac",
   975  			"administration": "ad",
   976  			"checks": "c",
   977  			"contents": "co",
   978  			"content_references": "cr",
   979  			"deployments": "d",
   980  			"environments": "e",
   981  			"issues": "i",
   982  			"metadata": "md",
   983  			"members": "m",
   984  			"organization_administration": "oa",
   985  			"organization_custom_org_roles": "ocr",
   986  			"organization_hooks": "oh",
   987  			"organization_plan": "op",
   988  			"organization_pre_receive_hooks": "opr",
   989  			"organization_projects": "op",
   990  			"organization_secrets": "os",
   991  			"organization_self_hosted_runners": "osh",
   992  			"organization_user_blocking": "oub",
   993  			"packages": "pkg",
   994  			"pages": "pg",
   995  			"pull_requests": "pr",
   996  			"repository_hooks": "rh",
   997  			"repository_projects": "rp",
   998  			"repository_pre_receive_hooks": "rprh",
   999  			"secrets": "s",
  1000  			"secret_scanning_alerts": "ssa",
  1001  			"security_events": "se",
  1002  			"single_file": "sf",
  1003  			"statuses": "s",
  1004  			"team_discussions": "td",
  1005  			"vulnerability_alerts": "va",
  1006  			"workflows": "w"
  1007  		},
  1008  		"created_at": ` + referenceTimeStr + `,
  1009  		"updated_at": ` + referenceTimeStr + `,
  1010  		"has_multiple_single_files": false,
  1011  		"suspended_by": {
  1012  			"login": "l",
  1013  			"id": 1,
  1014  			"avatar_url": "a",
  1015  			"gravatar_id": "g",
  1016  			"name": "n",
  1017  			"company": "c",
  1018  			"blog": "b",
  1019  			"location": "l",
  1020  			"email": "e",
  1021  			"hireable": true,
  1022  			"bio": "b",
  1023  			"twitter_username": "t",
  1024  			"public_repos": 1,
  1025  			"followers": 1,
  1026  			"following": 1,
  1027  			"created_at": ` + referenceTimeStr + `,
  1028  			"suspended_at": ` + referenceTimeStr + `,
  1029  			"url": "u"
  1030  		},
  1031  		"suspended_at": ` + referenceTimeStr + `
  1032  	}`
  1033  
  1034  	testJSONMarshal(t, u, want)
  1035  }
  1036  
  1037  func TestInstallationTokenOptions_Marshal(t *testing.T) {
  1038  	testJSONMarshal(t, &InstallationTokenOptions{}, "{}")
  1039  
  1040  	u := &InstallationTokenOptions{
  1041  		RepositoryIDs: []int64{1},
  1042  		Permissions: &InstallationPermissions{
  1043  			Actions:                       String("a"),
  1044  			ActionsVariables:              String("ac"),
  1045  			Administration:                String("ad"),
  1046  			Checks:                        String("c"),
  1047  			Contents:                      String("co"),
  1048  			ContentReferences:             String("cr"),
  1049  			Deployments:                   String("d"),
  1050  			Environments:                  String("e"),
  1051  			Issues:                        String("i"),
  1052  			Metadata:                      String("md"),
  1053  			Members:                       String("m"),
  1054  			OrganizationAdministration:    String("oa"),
  1055  			OrganizationCustomOrgRoles:    String("ocr"),
  1056  			OrganizationHooks:             String("oh"),
  1057  			OrganizationPlan:              String("op"),
  1058  			OrganizationPreReceiveHooks:   String("opr"),
  1059  			OrganizationProjects:          String("op"),
  1060  			OrganizationSecrets:           String("os"),
  1061  			OrganizationSelfHostedRunners: String("osh"),
  1062  			OrganizationUserBlocking:      String("oub"),
  1063  			Packages:                      String("pkg"),
  1064  			Pages:                         String("pg"),
  1065  			PullRequests:                  String("pr"),
  1066  			RepositoryHooks:               String("rh"),
  1067  			RepositoryProjects:            String("rp"),
  1068  			RepositoryPreReceiveHooks:     String("rprh"),
  1069  			Secrets:                       String("s"),
  1070  			SecretScanningAlerts:          String("ssa"),
  1071  			SecurityEvents:                String("se"),
  1072  			SingleFile:                    String("sf"),
  1073  			Statuses:                      String("s"),
  1074  			TeamDiscussions:               String("td"),
  1075  			VulnerabilityAlerts:           String("va"),
  1076  			Workflows:                     String("w"),
  1077  		},
  1078  	}
  1079  
  1080  	want := `{
  1081  		"repository_ids": [1],
  1082  		"permissions": {
  1083  			"actions": "a",
  1084  			"actions_variables": "ac",
  1085  			"administration": "ad",
  1086  			"checks": "c",
  1087  			"contents": "co",
  1088  			"content_references": "cr",
  1089  			"deployments": "d",
  1090  			"environments": "e",
  1091  			"issues": "i",
  1092  			"metadata": "md",
  1093  			"members": "m",
  1094  			"organization_administration": "oa",
  1095  			"organization_custom_org_roles": "ocr",
  1096  			"organization_hooks": "oh",
  1097  			"organization_plan": "op",
  1098  			"organization_pre_receive_hooks": "opr",
  1099  			"organization_projects": "op",
  1100  			"organization_secrets": "os",
  1101  			"organization_self_hosted_runners": "osh",
  1102  			"organization_user_blocking": "oub",
  1103  			"packages": "pkg",
  1104  			"pages": "pg",
  1105  			"pull_requests": "pr",
  1106  			"repository_hooks": "rh",
  1107  			"repository_projects": "rp",
  1108  			"repository_pre_receive_hooks": "rprh",
  1109  			"secrets": "s",
  1110  			"secret_scanning_alerts": "ssa",
  1111  			"security_events": "se",
  1112  			"single_file": "sf",
  1113  			"statuses": "s",
  1114  			"team_discussions": "td",
  1115  			"vulnerability_alerts": "va",
  1116  			"workflows": "w"
  1117  		}
  1118  	}`
  1119  
  1120  	testJSONMarshal(t, u, want)
  1121  }
  1122  
  1123  func TestInstallationToken_Marshal(t *testing.T) {
  1124  	testJSONMarshal(t, &InstallationToken{}, "{}")
  1125  
  1126  	u := &InstallationToken{
  1127  		Token:     String("t"),
  1128  		ExpiresAt: &Timestamp{referenceTime},
  1129  		Permissions: &InstallationPermissions{
  1130  			Actions:                       String("a"),
  1131  			ActionsVariables:              String("ac"),
  1132  			Administration:                String("ad"),
  1133  			Checks:                        String("c"),
  1134  			Contents:                      String("co"),
  1135  			ContentReferences:             String("cr"),
  1136  			Deployments:                   String("d"),
  1137  			Environments:                  String("e"),
  1138  			Issues:                        String("i"),
  1139  			Metadata:                      String("md"),
  1140  			Members:                       String("m"),
  1141  			OrganizationAdministration:    String("oa"),
  1142  			OrganizationCustomOrgRoles:    String("ocr"),
  1143  			OrganizationHooks:             String("oh"),
  1144  			OrganizationPlan:              String("op"),
  1145  			OrganizationPreReceiveHooks:   String("opr"),
  1146  			OrganizationProjects:          String("op"),
  1147  			OrganizationSecrets:           String("os"),
  1148  			OrganizationSelfHostedRunners: String("osh"),
  1149  			OrganizationUserBlocking:      String("oub"),
  1150  			Packages:                      String("pkg"),
  1151  			Pages:                         String("pg"),
  1152  			PullRequests:                  String("pr"),
  1153  			RepositoryHooks:               String("rh"),
  1154  			RepositoryProjects:            String("rp"),
  1155  			RepositoryPreReceiveHooks:     String("rprh"),
  1156  			Secrets:                       String("s"),
  1157  			SecretScanningAlerts:          String("ssa"),
  1158  			SecurityEvents:                String("se"),
  1159  			SingleFile:                    String("sf"),
  1160  			Statuses:                      String("s"),
  1161  			TeamDiscussions:               String("td"),
  1162  			VulnerabilityAlerts:           String("va"),
  1163  			Workflows:                     String("w"),
  1164  		},
  1165  		Repositories: []*Repository{
  1166  			{
  1167  				ID:   Int64(1),
  1168  				URL:  String("u"),
  1169  				Name: String("n"),
  1170  			},
  1171  		},
  1172  	}
  1173  
  1174  	want := `{
  1175  		"token": "t",
  1176  		"expires_at": ` + referenceTimeStr + `,
  1177  		"permissions": {
  1178  			"actions": "a",
  1179  			"actions_variables": "ac",
  1180  			"administration": "ad",
  1181  			"checks": "c",
  1182  			"contents": "co",
  1183  			"content_references": "cr",
  1184  			"deployments": "d",
  1185  			"environments": "e",
  1186  			"issues": "i",
  1187  			"metadata": "md",
  1188  			"members": "m",
  1189  			"organization_administration": "oa",
  1190  			"organization_custom_org_roles": "ocr",
  1191  			"organization_hooks": "oh",
  1192  			"organization_plan": "op",
  1193  			"organization_pre_receive_hooks": "opr",
  1194  			"organization_projects": "op",
  1195  			"organization_secrets": "os",
  1196  			"organization_self_hosted_runners": "osh",
  1197  			"organization_user_blocking": "oub",
  1198  			"packages": "pkg",
  1199  			"pages": "pg",
  1200  			"pull_requests": "pr",
  1201  			"repository_hooks": "rh",
  1202  			"repository_projects": "rp",
  1203  			"repository_pre_receive_hooks": "rprh",
  1204  			"secrets": "s",
  1205  			"secret_scanning_alerts": "ssa",
  1206  			"security_events": "se",
  1207  			"single_file": "sf",
  1208  			"statuses": "s",
  1209  			"team_discussions": "td",
  1210  			"vulnerability_alerts": "va",
  1211  			"workflows": "w"
  1212  		},
  1213  		"repositories": [
  1214  			{
  1215  				"id": 1,
  1216  				"url": "u",
  1217  				"name": "n"
  1218  			}
  1219  		]
  1220  	}`
  1221  
  1222  	testJSONMarshal(t, u, want)
  1223  }
  1224  
  1225  func TestApp_Marshal(t *testing.T) {
  1226  	testJSONMarshal(t, &App{}, "{}")
  1227  
  1228  	u := &App{
  1229  		ID:     Int64(1),
  1230  		Slug:   String("s"),
  1231  		NodeID: String("nid"),
  1232  		Owner: &User{
  1233  			Login:           String("l"),
  1234  			ID:              Int64(1),
  1235  			URL:             String("u"),
  1236  			AvatarURL:       String("a"),
  1237  			GravatarID:      String("g"),
  1238  			Name:            String("n"),
  1239  			Company:         String("c"),
  1240  			Blog:            String("b"),
  1241  			Location:        String("l"),
  1242  			Email:           String("e"),
  1243  			Hireable:        Bool(true),
  1244  			Bio:             String("b"),
  1245  			TwitterUsername: String("t"),
  1246  			PublicRepos:     Int(1),
  1247  			Followers:       Int(1),
  1248  			Following:       Int(1),
  1249  			CreatedAt:       &Timestamp{referenceTime},
  1250  			SuspendedAt:     &Timestamp{referenceTime},
  1251  		},
  1252  		Name:        String("n"),
  1253  		Description: String("d"),
  1254  		ExternalURL: String("eu"),
  1255  		HTMLURL:     String("hu"),
  1256  		CreatedAt:   &Timestamp{referenceTime},
  1257  		UpdatedAt:   &Timestamp{referenceTime},
  1258  		Permissions: &InstallationPermissions{
  1259  			Actions:                       String("a"),
  1260  			ActionsVariables:              String("ac"),
  1261  			Administration:                String("ad"),
  1262  			Checks:                        String("c"),
  1263  			Contents:                      String("co"),
  1264  			ContentReferences:             String("cr"),
  1265  			Deployments:                   String("d"),
  1266  			Environments:                  String("e"),
  1267  			Issues:                        String("i"),
  1268  			Metadata:                      String("md"),
  1269  			Members:                       String("m"),
  1270  			OrganizationAdministration:    String("oa"),
  1271  			OrganizationCustomOrgRoles:    String("ocr"),
  1272  			OrganizationHooks:             String("oh"),
  1273  			OrganizationPlan:              String("op"),
  1274  			OrganizationPreReceiveHooks:   String("opr"),
  1275  			OrganizationProjects:          String("op"),
  1276  			OrganizationSecrets:           String("os"),
  1277  			OrganizationSelfHostedRunners: String("osh"),
  1278  			OrganizationUserBlocking:      String("oub"),
  1279  			Packages:                      String("pkg"),
  1280  			Pages:                         String("pg"),
  1281  			PullRequests:                  String("pr"),
  1282  			RepositoryHooks:               String("rh"),
  1283  			RepositoryProjects:            String("rp"),
  1284  			RepositoryPreReceiveHooks:     String("rprh"),
  1285  			Secrets:                       String("s"),
  1286  			SecretScanningAlerts:          String("ssa"),
  1287  			SecurityEvents:                String("se"),
  1288  			SingleFile:                    String("sf"),
  1289  			Statuses:                      String("s"),
  1290  			TeamDiscussions:               String("td"),
  1291  			VulnerabilityAlerts:           String("va"),
  1292  			Workflows:                     String("w"),
  1293  		},
  1294  		Events: []string{"s"},
  1295  	}
  1296  
  1297  	want := `{
  1298  		"id": 1,
  1299  		"slug": "s",
  1300  		"node_id": "nid",
  1301  		"owner": {
  1302  			"login": "l",
  1303  			"id": 1,
  1304  			"avatar_url": "a",
  1305  			"gravatar_id": "g",
  1306  			"name": "n",
  1307  			"company": "c",
  1308  			"blog": "b",
  1309  			"location": "l",
  1310  			"email": "e",
  1311  			"hireable": true,
  1312  			"bio": "b",
  1313  			"twitter_username": "t",
  1314  			"public_repos": 1,
  1315  			"followers": 1,
  1316  			"following": 1,
  1317  			"created_at": ` + referenceTimeStr + `,
  1318  			"suspended_at": ` + referenceTimeStr + `,
  1319  			"url": "u"
  1320  		},
  1321  		"name": "n",
  1322  		"description": "d",
  1323  		"external_url": "eu",
  1324  		"html_url": "hu",
  1325  		"created_at": ` + referenceTimeStr + `,
  1326  		"updated_at": ` + referenceTimeStr + `,
  1327  		"permissions": {
  1328  			"actions": "a",
  1329  			"actions_variables": "ac",
  1330  			"administration": "ad",
  1331  			"checks": "c",
  1332  			"contents": "co",
  1333  			"content_references": "cr",
  1334  			"deployments": "d",
  1335  			"environments": "e",
  1336  			"issues": "i",
  1337  			"metadata": "md",
  1338  			"members": "m",
  1339  			"organization_administration": "oa",
  1340  			"organization_custom_org_roles": "ocr",
  1341  			"organization_hooks": "oh",
  1342  			"organization_plan": "op",
  1343  			"organization_pre_receive_hooks": "opr",
  1344  			"organization_projects": "op",
  1345  			"organization_secrets": "os",
  1346  			"organization_self_hosted_runners": "osh",
  1347  			"organization_user_blocking": "oub",
  1348  			"packages": "pkg",
  1349  			"pages": "pg",
  1350  			"pull_requests": "pr",
  1351  			"repository_hooks": "rh",
  1352  			"repository_projects": "rp",
  1353  			"repository_pre_receive_hooks": "rprh",
  1354  			"secrets": "s",
  1355  			"secret_scanning_alerts": "ssa",
  1356  			"security_events": "se",
  1357  			"single_file": "sf",
  1358  			"statuses": "s",
  1359  			"team_discussions": "td",
  1360  			"vulnerability_alerts": "va",
  1361  			"workflows": "w"
  1362  		},
  1363  		"events": ["s"]
  1364  	}`
  1365  
  1366  	testJSONMarshal(t, u, want)
  1367  }