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