github.com/google/go-github/v69@v69.2.0/github/orgs_members_test.go (about)

     1  // Copyright 2013 The go-github AUTHORS. All rights reserved.
     2  //
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package github
     7  
     8  import (
     9  	"context"
    10  	"encoding/json"
    11  	"fmt"
    12  	"net/http"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/google/go-cmp/cmp"
    17  )
    18  
    19  func TestOrganizationsService_ListMembers(t *testing.T) {
    20  	t.Parallel()
    21  	client, mux, _ := setup(t)
    22  
    23  	mux.HandleFunc("/orgs/o/members", func(w http.ResponseWriter, r *http.Request) {
    24  		testMethod(t, r, "GET")
    25  		testFormValues(t, r, values{
    26  			"filter": "2fa_disabled",
    27  			"role":   "admin",
    28  			"page":   "2",
    29  		})
    30  		fmt.Fprint(w, `[{"id":1}]`)
    31  	})
    32  
    33  	opt := &ListMembersOptions{
    34  		PublicOnly:  false,
    35  		Filter:      "2fa_disabled",
    36  		Role:        "admin",
    37  		ListOptions: ListOptions{Page: 2},
    38  	}
    39  	ctx := context.Background()
    40  	members, _, err := client.Organizations.ListMembers(ctx, "o", opt)
    41  	if err != nil {
    42  		t.Errorf("Organizations.ListMembers returned error: %v", err)
    43  	}
    44  
    45  	want := []*User{{ID: Ptr(int64(1))}}
    46  	if !cmp.Equal(members, want) {
    47  		t.Errorf("Organizations.ListMembers returned %+v, want %+v", members, want)
    48  	}
    49  
    50  	const methodName = "ListMembers"
    51  	testBadOptions(t, methodName, func() (err error) {
    52  		_, _, err = client.Organizations.ListMembers(ctx, "\n", opt)
    53  		return err
    54  	})
    55  
    56  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
    57  		got, resp, err := client.Organizations.ListMembers(ctx, "o", opt)
    58  		if got != nil {
    59  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
    60  		}
    61  		return resp, err
    62  	})
    63  }
    64  
    65  func TestOrganizationsService_ListMembers_invalidOrg(t *testing.T) {
    66  	t.Parallel()
    67  	client, _, _ := setup(t)
    68  
    69  	ctx := context.Background()
    70  	_, _, err := client.Organizations.ListMembers(ctx, "%", nil)
    71  	testURLParseError(t, err)
    72  }
    73  
    74  func TestOrganizationsService_ListMembers_public(t *testing.T) {
    75  	t.Parallel()
    76  	client, mux, _ := setup(t)
    77  
    78  	mux.HandleFunc("/orgs/o/public_members", func(w http.ResponseWriter, r *http.Request) {
    79  		testMethod(t, r, "GET")
    80  		fmt.Fprint(w, `[{"id":1}]`)
    81  	})
    82  
    83  	opt := &ListMembersOptions{PublicOnly: true}
    84  	ctx := context.Background()
    85  	members, _, err := client.Organizations.ListMembers(ctx, "o", opt)
    86  	if err != nil {
    87  		t.Errorf("Organizations.ListMembers returned error: %v", err)
    88  	}
    89  
    90  	want := []*User{{ID: Ptr(int64(1))}}
    91  	if !cmp.Equal(members, want) {
    92  		t.Errorf("Organizations.ListMembers returned %+v, want %+v", members, want)
    93  	}
    94  }
    95  
    96  func TestOrganizationsService_IsMember(t *testing.T) {
    97  	t.Parallel()
    98  	client, mux, _ := setup(t)
    99  
   100  	mux.HandleFunc("/orgs/o/members/u", func(w http.ResponseWriter, r *http.Request) {
   101  		testMethod(t, r, "GET")
   102  		w.WriteHeader(http.StatusNoContent)
   103  	})
   104  
   105  	ctx := context.Background()
   106  	member, _, err := client.Organizations.IsMember(ctx, "o", "u")
   107  	if err != nil {
   108  		t.Errorf("Organizations.IsMember returned error: %v", err)
   109  	}
   110  	if want := true; member != want {
   111  		t.Errorf("Organizations.IsMember returned %+v, want %+v", member, want)
   112  	}
   113  
   114  	const methodName = "IsMember"
   115  	testBadOptions(t, methodName, func() (err error) {
   116  		_, _, err = client.Organizations.IsMember(ctx, "\n", "\n")
   117  		return err
   118  	})
   119  
   120  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   121  		got, resp, err := client.Organizations.IsMember(ctx, "o", "u")
   122  		if got {
   123  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   124  		}
   125  		return resp, err
   126  	})
   127  }
   128  
   129  // Ensure that a 404 response is interpreted as "false" and not an error.
   130  func TestOrganizationsService_IsMember_notMember(t *testing.T) {
   131  	t.Parallel()
   132  	client, mux, _ := setup(t)
   133  
   134  	mux.HandleFunc("/orgs/o/members/u", func(w http.ResponseWriter, r *http.Request) {
   135  		testMethod(t, r, "GET")
   136  		w.WriteHeader(http.StatusNotFound)
   137  	})
   138  
   139  	ctx := context.Background()
   140  	member, _, err := client.Organizations.IsMember(ctx, "o", "u")
   141  	if err != nil {
   142  		t.Errorf("Organizations.IsMember returned error: %+v", err)
   143  	}
   144  	if want := false; member != want {
   145  		t.Errorf("Organizations.IsMember returned %+v, want %+v", member, want)
   146  	}
   147  }
   148  
   149  // Ensure that a 400 response is interpreted as an actual error, and not simply
   150  // as "false" like the above case of a 404.
   151  func TestOrganizationsService_IsMember_error(t *testing.T) {
   152  	t.Parallel()
   153  	client, mux, _ := setup(t)
   154  
   155  	mux.HandleFunc("/orgs/o/members/u", func(w http.ResponseWriter, r *http.Request) {
   156  		testMethod(t, r, "GET")
   157  		http.Error(w, "BadRequest", http.StatusBadRequest)
   158  	})
   159  
   160  	ctx := context.Background()
   161  	member, _, err := client.Organizations.IsMember(ctx, "o", "u")
   162  	if err == nil {
   163  		t.Errorf("Expected HTTP 400 response")
   164  	}
   165  	if want := false; member != want {
   166  		t.Errorf("Organizations.IsMember returned %+v, want %+v", member, want)
   167  	}
   168  }
   169  
   170  func TestOrganizationsService_IsMember_invalidOrg(t *testing.T) {
   171  	t.Parallel()
   172  	client, _, _ := setup(t)
   173  
   174  	ctx := context.Background()
   175  	_, _, err := client.Organizations.IsMember(ctx, "%", "u")
   176  	testURLParseError(t, err)
   177  }
   178  
   179  func TestOrganizationsService_IsPublicMember(t *testing.T) {
   180  	t.Parallel()
   181  	client, mux, _ := setup(t)
   182  
   183  	mux.HandleFunc("/orgs/o/public_members/u", func(w http.ResponseWriter, r *http.Request) {
   184  		testMethod(t, r, "GET")
   185  		w.WriteHeader(http.StatusNoContent)
   186  	})
   187  
   188  	ctx := context.Background()
   189  	member, _, err := client.Organizations.IsPublicMember(ctx, "o", "u")
   190  	if err != nil {
   191  		t.Errorf("Organizations.IsPublicMember returned error: %v", err)
   192  	}
   193  	if want := true; member != want {
   194  		t.Errorf("Organizations.IsPublicMember returned %+v, want %+v", member, want)
   195  	}
   196  
   197  	const methodName = "IsPublicMember"
   198  	testBadOptions(t, methodName, func() (err error) {
   199  		_, _, err = client.Organizations.IsPublicMember(ctx, "\n", "\n")
   200  		return err
   201  	})
   202  
   203  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   204  		got, resp, err := client.Organizations.IsPublicMember(ctx, "o", "u")
   205  		if got {
   206  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   207  		}
   208  		return resp, err
   209  	})
   210  }
   211  
   212  // Ensure that a 404 response is interpreted as "false" and not an error.
   213  func TestOrganizationsService_IsPublicMember_notMember(t *testing.T) {
   214  	t.Parallel()
   215  	client, mux, _ := setup(t)
   216  
   217  	mux.HandleFunc("/orgs/o/public_members/u", func(w http.ResponseWriter, r *http.Request) {
   218  		testMethod(t, r, "GET")
   219  		w.WriteHeader(http.StatusNotFound)
   220  	})
   221  
   222  	ctx := context.Background()
   223  	member, _, err := client.Organizations.IsPublicMember(ctx, "o", "u")
   224  	if err != nil {
   225  		t.Errorf("Organizations.IsPublicMember returned error: %v", err)
   226  	}
   227  	if want := false; member != want {
   228  		t.Errorf("Organizations.IsPublicMember returned %+v, want %+v", member, want)
   229  	}
   230  }
   231  
   232  // Ensure that a 400 response is interpreted as an actual error, and not simply
   233  // as "false" like the above case of a 404.
   234  func TestOrganizationsService_IsPublicMember_error(t *testing.T) {
   235  	t.Parallel()
   236  	client, mux, _ := setup(t)
   237  
   238  	mux.HandleFunc("/orgs/o/public_members/u", func(w http.ResponseWriter, r *http.Request) {
   239  		testMethod(t, r, "GET")
   240  		http.Error(w, "BadRequest", http.StatusBadRequest)
   241  	})
   242  
   243  	ctx := context.Background()
   244  	member, _, err := client.Organizations.IsPublicMember(ctx, "o", "u")
   245  	if err == nil {
   246  		t.Errorf("Expected HTTP 400 response")
   247  	}
   248  	if want := false; member != want {
   249  		t.Errorf("Organizations.IsPublicMember returned %+v, want %+v", member, want)
   250  	}
   251  }
   252  
   253  func TestOrganizationsService_IsPublicMember_invalidOrg(t *testing.T) {
   254  	t.Parallel()
   255  	client, _, _ := setup(t)
   256  
   257  	ctx := context.Background()
   258  	_, _, err := client.Organizations.IsPublicMember(ctx, "%", "u")
   259  	testURLParseError(t, err)
   260  }
   261  
   262  func TestOrganizationsService_RemoveMember(t *testing.T) {
   263  	t.Parallel()
   264  	client, mux, _ := setup(t)
   265  
   266  	mux.HandleFunc("/orgs/o/members/u", func(w http.ResponseWriter, r *http.Request) {
   267  		testMethod(t, r, "DELETE")
   268  	})
   269  
   270  	ctx := context.Background()
   271  	_, err := client.Organizations.RemoveMember(ctx, "o", "u")
   272  	if err != nil {
   273  		t.Errorf("Organizations.RemoveMember returned error: %v", err)
   274  	}
   275  
   276  	const methodName = "RemoveMember"
   277  	testBadOptions(t, methodName, func() (err error) {
   278  		_, err = client.Organizations.RemoveMember(ctx, "\n", "\n")
   279  		return err
   280  	})
   281  
   282  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   283  		return client.Organizations.RemoveMember(ctx, "o", "u")
   284  	})
   285  }
   286  
   287  func TestOrganizationsService_CancelInvite(t *testing.T) {
   288  	t.Parallel()
   289  	client, mux, _ := setup(t)
   290  
   291  	mux.HandleFunc("/orgs/o/invitations/1", func(w http.ResponseWriter, r *http.Request) {
   292  		testMethod(t, r, "DELETE")
   293  		w.WriteHeader(http.StatusNoContent)
   294  	})
   295  
   296  	ctx := context.Background()
   297  	_, err := client.Organizations.CancelInvite(ctx, "o", 1)
   298  	if err != nil {
   299  		t.Errorf("Organizations.CancelInvite returned error: %v", err)
   300  	}
   301  
   302  	const methodName = "CancelInvite"
   303  	testBadOptions(t, methodName, func() (err error) {
   304  		_, err = client.Organizations.CancelInvite(ctx, "\n", 1)
   305  		return err
   306  	})
   307  
   308  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   309  		return client.Organizations.CancelInvite(ctx, "o", 1)
   310  	})
   311  }
   312  
   313  func TestOrganizationsService_RemoveMember_invalidOrg(t *testing.T) {
   314  	t.Parallel()
   315  	client, _, _ := setup(t)
   316  
   317  	ctx := context.Background()
   318  	_, err := client.Organizations.RemoveMember(ctx, "%", "u")
   319  	testURLParseError(t, err)
   320  }
   321  
   322  func TestOrganizationsService_PublicizeMembership(t *testing.T) {
   323  	t.Parallel()
   324  	client, mux, _ := setup(t)
   325  
   326  	mux.HandleFunc("/orgs/o/public_members/u", func(w http.ResponseWriter, r *http.Request) {
   327  		testMethod(t, r, "PUT")
   328  	})
   329  
   330  	ctx := context.Background()
   331  	_, err := client.Organizations.PublicizeMembership(ctx, "o", "u")
   332  	if err != nil {
   333  		t.Errorf("Organizations.PublicizeMembership returned error: %v", err)
   334  	}
   335  
   336  	const methodName = "PublicizeMembership"
   337  	testBadOptions(t, methodName, func() (err error) {
   338  		_, err = client.Organizations.PublicizeMembership(ctx, "\n", "\n")
   339  		return err
   340  	})
   341  
   342  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   343  		return client.Organizations.PublicizeMembership(ctx, "o", "u")
   344  	})
   345  }
   346  
   347  func TestOrganizationsService_ConcealMembership(t *testing.T) {
   348  	t.Parallel()
   349  	client, mux, _ := setup(t)
   350  
   351  	mux.HandleFunc("/orgs/o/public_members/u", func(w http.ResponseWriter, r *http.Request) {
   352  		testMethod(t, r, "DELETE")
   353  	})
   354  
   355  	ctx := context.Background()
   356  	_, err := client.Organizations.ConcealMembership(ctx, "o", "u")
   357  	if err != nil {
   358  		t.Errorf("Organizations.ConcealMembership returned error: %v", err)
   359  	}
   360  
   361  	const methodName = "ConcealMembership"
   362  	testBadOptions(t, methodName, func() (err error) {
   363  		_, err = client.Organizations.ConcealMembership(ctx, "\n", "\n")
   364  		return err
   365  	})
   366  
   367  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   368  		return client.Organizations.ConcealMembership(ctx, "o", "u")
   369  	})
   370  }
   371  
   372  func TestOrganizationsService_ListOrgMemberships(t *testing.T) {
   373  	t.Parallel()
   374  	client, mux, _ := setup(t)
   375  
   376  	mux.HandleFunc("/user/memberships/orgs", func(w http.ResponseWriter, r *http.Request) {
   377  		testMethod(t, r, "GET")
   378  		testFormValues(t, r, values{
   379  			"state": "active",
   380  			"page":  "2",
   381  		})
   382  		fmt.Fprint(w, `[{"url":"u"}]`)
   383  	})
   384  
   385  	opt := &ListOrgMembershipsOptions{
   386  		State:       "active",
   387  		ListOptions: ListOptions{Page: 2},
   388  	}
   389  	ctx := context.Background()
   390  	memberships, _, err := client.Organizations.ListOrgMemberships(ctx, opt)
   391  	if err != nil {
   392  		t.Errorf("Organizations.ListOrgMemberships returned error: %v", err)
   393  	}
   394  
   395  	want := []*Membership{{URL: Ptr("u")}}
   396  	if !cmp.Equal(memberships, want) {
   397  		t.Errorf("Organizations.ListOrgMemberships returned %+v, want %+v", memberships, want)
   398  	}
   399  
   400  	const methodName = "ListOrgMemberships"
   401  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   402  		got, resp, err := client.Organizations.ListOrgMemberships(ctx, opt)
   403  		if got != nil {
   404  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   405  		}
   406  		return resp, err
   407  	})
   408  }
   409  
   410  func TestOrganizationsService_GetOrgMembership_AuthenticatedUser(t *testing.T) {
   411  	t.Parallel()
   412  	client, mux, _ := setup(t)
   413  
   414  	mux.HandleFunc("/user/memberships/orgs/o", func(w http.ResponseWriter, r *http.Request) {
   415  		testMethod(t, r, "GET")
   416  		fmt.Fprint(w, `{"url":"u"}`)
   417  	})
   418  
   419  	ctx := context.Background()
   420  	membership, _, err := client.Organizations.GetOrgMembership(ctx, "", "o")
   421  	if err != nil {
   422  		t.Errorf("Organizations.GetOrgMembership returned error: %v", err)
   423  	}
   424  
   425  	want := &Membership{URL: Ptr("u")}
   426  	if !cmp.Equal(membership, want) {
   427  		t.Errorf("Organizations.GetOrgMembership returned %+v, want %+v", membership, want)
   428  	}
   429  
   430  	const methodName = "GetOrgMembership"
   431  	testBadOptions(t, methodName, func() (err error) {
   432  		_, _, err = client.Organizations.GetOrgMembership(ctx, "\n", "\n")
   433  		return err
   434  	})
   435  
   436  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   437  		got, resp, err := client.Organizations.GetOrgMembership(ctx, "", "o")
   438  		if got != nil {
   439  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   440  		}
   441  		return resp, err
   442  	})
   443  }
   444  
   445  func TestOrganizationsService_GetOrgMembership_SpecifiedUser(t *testing.T) {
   446  	t.Parallel()
   447  	client, mux, _ := setup(t)
   448  
   449  	mux.HandleFunc("/orgs/o/memberships/u", func(w http.ResponseWriter, r *http.Request) {
   450  		testMethod(t, r, "GET")
   451  		fmt.Fprint(w, `{"url":"u"}`)
   452  	})
   453  
   454  	ctx := context.Background()
   455  	membership, _, err := client.Organizations.GetOrgMembership(ctx, "u", "o")
   456  	if err != nil {
   457  		t.Errorf("Organizations.GetOrgMembership returned error: %v", err)
   458  	}
   459  
   460  	want := &Membership{URL: Ptr("u")}
   461  	if !cmp.Equal(membership, want) {
   462  		t.Errorf("Organizations.GetOrgMembership returned %+v, want %+v", membership, want)
   463  	}
   464  }
   465  
   466  func TestOrganizationsService_EditOrgMembership_AuthenticatedUser(t *testing.T) {
   467  	t.Parallel()
   468  	client, mux, _ := setup(t)
   469  
   470  	input := &Membership{State: Ptr("active")}
   471  
   472  	mux.HandleFunc("/user/memberships/orgs/o", func(w http.ResponseWriter, r *http.Request) {
   473  		v := new(Membership)
   474  		assertNilError(t, json.NewDecoder(r.Body).Decode(v))
   475  
   476  		testMethod(t, r, "PATCH")
   477  		if !cmp.Equal(v, input) {
   478  			t.Errorf("Request body = %+v, want %+v", v, input)
   479  		}
   480  
   481  		fmt.Fprint(w, `{"url":"u"}`)
   482  	})
   483  
   484  	ctx := context.Background()
   485  	membership, _, err := client.Organizations.EditOrgMembership(ctx, "", "o", input)
   486  	if err != nil {
   487  		t.Errorf("Organizations.EditOrgMembership returned error: %v", err)
   488  	}
   489  
   490  	want := &Membership{URL: Ptr("u")}
   491  	if !cmp.Equal(membership, want) {
   492  		t.Errorf("Organizations.EditOrgMembership returned %+v, want %+v", membership, want)
   493  	}
   494  
   495  	const methodName = "EditOrgMembership"
   496  	testBadOptions(t, methodName, func() (err error) {
   497  		_, _, err = client.Organizations.EditOrgMembership(ctx, "\n", "\n", input)
   498  		return err
   499  	})
   500  
   501  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   502  		got, resp, err := client.Organizations.EditOrgMembership(ctx, "", "o", input)
   503  		if got != nil {
   504  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   505  		}
   506  		return resp, err
   507  	})
   508  }
   509  
   510  func TestOrganizationsService_EditOrgMembership_SpecifiedUser(t *testing.T) {
   511  	t.Parallel()
   512  	client, mux, _ := setup(t)
   513  
   514  	input := &Membership{State: Ptr("active")}
   515  
   516  	mux.HandleFunc("/orgs/o/memberships/u", func(w http.ResponseWriter, r *http.Request) {
   517  		v := new(Membership)
   518  		assertNilError(t, json.NewDecoder(r.Body).Decode(v))
   519  
   520  		testMethod(t, r, "PUT")
   521  		if !cmp.Equal(v, input) {
   522  			t.Errorf("Request body = %+v, want %+v", v, input)
   523  		}
   524  
   525  		fmt.Fprint(w, `{"url":"u"}`)
   526  	})
   527  
   528  	ctx := context.Background()
   529  	membership, _, err := client.Organizations.EditOrgMembership(ctx, "u", "o", input)
   530  	if err != nil {
   531  		t.Errorf("Organizations.EditOrgMembership returned error: %v", err)
   532  	}
   533  
   534  	want := &Membership{URL: Ptr("u")}
   535  	if !cmp.Equal(membership, want) {
   536  		t.Errorf("Organizations.EditOrgMembership returned %+v, want %+v", membership, want)
   537  	}
   538  }
   539  
   540  func TestOrganizationsService_RemoveOrgMembership(t *testing.T) {
   541  	t.Parallel()
   542  	client, mux, _ := setup(t)
   543  
   544  	mux.HandleFunc("/orgs/o/memberships/u", func(w http.ResponseWriter, r *http.Request) {
   545  		testMethod(t, r, "DELETE")
   546  		w.WriteHeader(http.StatusNoContent)
   547  	})
   548  
   549  	ctx := context.Background()
   550  	_, err := client.Organizations.RemoveOrgMembership(ctx, "u", "o")
   551  	if err != nil {
   552  		t.Errorf("Organizations.RemoveOrgMembership returned error: %v", err)
   553  	}
   554  
   555  	const methodName = "RemoveOrgMembership"
   556  	testBadOptions(t, methodName, func() (err error) {
   557  		_, err = client.Organizations.RemoveOrgMembership(ctx, "\n", "\n")
   558  		return err
   559  	})
   560  
   561  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   562  		return client.Organizations.RemoveOrgMembership(ctx, "u", "o")
   563  	})
   564  }
   565  
   566  func TestOrganizationsService_ListPendingOrgInvitations(t *testing.T) {
   567  	t.Parallel()
   568  	client, mux, _ := setup(t)
   569  
   570  	mux.HandleFunc("/orgs/o/invitations", func(w http.ResponseWriter, r *http.Request) {
   571  		testMethod(t, r, "GET")
   572  		testFormValues(t, r, values{"page": "1"})
   573  		fmt.Fprint(w, `[
   574  				{
   575      					"id": 1,
   576      					"login": "monalisa",
   577      					"email": "octocat@github.com",
   578      					"role": "direct_member",
   579  					"created_at": "2017-01-21T00:00:00Z",
   580      					"inviter": {
   581        						"login": "other_user",
   582        						"id": 1,
   583        						"avatar_url": "https://github.com/images/error/other_user_happy.gif",
   584        						"gravatar_id": "",
   585        						"url": "https://api.github.com/users/other_user",
   586        						"html_url": "https://github.com/other_user",
   587        						"followers_url": "https://api.github.com/users/other_user/followers",
   588        						"following_url": "https://api.github.com/users/other_user/following/other_user",
   589        						"gists_url": "https://api.github.com/users/other_user/gists/gist_id",
   590        						"starred_url": "https://api.github.com/users/other_user/starred/owner/repo",
   591        						"subscriptions_url": "https://api.github.com/users/other_user/subscriptions",
   592        						"organizations_url": "https://api.github.com/users/other_user/orgs",
   593        						"repos_url": "https://api.github.com/users/other_user/repos",
   594        						"events_url": "https://api.github.com/users/other_user/events/privacy",
   595        						"received_events_url": "https://api.github.com/users/other_user/received_events/privacy",
   596        						"type": "User",
   597        						"site_admin": false
   598  						},
   599  						"team_count": 2,
   600  						"invitation_team_url": "https://api.github.com/organizations/2/invitations/1/teams"
   601    				}
   602  			]`)
   603  	})
   604  
   605  	opt := &ListOptions{Page: 1}
   606  	ctx := context.Background()
   607  	invitations, _, err := client.Organizations.ListPendingOrgInvitations(ctx, "o", opt)
   608  	if err != nil {
   609  		t.Errorf("Organizations.ListPendingOrgInvitations returned error: %v", err)
   610  	}
   611  
   612  	createdAt := time.Date(2017, time.January, 21, 0, 0, 0, 0, time.UTC)
   613  	want := []*Invitation{
   614  		{
   615  			ID:        Ptr(int64(1)),
   616  			Login:     Ptr("monalisa"),
   617  			Email:     Ptr("octocat@github.com"),
   618  			Role:      Ptr("direct_member"),
   619  			CreatedAt: &Timestamp{createdAt},
   620  			Inviter: &User{
   621  				Login:             Ptr("other_user"),
   622  				ID:                Ptr(int64(1)),
   623  				AvatarURL:         Ptr("https://github.com/images/error/other_user_happy.gif"),
   624  				GravatarID:        Ptr(""),
   625  				URL:               Ptr("https://api.github.com/users/other_user"),
   626  				HTMLURL:           Ptr("https://github.com/other_user"),
   627  				FollowersURL:      Ptr("https://api.github.com/users/other_user/followers"),
   628  				FollowingURL:      Ptr("https://api.github.com/users/other_user/following/other_user"),
   629  				GistsURL:          Ptr("https://api.github.com/users/other_user/gists/gist_id"),
   630  				StarredURL:        Ptr("https://api.github.com/users/other_user/starred/owner/repo"),
   631  				SubscriptionsURL:  Ptr("https://api.github.com/users/other_user/subscriptions"),
   632  				OrganizationsURL:  Ptr("https://api.github.com/users/other_user/orgs"),
   633  				ReposURL:          Ptr("https://api.github.com/users/other_user/repos"),
   634  				EventsURL:         Ptr("https://api.github.com/users/other_user/events/privacy"),
   635  				ReceivedEventsURL: Ptr("https://api.github.com/users/other_user/received_events/privacy"),
   636  				Type:              Ptr("User"),
   637  				SiteAdmin:         Ptr(false),
   638  			},
   639  			TeamCount:         Ptr(2),
   640  			InvitationTeamURL: Ptr("https://api.github.com/organizations/2/invitations/1/teams"),
   641  		}}
   642  
   643  	if !cmp.Equal(invitations, want) {
   644  		t.Errorf("Organizations.ListPendingOrgInvitations returned %+v, want %+v", invitations, want)
   645  	}
   646  
   647  	const methodName = "ListPendingOrgInvitations"
   648  	testBadOptions(t, methodName, func() (err error) {
   649  		_, _, err = client.Organizations.ListPendingOrgInvitations(ctx, "\n", opt)
   650  		return err
   651  	})
   652  
   653  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   654  		got, resp, err := client.Organizations.ListPendingOrgInvitations(ctx, "o", opt)
   655  		if got != nil {
   656  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   657  		}
   658  		return resp, err
   659  	})
   660  }
   661  
   662  func TestOrganizationsService_CreateOrgInvitation(t *testing.T) {
   663  	t.Parallel()
   664  	client, mux, _ := setup(t)
   665  
   666  	input := &CreateOrgInvitationOptions{
   667  		Email: Ptr("octocat@github.com"),
   668  		Role:  Ptr("direct_member"),
   669  		TeamID: []int64{
   670  			12,
   671  			26,
   672  		},
   673  	}
   674  
   675  	mux.HandleFunc("/orgs/o/invitations", func(w http.ResponseWriter, r *http.Request) {
   676  		v := new(CreateOrgInvitationOptions)
   677  		assertNilError(t, json.NewDecoder(r.Body).Decode(v))
   678  
   679  		testMethod(t, r, "POST")
   680  		if !cmp.Equal(v, input) {
   681  			t.Errorf("Request body = %+v, want %+v", v, input)
   682  		}
   683  
   684  		fmt.Fprintln(w, `{"email": "octocat@github.com"}`)
   685  	})
   686  
   687  	ctx := context.Background()
   688  	invitations, _, err := client.Organizations.CreateOrgInvitation(ctx, "o", input)
   689  	if err != nil {
   690  		t.Errorf("Organizations.CreateOrgInvitation returned error: %v", err)
   691  	}
   692  
   693  	want := &Invitation{Email: Ptr("octocat@github.com")}
   694  	if !cmp.Equal(invitations, want) {
   695  		t.Errorf("Organizations.ListPendingOrgInvitations returned %+v, want %+v", invitations, want)
   696  	}
   697  
   698  	const methodName = "CreateOrgInvitation"
   699  	testBadOptions(t, methodName, func() (err error) {
   700  		_, _, err = client.Organizations.CreateOrgInvitation(ctx, "\n", input)
   701  		return err
   702  	})
   703  
   704  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   705  		got, resp, err := client.Organizations.CreateOrgInvitation(ctx, "o", input)
   706  		if got != nil {
   707  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   708  		}
   709  		return resp, err
   710  	})
   711  }
   712  
   713  func TestOrganizationsService_ListOrgInvitationTeams(t *testing.T) {
   714  	t.Parallel()
   715  	client, mux, _ := setup(t)
   716  
   717  	mux.HandleFunc("/orgs/o/invitations/22/teams", func(w http.ResponseWriter, r *http.Request) {
   718  		testMethod(t, r, "GET")
   719  		testFormValues(t, r, values{"page": "1"})
   720  		fmt.Fprint(w, `[
   721  			{
   722  				"id": 1,
   723  				"url": "https://api.github.com/teams/1",
   724  				"name": "Justice League",
   725  				"slug": "justice-league",
   726  				"description": "A great team.",
   727  				"privacy": "closed",
   728  				"permission": "admin",
   729  				"members_url": "https://api.github.com/teams/1/members{/member}",
   730  				"repositories_url": "https://api.github.com/teams/1/repos"
   731  			  }
   732  			]`)
   733  	})
   734  
   735  	opt := &ListOptions{Page: 1}
   736  	ctx := context.Background()
   737  	invitations, _, err := client.Organizations.ListOrgInvitationTeams(ctx, "o", "22", opt)
   738  	if err != nil {
   739  		t.Errorf("Organizations.ListOrgInvitationTeams returned error: %v", err)
   740  	}
   741  
   742  	want := []*Team{
   743  		{
   744  			ID:              Ptr(int64(1)),
   745  			URL:             Ptr("https://api.github.com/teams/1"),
   746  			Name:            Ptr("Justice League"),
   747  			Slug:            Ptr("justice-league"),
   748  			Description:     Ptr("A great team."),
   749  			Privacy:         Ptr("closed"),
   750  			Permission:      Ptr("admin"),
   751  			MembersURL:      Ptr("https://api.github.com/teams/1/members{/member}"),
   752  			RepositoriesURL: Ptr("https://api.github.com/teams/1/repos"),
   753  		},
   754  	}
   755  
   756  	if !cmp.Equal(invitations, want) {
   757  		t.Errorf("Organizations.ListOrgInvitationTeams returned %+v, want %+v", invitations, want)
   758  	}
   759  
   760  	const methodName = "ListOrgInvitationTeams"
   761  	testBadOptions(t, methodName, func() (err error) {
   762  		_, _, err = client.Organizations.ListOrgInvitationTeams(ctx, "\n", "\n", opt)
   763  		return err
   764  	})
   765  
   766  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   767  		got, resp, err := client.Organizations.ListOrgInvitationTeams(ctx, "o", "22", opt)
   768  		if got != nil {
   769  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   770  		}
   771  		return resp, err
   772  	})
   773  }
   774  
   775  func TestOrganizationsService_ListFailedOrgInvitations(t *testing.T) {
   776  	t.Parallel()
   777  	client, mux, _ := setup(t)
   778  
   779  	mux.HandleFunc("/orgs/o/failed_invitations", func(w http.ResponseWriter, r *http.Request) {
   780  		testMethod(t, r, "GET")
   781  		testFormValues(t, r, values{"page": "2", "per_page": "1"})
   782  		fmt.Fprint(w, `[
   783  			{
   784  			   "id":1,
   785  			   "login":"monalisa",
   786  			   "node_id":"MDQ6VXNlcjE=",
   787  			   "email":"octocat@github.com",
   788  			   "role":"direct_member",
   789  			   "created_at":"2016-11-30T06:46:10Z",
   790  			   "failed_at":"2017-01-02T01:10:00Z",
   791  			   "failed_reason":"the reason",
   792  			   "inviter":{
   793  				  "login":"other_user",
   794  				  "id":1,
   795  				  "node_id":"MDQ6VXNlcjE=",
   796  				  "avatar_url":"https://github.com/images/error/other_user_happy.gif",
   797  				  "gravatar_id":"",
   798  				  "url":"https://api.github.com/users/other_user",
   799  				  "html_url":"https://github.com/other_user",
   800  				  "followers_url":"https://api.github.com/users/other_user/followers",
   801  				  "following_url":"https://api.github.com/users/other_user/following{/other_user}",
   802  				  "gists_url":"https://api.github.com/users/other_user/gists{/gist_id}",
   803  				  "starred_url":"https://api.github.com/users/other_user/starred{/owner}{/repo}",
   804  				  "subscriptions_url":"https://api.github.com/users/other_user/subscriptions",
   805  				  "organizations_url":"https://api.github.com/users/other_user/orgs",
   806  				  "repos_url":"https://api.github.com/users/other_user/repos",
   807  				  "events_url":"https://api.github.com/users/other_user/events{/privacy}",
   808  				  "received_events_url":"https://api.github.com/users/other_user/received_events",
   809  				  "type":"User",
   810  				  "site_admin":false
   811  			   },
   812  			   "team_count":2,
   813  			   "invitation_team_url":"https://api.github.com/organizations/2/invitations/1/teams"
   814  			}
   815  		]`)
   816  	})
   817  
   818  	opts := &ListOptions{Page: 2, PerPage: 1}
   819  	ctx := context.Background()
   820  	failedInvitations, _, err := client.Organizations.ListFailedOrgInvitations(ctx, "o", opts)
   821  	if err != nil {
   822  		t.Errorf("Organizations.ListFailedOrgInvitations returned error: %v", err)
   823  	}
   824  
   825  	createdAt := time.Date(2016, time.November, 30, 6, 46, 10, 0, time.UTC)
   826  	want := []*Invitation{
   827  		{
   828  			ID:           Ptr(int64(1)),
   829  			Login:        Ptr("monalisa"),
   830  			NodeID:       Ptr("MDQ6VXNlcjE="),
   831  			Email:        Ptr("octocat@github.com"),
   832  			Role:         Ptr("direct_member"),
   833  			FailedAt:     &Timestamp{time.Date(2017, time.January, 2, 1, 10, 0, 0, time.UTC)},
   834  			FailedReason: Ptr("the reason"),
   835  			CreatedAt:    &Timestamp{createdAt},
   836  			Inviter: &User{
   837  				Login:             Ptr("other_user"),
   838  				ID:                Ptr(int64(1)),
   839  				NodeID:            Ptr("MDQ6VXNlcjE="),
   840  				AvatarURL:         Ptr("https://github.com/images/error/other_user_happy.gif"),
   841  				GravatarID:        Ptr(""),
   842  				URL:               Ptr("https://api.github.com/users/other_user"),
   843  				HTMLURL:           Ptr("https://github.com/other_user"),
   844  				FollowersURL:      Ptr("https://api.github.com/users/other_user/followers"),
   845  				FollowingURL:      Ptr("https://api.github.com/users/other_user/following{/other_user}"),
   846  				GistsURL:          Ptr("https://api.github.com/users/other_user/gists{/gist_id}"),
   847  				StarredURL:        Ptr("https://api.github.com/users/other_user/starred{/owner}{/repo}"),
   848  				SubscriptionsURL:  Ptr("https://api.github.com/users/other_user/subscriptions"),
   849  				OrganizationsURL:  Ptr("https://api.github.com/users/other_user/orgs"),
   850  				ReposURL:          Ptr("https://api.github.com/users/other_user/repos"),
   851  				EventsURL:         Ptr("https://api.github.com/users/other_user/events{/privacy}"),
   852  				ReceivedEventsURL: Ptr("https://api.github.com/users/other_user/received_events"),
   853  				Type:              Ptr("User"),
   854  				SiteAdmin:         Ptr(false),
   855  			},
   856  			TeamCount:         Ptr(2),
   857  			InvitationTeamURL: Ptr("https://api.github.com/organizations/2/invitations/1/teams"),
   858  		},
   859  	}
   860  
   861  	if !cmp.Equal(failedInvitations, want) {
   862  		t.Errorf("Organizations.ListFailedOrgInvitations returned %+v, want %+v", failedInvitations, want)
   863  	}
   864  
   865  	const methodName = "ListFailedOrgInvitations"
   866  	testBadOptions(t, methodName, func() error {
   867  		_, _, err := client.Organizations.ListFailedOrgInvitations(ctx, "\n", opts)
   868  		return err
   869  	})
   870  
   871  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   872  		got, resp, err := client.Organizations.ListFailedOrgInvitations(ctx, "o", opts)
   873  		if got != nil {
   874  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   875  		}
   876  		return resp, err
   877  	})
   878  }
   879  
   880  func TestMembership_Marshal(t *testing.T) {
   881  	t.Parallel()
   882  	testJSONMarshal(t, &Membership{}, "{}")
   883  
   884  	u := &Membership{
   885  		URL:             Ptr("url"),
   886  		State:           Ptr("state"),
   887  		Role:            Ptr("email"),
   888  		OrganizationURL: Ptr("orgurl"),
   889  		Organization: &Organization{
   890  			BillingEmail:                         Ptr("be"),
   891  			Blog:                                 Ptr("b"),
   892  			Company:                              Ptr("c"),
   893  			Email:                                Ptr("e"),
   894  			TwitterUsername:                      Ptr("tu"),
   895  			Location:                             Ptr("loc"),
   896  			Name:                                 Ptr("n"),
   897  			Description:                          Ptr("d"),
   898  			IsVerified:                           Ptr(true),
   899  			HasOrganizationProjects:              Ptr(true),
   900  			HasRepositoryProjects:                Ptr(true),
   901  			DefaultRepoPermission:                Ptr("drp"),
   902  			MembersCanCreateRepos:                Ptr(true),
   903  			MembersCanCreateInternalRepos:        Ptr(true),
   904  			MembersCanCreatePrivateRepos:         Ptr(true),
   905  			MembersCanCreatePublicRepos:          Ptr(false),
   906  			MembersAllowedRepositoryCreationType: Ptr("marct"),
   907  			MembersCanCreatePages:                Ptr(true),
   908  			MembersCanCreatePublicPages:          Ptr(false),
   909  			MembersCanCreatePrivatePages:         Ptr(true),
   910  		},
   911  		User: &User{
   912  			Login:     Ptr("l"),
   913  			ID:        Ptr(int64(1)),
   914  			NodeID:    Ptr("n"),
   915  			URL:       Ptr("u"),
   916  			ReposURL:  Ptr("r"),
   917  			EventsURL: Ptr("e"),
   918  			AvatarURL: Ptr("a"),
   919  		},
   920  	}
   921  
   922  	want := `{
   923  		"url": "url",
   924  		"state": "state",
   925  		"role": "email",
   926  		"organization_url": "orgurl",
   927  		"organization": {
   928  			"name": "n",
   929  			"company": "c",
   930  			"blog": "b",
   931  			"location": "loc",
   932  			"email": "e",
   933  			"twitter_username": "tu",
   934  			"description": "d",
   935  			"billing_email": "be",
   936  			"is_verified": true,
   937  			"has_organization_projects": true,
   938  			"has_repository_projects": true,
   939  			"default_repository_permission": "drp",
   940  			"members_can_create_repositories": true,
   941  			"members_can_create_public_repositories": false,
   942  			"members_can_create_private_repositories": true,
   943  			"members_can_create_internal_repositories": true,
   944  			"members_allowed_repository_creation_type": "marct",
   945  			"members_can_create_pages": true,
   946  			"members_can_create_public_pages": false,
   947  			"members_can_create_private_pages": true
   948  		},
   949  		"user": {
   950  			"login": "l",
   951  			"id": 1,
   952  			"node_id": "n",
   953  			"avatar_url": "a",
   954  			"url": "u",
   955  			"events_url": "e",
   956  			"repos_url": "r"
   957  		}
   958  	}`
   959  
   960  	testJSONMarshal(t, u, want)
   961  }
   962  
   963  func TestCreateOrgInvitationOptions_Marshal(t *testing.T) {
   964  	t.Parallel()
   965  	testJSONMarshal(t, &CreateOrgInvitationOptions{}, "{}")
   966  
   967  	u := &CreateOrgInvitationOptions{
   968  		InviteeID: Ptr(int64(1)),
   969  		Email:     Ptr("email"),
   970  		Role:      Ptr("role"),
   971  		TeamID:    []int64{1},
   972  	}
   973  
   974  	want := `{
   975  		"invitee_id": 1,
   976  		"email": "email",
   977  		"role": "role",
   978  		"team_ids": [
   979  			1
   980  		]
   981  	}`
   982  
   983  	testJSONMarshal(t, u, want)
   984  }