github.com/google/go-github/v68@v68.0.0/github/repos_rules_test.go (about)

     1  // Copyright 2023 The go-github AUTHORS. All rights reserved.
     2  //
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package github
     7  
     8  import (
     9  	"context"
    10  	"fmt"
    11  	"net/http"
    12  	"testing"
    13  
    14  	"github.com/google/go-cmp/cmp"
    15  )
    16  
    17  func TestRepositoryRule_UnmarshalJSON(t *testing.T) {
    18  	t.Parallel()
    19  	tests := map[string]struct {
    20  		data    string
    21  		want    *RepositoryRule
    22  		wantErr bool
    23  	}{
    24  		"Invalid JSON": {
    25  			data: `{`,
    26  			want: &RepositoryRule{
    27  				Type:       "",
    28  				Parameters: nil,
    29  			},
    30  			wantErr: true,
    31  		},
    32  		"With Metadata": {
    33  			data: `{
    34                      "type": "creation",
    35  					"ruleset_source_type": "Repository",
    36  					"ruleset_source": "google",
    37  					"ruleset_id": 1984
    38             		   }`,
    39  			want: &RepositoryRule{
    40  				RulesetSource:     "google",
    41  				RulesetSourceType: "Repository",
    42  				RulesetID:         1984,
    43  				Type:              "creation",
    44  			},
    45  		},
    46  		"Valid creation": {
    47  			data: `{"type":"creation"}`,
    48  			want: NewCreationRule(),
    49  		},
    50  		"Valid deletion": {
    51  			data: `{"type":"deletion"}`,
    52  			want: &RepositoryRule{
    53  				Type:       "deletion",
    54  				Parameters: nil,
    55  			},
    56  		},
    57  		"Valid required_linear_history": {
    58  			data: `{"type":"required_linear_history"}`,
    59  			want: &RepositoryRule{
    60  				Type:       "required_linear_history",
    61  				Parameters: nil,
    62  			},
    63  		},
    64  		"Valid required_signatures": {
    65  			data: `{"type":"required_signatures"}`,
    66  			want: &RepositoryRule{
    67  				Type:       "required_signatures",
    68  				Parameters: nil,
    69  			},
    70  		},
    71  		"Valid merge_queue": {
    72  			data: `{"type":"merge_queue"}`,
    73  			want: &RepositoryRule{
    74  				Type:       "merge_queue",
    75  				Parameters: nil,
    76  			},
    77  		},
    78  		"Valid merge_queue with params": {
    79  			data: `{
    80  				"type":"merge_queue",
    81  				"parameters":{
    82  					"check_response_timeout_minutes": 35,
    83  					"grouping_strategy": "HEADGREEN",
    84  					"max_entries_to_build": 8,
    85  					"max_entries_to_merge": 4,
    86  					"merge_method": "SQUASH",
    87  					"min_entries_to_merge": 2,
    88  					"min_entries_to_merge_wait_minutes": 13
    89  				}
    90  			}`,
    91  			want: NewMergeQueueRule(&MergeQueueRuleParameters{
    92  				CheckResponseTimeoutMinutes:  35,
    93  				GroupingStrategy:             "HEADGREEN",
    94  				MaxEntriesToBuild:            8,
    95  				MaxEntriesToMerge:            4,
    96  				MergeMethod:                  "SQUASH",
    97  				MinEntriesToMerge:            2,
    98  				MinEntriesToMergeWaitMinutes: 13,
    99  			}),
   100  		},
   101  		"Invalid merge_queue with params": {
   102  			data: `{
   103  				"type":"merge_queue",
   104  				"parameters":{
   105  					"check_response_timeout_minutes": "35",
   106  					"grouping_strategy": "HEADGREEN",
   107  					"max_entries_to_build": "8",
   108  					"max_entries_to_merge": "4",
   109  					"merge_method": "SQUASH",
   110  					"min_entries_to_merge": "2",
   111  					"min_entries_to_merge_wait_minutes": "13"
   112  				}
   113  			}`,
   114  			want: &RepositoryRule{
   115  				Type:       "merge_queue",
   116  				Parameters: nil,
   117  			},
   118  			wantErr: true,
   119  		},
   120  		"Valid non_fast_forward": {
   121  			data: `{"type":"non_fast_forward"}`,
   122  			want: &RepositoryRule{
   123  				Type:       "non_fast_forward",
   124  				Parameters: nil,
   125  			},
   126  		},
   127  		"Valid update params": {
   128  			data: `{"type":"update","parameters":{"update_allows_fetch_and_merge":true}}`,
   129  			want: NewUpdateRule(&UpdateAllowsFetchAndMergeRuleParameters{UpdateAllowsFetchAndMerge: true}),
   130  		},
   131  		"Invalid update params": {
   132  			data: `{"type":"update","parameters":{"update_allows_fetch_and_merge":"true"}}`,
   133  			want: &RepositoryRule{
   134  				Type:       "update",
   135  				Parameters: nil,
   136  			},
   137  			wantErr: true,
   138  		},
   139  		"Valid required_deployments params": {
   140  			data: `{"type":"required_deployments","parameters":{"required_deployment_environments":["test"]}}`,
   141  			want: NewRequiredDeploymentsRule(&RequiredDeploymentEnvironmentsRuleParameters{
   142  				RequiredDeploymentEnvironments: []string{"test"},
   143  			}),
   144  		},
   145  		"Invalid required_deployments params": {
   146  			data: `{"type":"required_deployments","parameters":{"required_deployment_environments":true}}`,
   147  			want: &RepositoryRule{
   148  				Type:       "required_deployments",
   149  				Parameters: nil,
   150  			},
   151  			wantErr: true,
   152  		},
   153  		"Valid commit_message_pattern params": {
   154  			data: `{"type":"commit_message_pattern","parameters":{"operator":"starts_with","pattern":"github"}}`,
   155  			want: NewCommitMessagePatternRule(&RulePatternParameters{
   156  				Operator: "starts_with",
   157  				Pattern:  "github",
   158  			}),
   159  		},
   160  		"Invalid commit_message_pattern params": {
   161  			data: `{"type":"commit_message_pattern","parameters":{"operator":"starts_with","pattern":1}}`,
   162  			want: &RepositoryRule{
   163  				Type:       "commit_message_pattern",
   164  				Parameters: nil,
   165  			},
   166  			wantErr: true,
   167  		},
   168  		"Valid commit_author_email_pattern params": {
   169  			data: `{"type":"commit_author_email_pattern","parameters":{"operator":"starts_with","pattern":"github"}}`,
   170  			want: NewCommitAuthorEmailPatternRule(&RulePatternParameters{
   171  				Operator: "starts_with",
   172  				Pattern:  "github",
   173  			}),
   174  		},
   175  		"Invalid commit_author_email_pattern params": {
   176  			data: `{"type":"commit_author_email_pattern","parameters":{"operator":"starts_with","pattern":1}}`,
   177  			want: &RepositoryRule{
   178  				Type:       "commit_author_email_pattern",
   179  				Parameters: nil,
   180  			},
   181  			wantErr: true,
   182  		},
   183  		"Valid committer_email_pattern params": {
   184  			data: `{"type":"committer_email_pattern","parameters":{"operator":"starts_with","pattern":"github"}}`,
   185  			want: NewCommitterEmailPatternRule(&RulePatternParameters{
   186  				Operator: "starts_with",
   187  				Pattern:  "github",
   188  			}),
   189  		},
   190  		"Invalid committer_email_pattern params": {
   191  			data: `{"type":"committer_email_pattern","parameters":{"operator":"starts_with","pattern":1}}`,
   192  			want: &RepositoryRule{
   193  				Type:       "committer_email_pattern",
   194  				Parameters: nil,
   195  			},
   196  			wantErr: true,
   197  		},
   198  		"Valid branch_name_pattern params": {
   199  			data: `{"type":"branch_name_pattern","parameters":{"operator":"starts_with","pattern":"github"}}`,
   200  			want: NewBranchNamePatternRule(&RulePatternParameters{
   201  				Operator: "starts_with",
   202  				Pattern:  "github",
   203  			}),
   204  		},
   205  		"Invalid branch_name_pattern params": {
   206  			data: `{"type":"branch_name_pattern","parameters":{"operator":"starts_with","pattern":1}}`,
   207  			want: &RepositoryRule{
   208  				Type:       "branch_name_pattern",
   209  				Parameters: nil,
   210  			},
   211  			wantErr: true,
   212  		},
   213  		"Valid tag_name_pattern params": {
   214  			data: `{"type":"tag_name_pattern","parameters":{"operator":"starts_with","pattern":"github"}}`,
   215  			want: NewTagNamePatternRule(&RulePatternParameters{
   216  				Operator: "starts_with",
   217  				Pattern:  "github",
   218  			}),
   219  		},
   220  		"Invalid tag_name_pattern params": {
   221  			data: `{"type":"tag_name_pattern","parameters":{"operator":"starts_with","pattern":1}}`,
   222  			want: &RepositoryRule{
   223  				Type:       "tag_name_pattern",
   224  				Parameters: nil,
   225  			},
   226  			wantErr: true,
   227  		},
   228  		"Valid file_path_restriction params": {
   229  			data: `{"type":"file_path_restriction","parameters":{"restricted_file_paths":["/a/file"]}}`,
   230  			want: NewFilePathRestrictionRule(&RuleFileParameters{
   231  				RestrictedFilePaths: &[]string{"/a/file"},
   232  			}),
   233  		},
   234  		"Invalid file_path_restriction params": {
   235  			data: `{"type":"file_path_restriction","parameters":{"restricted_file_paths":true}}`,
   236  			want: &RepositoryRule{
   237  				Type:       "file_path_restriction",
   238  				Parameters: nil,
   239  			},
   240  			wantErr: true,
   241  		},
   242  		"Valid pull_request params": {
   243  			data: `{
   244  				"type":"pull_request",
   245  				"parameters":{
   246  					"dismiss_stale_reviews_on_push": true,
   247  					"require_code_owner_review": true,
   248  					"require_last_push_approval": true,
   249  					"required_approving_review_count": 1,
   250  					"required_review_thread_resolution":true
   251  				}
   252  			}`,
   253  			want: NewPullRequestRule(&PullRequestRuleParameters{
   254  				DismissStaleReviewsOnPush:      true,
   255  				RequireCodeOwnerReview:         true,
   256  				RequireLastPushApproval:        true,
   257  				RequiredApprovingReviewCount:   1,
   258  				RequiredReviewThreadResolution: true,
   259  			}),
   260  		},
   261  		"Invalid pull_request params": {
   262  			data: `{"type":"pull_request","parameters": {"dismiss_stale_reviews_on_push":"true"}}`,
   263  			want: &RepositoryRule{
   264  				Type:       "pull_request",
   265  				Parameters: nil,
   266  			},
   267  			wantErr: true,
   268  		},
   269  		"Valid required_status_checks params": {
   270  			data: `{"type":"required_status_checks","parameters":{"required_status_checks":[{"context":"test","integration_id":1}],"strict_required_status_checks_policy":true,"do_not_enforce_on_create":true}}`,
   271  			want: NewRequiredStatusChecksRule(&RequiredStatusChecksRuleParameters{
   272  				DoNotEnforceOnCreate: Ptr(true),
   273  				RequiredStatusChecks: []RuleRequiredStatusChecks{
   274  					{
   275  						Context:       "test",
   276  						IntegrationID: Ptr(int64(1)),
   277  					},
   278  				},
   279  				StrictRequiredStatusChecksPolicy: true,
   280  			}),
   281  		},
   282  		"Invalid required_status_checks params": {
   283  			data: `{"type":"required_status_checks",
   284  			"parameters": {
   285  				"required_status_checks": [
   286  				  {
   287  					"context": 1
   288  				  }
   289  				]
   290  			  }}`,
   291  			want: &RepositoryRule{
   292  				Type:       "required_status_checks",
   293  				Parameters: nil,
   294  			},
   295  			wantErr: true,
   296  		},
   297  		"Valid Required workflows params": {
   298  			data: `{"type":"workflows","parameters":{"workflows":[{"path": ".github/workflows/test.yml", "repository_id": 1}]}}`,
   299  			want: NewRequiredWorkflowsRule(&RequiredWorkflowsRuleParameters{
   300  				RequiredWorkflows: []*RuleRequiredWorkflow{
   301  					{
   302  						Path:         ".github/workflows/test.yml",
   303  						RepositoryID: Ptr(int64(1)),
   304  					},
   305  				},
   306  			}),
   307  		},
   308  		"Invalid Required workflows params": {
   309  			data: `{"type":"workflows","parameters":{"workflows":[{"path": ".github/workflows/test.yml", "repository_id": "test"}]}}`,
   310  			want: &RepositoryRule{
   311  				Type:       "workflows",
   312  				Parameters: nil,
   313  			},
   314  			wantErr: true,
   315  		},
   316  		"Valid Required code_scanning params": {
   317  			data: `{"type":"code_scanning","parameters":{"code_scanning_tools":[{"tool": "CodeQL", "security_alerts_threshold": "high_or_higher", "alerts_threshold": "errors"}]}}`,
   318  			want: NewRequiredCodeScanningRule(&RequiredCodeScanningRuleParameters{
   319  				RequiredCodeScanningTools: []*RuleRequiredCodeScanningTool{
   320  					{
   321  						Tool:                    "CodeQL",
   322  						SecurityAlertsThreshold: "high_or_higher",
   323  						AlertsThreshold:         "errors",
   324  					},
   325  				},
   326  			}),
   327  		},
   328  		"Invalid Required code_scanning params": {
   329  			data: `{"type":"code_scanning","parameters":{"code_scanning_tools":[{"tool": 1}]}}`,
   330  			want: &RepositoryRule{
   331  				Type:       "code_scanning",
   332  				Parameters: nil,
   333  			},
   334  			wantErr: true,
   335  		},
   336  		"Invalid type": {
   337  			data: `{"type":"unknown"}`,
   338  			want: &RepositoryRule{
   339  				Type:       "",
   340  				Parameters: nil,
   341  			},
   342  			wantErr: true,
   343  		},
   344  		"Valid max_file_path_length params": {
   345  			data: `{"type":"max_file_path_length","parameters":{"max_file_path_length": 255}}`,
   346  			want: NewMaxFilePathLengthRule(&RuleMaxFilePathLengthParameters{
   347  				MaxFilePathLength: 255,
   348  			}),
   349  		},
   350  		"Invalid max_file_path_length params": {
   351  			data: `{"type":"max_file_path_length","parameters":{"max_file_path_length": "255"}}`,
   352  			want: &RepositoryRule{
   353  				Type:       "max_file_path_length",
   354  				Parameters: nil,
   355  			},
   356  			wantErr: true,
   357  		},
   358  		"Valid file_extension_restriction params": {
   359  			data: `{"type":"file_extension_restriction","parameters":{"restricted_file_extensions":[".exe"]}}`,
   360  			want: NewFileExtensionRestrictionRule(&RuleFileExtensionRestrictionParameters{
   361  				RestrictedFileExtensions: []string{".exe"},
   362  			}),
   363  		},
   364  		"Invalid file_extension_restriction params": {
   365  			data: `{"type":"file_extension_restriction","parameters":{"restricted_file_extensions":true}}`,
   366  			want: &RepositoryRule{
   367  				Type:       "file_extension_restriction",
   368  				Parameters: nil,
   369  			},
   370  			wantErr: true,
   371  		},
   372  		"Valid max_file_size params": {
   373  			data: `{"type":"max_file_size","parameters":{"max_file_size": 1024}}`,
   374  			want: NewMaxFileSizeRule(&RuleMaxFileSizeParameters{
   375  				MaxFileSize: 1024,
   376  			}),
   377  		},
   378  		"Invalid max_file_size params": {
   379  			data: `{"type":"max_file_size","parameters":{"max_file_size": "1024"}}`,
   380  			want: &RepositoryRule{
   381  				Type:       "max_file_size",
   382  				Parameters: nil,
   383  			},
   384  			wantErr: true,
   385  		},
   386  	}
   387  
   388  	for name, tc := range tests {
   389  		tc := tc
   390  		rule := &RepositoryRule{}
   391  
   392  		t.Run(name, func(t *testing.T) {
   393  			t.Parallel()
   394  			err := rule.UnmarshalJSON([]byte(tc.data))
   395  			if err == nil && tc.wantErr {
   396  				t.Errorf("RepositoryRule.UnmarshalJSON returned nil instead of an error")
   397  			}
   398  			if err != nil && !tc.wantErr {
   399  				t.Errorf("RepositoryRule.UnmarshalJSON returned an unexpected error: %+v", err)
   400  			}
   401  			if !cmp.Equal(tc.want, rule) {
   402  				t.Errorf("RepositoryRule.UnmarshalJSON expected rule %+v, got %+v", tc.want, rule)
   403  			}
   404  		})
   405  	}
   406  }
   407  
   408  func TestRepositoriesService_GetRulesForBranch(t *testing.T) {
   409  	t.Parallel()
   410  	client, mux, _ := setup(t)
   411  
   412  	mux.HandleFunc("/repos/o/repo/rules/branches/branch", func(w http.ResponseWriter, r *http.Request) {
   413  		testMethod(t, r, "GET")
   414  		fmt.Fprint(w, `[
   415  			{
   416  			  "ruleset_id": 42069,
   417  			  "ruleset_source_type": "Repository",
   418  			  "ruleset_source": "google",
   419  			  "type": "creation"
   420  			},
   421  			{
   422  			  "ruleset_id": 42069,
   423  			  "ruleset_source_type": "Organization",
   424  			  "ruleset_source": "google",
   425  			  "type": "update",
   426  			  "parameters": {
   427  			    "update_allows_fetch_and_merge": true
   428  			  }
   429  			}
   430  		]`)
   431  	})
   432  
   433  	ctx := context.Background()
   434  	rules, _, err := client.Repositories.GetRulesForBranch(ctx, "o", "repo", "branch")
   435  	if err != nil {
   436  		t.Errorf("Repositories.GetRulesForBranch returned error: %v", err)
   437  	}
   438  
   439  	creationRule := NewCreationRule()
   440  	creationRule.RulesetID = 42069
   441  	creationRule.RulesetSource = "google"
   442  	creationRule.RulesetSourceType = "Repository"
   443  	updateRule := NewUpdateRule(&UpdateAllowsFetchAndMergeRuleParameters{
   444  		UpdateAllowsFetchAndMerge: true,
   445  	})
   446  	updateRule.RulesetID = 42069
   447  	updateRule.RulesetSource = "google"
   448  	updateRule.RulesetSourceType = "Organization"
   449  
   450  	want := []*RepositoryRule{
   451  		creationRule,
   452  		updateRule,
   453  	}
   454  	if !cmp.Equal(rules, want) {
   455  		t.Errorf("Repositories.GetRulesForBranch returned %+v, want %+v", rules, want)
   456  	}
   457  
   458  	const methodName = "GetRulesForBranch"
   459  
   460  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   461  		got, resp, err := client.Repositories.GetRulesForBranch(ctx, "o", "repo", "branch")
   462  		if got != nil {
   463  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   464  		}
   465  		return resp, err
   466  	})
   467  }
   468  
   469  func TestRepositoriesService_GetRulesForBranchEmptyUpdateRule(t *testing.T) {
   470  	t.Parallel()
   471  	client, mux, _ := setup(t)
   472  
   473  	mux.HandleFunc("/repos/o/repo/rules/branches/branch", func(w http.ResponseWriter, r *http.Request) {
   474  		testMethod(t, r, "GET")
   475  		fmt.Fprint(w, `[
   476  			{
   477  			  "type": "update"
   478  			}
   479  		]`)
   480  	})
   481  
   482  	ctx := context.Background()
   483  	rules, _, err := client.Repositories.GetRulesForBranch(ctx, "o", "repo", "branch")
   484  	if err != nil {
   485  		t.Errorf("Repositories.GetRulesForBranch returned error: %v", err)
   486  	}
   487  
   488  	updateRule := NewUpdateRule(nil)
   489  
   490  	want := []*RepositoryRule{
   491  		updateRule,
   492  	}
   493  	if !cmp.Equal(rules, want) {
   494  		t.Errorf("Repositories.GetRulesForBranch returned %+v, want %+v", Stringify(rules), Stringify(want))
   495  	}
   496  
   497  	const methodName = "GetRulesForBranch"
   498  
   499  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   500  		got, resp, err := client.Repositories.GetRulesForBranch(ctx, "o", "repo", "branch")
   501  		if got != nil {
   502  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   503  		}
   504  		return resp, err
   505  	})
   506  }
   507  
   508  func TestRepositoriesService_GetAllRulesets(t *testing.T) {
   509  	t.Parallel()
   510  	client, mux, _ := setup(t)
   511  
   512  	mux.HandleFunc("/repos/o/repo/rulesets", func(w http.ResponseWriter, r *http.Request) {
   513  		testMethod(t, r, "GET")
   514  		fmt.Fprint(w, `[
   515  			{
   516  			  "id": 42,
   517  			  "name": "ruleset",
   518  			  "source_type": "Repository",
   519  			  "source": "o/repo",
   520  			  "enforcement": "enabled",
   521  			  "created_at": `+referenceTimeStr+`,
   522  			  "updated_at": `+referenceTimeStr+`
   523  			},
   524  			{
   525  			  "id": 314,
   526  			  "name": "Another ruleset",
   527  			  "source_type": "Repository",
   528  			  "source": "o/repo",
   529  			  "enforcement": "enabled",
   530  			  "created_at": `+referenceTimeStr+`,
   531  			  "updated_at": `+referenceTimeStr+`
   532  			}
   533  		]`)
   534  	})
   535  
   536  	ctx := context.Background()
   537  	ruleSet, _, err := client.Repositories.GetAllRulesets(ctx, "o", "repo", false)
   538  	if err != nil {
   539  		t.Errorf("Repositories.GetAllRulesets returned error: %v", err)
   540  	}
   541  
   542  	want := []*Ruleset{
   543  		{
   544  			ID:          Ptr(int64(42)),
   545  			Name:        "ruleset",
   546  			SourceType:  Ptr("Repository"),
   547  			Source:      "o/repo",
   548  			Enforcement: "enabled",
   549  			CreatedAt:   &Timestamp{referenceTime},
   550  			UpdatedAt:   &Timestamp{referenceTime},
   551  		},
   552  		{
   553  			ID:          Ptr(int64(314)),
   554  			Name:        "Another ruleset",
   555  			SourceType:  Ptr("Repository"),
   556  			Source:      "o/repo",
   557  			Enforcement: "enabled",
   558  			CreatedAt:   &Timestamp{referenceTime},
   559  			UpdatedAt:   &Timestamp{referenceTime},
   560  		},
   561  	}
   562  	if !cmp.Equal(ruleSet, want) {
   563  		t.Errorf("Repositories.GetAllRulesets returned %+v, want %+v", ruleSet, want)
   564  	}
   565  
   566  	const methodName = "GetAllRulesets"
   567  
   568  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   569  		got, resp, err := client.Repositories.GetAllRulesets(ctx, "o", "repo", false)
   570  		if got != nil {
   571  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   572  		}
   573  		return resp, err
   574  	})
   575  }
   576  
   577  func TestRepositoriesService_CreateRuleset(t *testing.T) {
   578  	t.Parallel()
   579  	client, mux, _ := setup(t)
   580  
   581  	mux.HandleFunc("/repos/o/repo/rulesets", func(w http.ResponseWriter, r *http.Request) {
   582  		testMethod(t, r, "POST")
   583  		fmt.Fprint(w, `{
   584  			"id": 42,
   585  			"name": "ruleset",
   586  			"source_type": "Repository",
   587  			"source": "o/repo",
   588  			"enforcement": "enabled"
   589  		}`)
   590  	})
   591  
   592  	ctx := context.Background()
   593  	ruleSet, _, err := client.Repositories.CreateRuleset(ctx, "o", "repo", &Ruleset{
   594  		Name:        "ruleset",
   595  		Enforcement: "enabled",
   596  	})
   597  	if err != nil {
   598  		t.Errorf("Repositories.CreateRuleset returned error: %v", err)
   599  	}
   600  
   601  	want := &Ruleset{
   602  		ID:          Ptr(int64(42)),
   603  		Name:        "ruleset",
   604  		SourceType:  Ptr("Repository"),
   605  		Source:      "o/repo",
   606  		Enforcement: "enabled",
   607  	}
   608  	if !cmp.Equal(ruleSet, want) {
   609  		t.Errorf("Repositories.CreateRuleset returned %+v, want %+v", ruleSet, want)
   610  	}
   611  
   612  	const methodName = "CreateRuleset"
   613  
   614  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   615  		got, resp, err := client.Repositories.CreateRuleset(ctx, "o", "repo", &Ruleset{})
   616  		if got != nil {
   617  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   618  		}
   619  		return resp, err
   620  	})
   621  }
   622  
   623  func TestRepositoriesService_CreateRulesetWithPushRules(t *testing.T) {
   624  	t.Parallel()
   625  	client, mux, _ := setup(t)
   626  
   627  	mux.HandleFunc("/repos/o/repo/rulesets", func(w http.ResponseWriter, r *http.Request) {
   628  		testMethod(t, r, "POST")
   629  		fmt.Fprint(w, `{
   630  			"id": 42,
   631  			"name": "ruleset",
   632  			"source_type": "Repository",
   633  			"source": "o/repo",
   634  			"enforcement": "enabled",
   635  			"target": "push",
   636  			"rules": [
   637  				{
   638  					"type": "file_path_restriction",
   639  					"parameters": {
   640  						"restricted_file_paths": ["/a/file"]
   641  					}
   642  				},
   643  				{
   644  					"type": "max_file_path_length",
   645  					"parameters": {
   646  						"max_file_path_length": 255
   647  					}
   648  				},
   649  				{
   650  					"type": "file_extension_restriction",
   651  					"parameters": {
   652  						"restricted_file_extensions": [".exe"]
   653  					}
   654  				},
   655  				{
   656  					"type": "max_file_size",
   657  					"parameters": {
   658  						"max_file_size": 1024
   659  					}
   660  				}
   661  			]
   662  		}`)
   663  	})
   664  
   665  	ctx := context.Background()
   666  	ruleSet, _, err := client.Repositories.CreateRuleset(ctx, "o", "repo", &Ruleset{
   667  		Name:        "ruleset",
   668  		Enforcement: "enabled",
   669  	})
   670  	if err != nil {
   671  		t.Errorf("Repositories.CreateRuleset returned error: %v", err)
   672  	}
   673  
   674  	want := &Ruleset{
   675  		ID:          Ptr(int64(42)),
   676  		Name:        "ruleset",
   677  		SourceType:  Ptr("Repository"),
   678  		Source:      "o/repo",
   679  		Target:      Ptr("push"),
   680  		Enforcement: "enabled",
   681  		Rules: []*RepositoryRule{
   682  			NewFilePathRestrictionRule(&RuleFileParameters{
   683  				RestrictedFilePaths: &[]string{"/a/file"},
   684  			}),
   685  			NewMaxFilePathLengthRule(&RuleMaxFilePathLengthParameters{
   686  				MaxFilePathLength: 255,
   687  			}),
   688  			NewFileExtensionRestrictionRule(&RuleFileExtensionRestrictionParameters{
   689  				RestrictedFileExtensions: []string{".exe"},
   690  			}),
   691  			NewMaxFileSizeRule(&RuleMaxFileSizeParameters{
   692  				MaxFileSize: 1024,
   693  			}),
   694  		},
   695  	}
   696  	if !cmp.Equal(ruleSet, want) {
   697  		t.Errorf("Repositories.CreateRuleset returned %+v, want %+v", ruleSet, want)
   698  	}
   699  
   700  	const methodName = "CreateRuleset"
   701  
   702  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   703  		got, resp, err := client.Repositories.CreateRuleset(ctx, "o", "repo", &Ruleset{})
   704  		if got != nil {
   705  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   706  		}
   707  		return resp, err
   708  	})
   709  }
   710  
   711  func TestRepositoriesService_GetRuleset(t *testing.T) {
   712  	t.Parallel()
   713  	client, mux, _ := setup(t)
   714  
   715  	mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) {
   716  		testMethod(t, r, "GET")
   717  		fmt.Fprint(w, `{
   718  			"id": 42,
   719  			"name": "ruleset",
   720  			"source_type": "Organization",
   721  			"source": "o",
   722  			"enforcement": "enabled",
   723  			"created_at": `+referenceTimeStr+`,
   724  			"updated_at": `+referenceTimeStr+`
   725  		}`)
   726  	})
   727  
   728  	ctx := context.Background()
   729  	ruleSet, _, err := client.Repositories.GetRuleset(ctx, "o", "repo", 42, true)
   730  	if err != nil {
   731  		t.Errorf("Repositories.GetRuleset returned error: %v", err)
   732  	}
   733  
   734  	want := &Ruleset{
   735  		ID:          Ptr(int64(42)),
   736  		Name:        "ruleset",
   737  		SourceType:  Ptr("Organization"),
   738  		Source:      "o",
   739  		Enforcement: "enabled",
   740  		CreatedAt:   &Timestamp{referenceTime},
   741  		UpdatedAt:   &Timestamp{referenceTime},
   742  	}
   743  	if !cmp.Equal(ruleSet, want) {
   744  		t.Errorf("Repositories.GetRuleset returned %+v, want %+v", ruleSet, want)
   745  	}
   746  
   747  	const methodName = "GetRuleset"
   748  
   749  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   750  		got, resp, err := client.Repositories.GetRuleset(ctx, "o", "repo", 42, true)
   751  		if got != nil {
   752  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   753  		}
   754  		return resp, err
   755  	})
   756  }
   757  
   758  func TestRepositoriesService_UpdateRulesetNoBypassActor(t *testing.T) {
   759  	t.Parallel()
   760  	client, mux, _ := setup(t)
   761  
   762  	rs := &Ruleset{
   763  		Name:        "ruleset",
   764  		Source:      "o/repo",
   765  		Enforcement: "enabled",
   766  	}
   767  
   768  	mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) {
   769  		testMethod(t, r, "PUT")
   770  		fmt.Fprint(w, `{
   771  			"id": 42,
   772  			"name": "ruleset",
   773  			"source_type": "Repository",
   774  			"source": "o/repo",
   775  			"enforcement": "enabled"
   776  		}`)
   777  	})
   778  
   779  	ctx := context.Background()
   780  
   781  	ruleSet, _, err := client.Repositories.UpdateRulesetNoBypassActor(ctx, "o", "repo", 42, rs)
   782  
   783  	if err != nil {
   784  		t.Errorf("Repositories.UpdateRulesetNoBypassActor returned error: %v \n", err)
   785  	}
   786  
   787  	want := &Ruleset{
   788  		ID:          Ptr(int64(42)),
   789  		Name:        "ruleset",
   790  		SourceType:  Ptr("Repository"),
   791  		Source:      "o/repo",
   792  		Enforcement: "enabled",
   793  	}
   794  
   795  	if !cmp.Equal(ruleSet, want) {
   796  		t.Errorf("Repositories.UpdateRulesetNoBypassActor returned %+v, want %+v", ruleSet, want)
   797  	}
   798  
   799  	const methodName = "UpdateRulesetNoBypassActor"
   800  
   801  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   802  		got, resp, err := client.Repositories.UpdateRulesetNoBypassActor(ctx, "o", "repo", 42, nil)
   803  		if got != nil {
   804  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   805  		}
   806  		return resp, err
   807  	})
   808  }
   809  
   810  func TestRepositoriesService_UpdateRuleset(t *testing.T) {
   811  	t.Parallel()
   812  	client, mux, _ := setup(t)
   813  
   814  	mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) {
   815  		testMethod(t, r, "PUT")
   816  		fmt.Fprint(w, `{
   817  			"id": 42,
   818  			"name": "ruleset",
   819  			"source_type": "Repository",
   820  			"source": "o/repo",
   821  			"enforcement": "enabled"
   822  		}`)
   823  	})
   824  
   825  	ctx := context.Background()
   826  	ruleSet, _, err := client.Repositories.UpdateRuleset(ctx, "o", "repo", 42, &Ruleset{
   827  		Name:        "ruleset",
   828  		Enforcement: "enabled",
   829  	})
   830  	if err != nil {
   831  		t.Errorf("Repositories.UpdateRuleset returned error: %v", err)
   832  	}
   833  
   834  	want := &Ruleset{
   835  		ID:          Ptr(int64(42)),
   836  		Name:        "ruleset",
   837  		SourceType:  Ptr("Repository"),
   838  		Source:      "o/repo",
   839  		Enforcement: "enabled",
   840  	}
   841  
   842  	if !cmp.Equal(ruleSet, want) {
   843  		t.Errorf("Repositories.UpdateRuleset returned %+v, want %+v", ruleSet, want)
   844  	}
   845  
   846  	const methodName = "UpdateRuleset"
   847  
   848  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   849  		got, resp, err := client.Repositories.UpdateRuleset(ctx, "o", "repo", 42, nil)
   850  		if got != nil {
   851  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   852  		}
   853  		return resp, err
   854  	})
   855  }
   856  
   857  func TestRepositoriesService_DeleteRuleset(t *testing.T) {
   858  	t.Parallel()
   859  	client, mux, _ := setup(t)
   860  
   861  	mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) {
   862  		testMethod(t, r, "DELETE")
   863  	})
   864  
   865  	ctx := context.Background()
   866  	_, err := client.Repositories.DeleteRuleset(ctx, "o", "repo", 42)
   867  	if err != nil {
   868  		t.Errorf("Repositories.DeleteRuleset returned error: %v", err)
   869  	}
   870  
   871  	const methodName = "DeleteRuleset"
   872  
   873  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   874  		return client.Repositories.DeleteRuleset(ctx, "o", "repo", 42)
   875  	})
   876  }