github.com/google/go-github/v60@v60.0.0/github/code-scanning_test.go (about)

     1  // Copyright 2020 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 TestCodeScanningService_Alert_ID(t *testing.T) {
    20  	// Test: nil Alert ID == 0
    21  	var a *Alert
    22  	id := a.ID()
    23  	var want int64
    24  	if id != want {
    25  		t.Errorf("Alert.ID error returned %+v, want %+v", id, want)
    26  	}
    27  
    28  	// Test: Valid HTMLURL
    29  	a = &Alert{
    30  		HTMLURL: String("https://github.com/o/r/security/code-scanning/88"),
    31  	}
    32  	id = a.ID()
    33  	want = 88
    34  	if !cmp.Equal(id, want) {
    35  		t.Errorf("Alert.ID error returned %+v, want %+v", id, want)
    36  	}
    37  
    38  	// Test: HTMLURL is nil
    39  	a = &Alert{}
    40  	id = a.ID()
    41  	want = 0
    42  	if !cmp.Equal(id, want) {
    43  		t.Errorf("Alert.ID error returned %+v, want %+v", id, want)
    44  	}
    45  
    46  	// Test: ID can't be parsed as an int
    47  	a = &Alert{
    48  		HTMLURL: String("https://github.com/o/r/security/code-scanning/bad88"),
    49  	}
    50  	id = a.ID()
    51  	want = 0
    52  	if !cmp.Equal(id, want) {
    53  		t.Errorf("Alert.ID error returned %+v, want %+v", id, want)
    54  	}
    55  }
    56  
    57  func TestCodeScanningService_UploadSarif(t *testing.T) {
    58  	client, mux, _, teardown := setup()
    59  	defer teardown()
    60  
    61  	expectedSarifID := &SarifID{
    62  		ID:  String("testid"),
    63  		URL: String("https://example.com/testurl"),
    64  	}
    65  
    66  	mux.HandleFunc("/repos/o/r/code-scanning/sarifs", func(w http.ResponseWriter, r *http.Request) {
    67  		v := new(SarifAnalysis)
    68  		assertNilError(t, json.NewDecoder(r.Body).Decode(v))
    69  		testMethod(t, r, "POST")
    70  		want := &SarifAnalysis{CommitSHA: String("abc"), Ref: String("ref/head/main"), Sarif: String("abc"), CheckoutURI: String("uri"), StartedAt: &Timestamp{time.Date(2006, time.January, 02, 15, 04, 05, 0, time.UTC)}, ToolName: String("codeql-cli")}
    71  		if !cmp.Equal(v, want) {
    72  			t.Errorf("Request body = %+v, want %+v", v, want)
    73  		}
    74  
    75  		w.WriteHeader(http.StatusAccepted)
    76  		respBody, _ := json.Marshal(expectedSarifID)
    77  		_, _ = w.Write(respBody)
    78  	})
    79  
    80  	ctx := context.Background()
    81  	sarifAnalysis := &SarifAnalysis{CommitSHA: String("abc"), Ref: String("ref/head/main"), Sarif: String("abc"), CheckoutURI: String("uri"), StartedAt: &Timestamp{time.Date(2006, time.January, 02, 15, 04, 05, 0, time.UTC)}, ToolName: String("codeql-cli")}
    82  	respSarifID, _, err := client.CodeScanning.UploadSarif(ctx, "o", "r", sarifAnalysis)
    83  	if err != nil {
    84  		t.Errorf("CodeScanning.UploadSarif returned error: %v", err)
    85  	}
    86  	if !cmp.Equal(expectedSarifID, respSarifID) {
    87  		t.Errorf("Sarif response = %+v, want %+v", respSarifID, expectedSarifID)
    88  	}
    89  
    90  	const methodName = "UploadSarif"
    91  	testBadOptions(t, methodName, func() (err error) {
    92  		_, _, err = client.CodeScanning.UploadSarif(ctx, "\n", "\n", sarifAnalysis)
    93  		return err
    94  	})
    95  
    96  	testNewRequestAndDoFailureCategory(t, methodName, client, codeScanningUploadCategory, func() (*Response, error) {
    97  		_, resp, err := client.CodeScanning.UploadSarif(ctx, "o", "r", sarifAnalysis)
    98  		return resp, err
    99  	})
   100  }
   101  
   102  func TestCodeScanningService_GetSARIF(t *testing.T) {
   103  	client, mux, _, teardown := setup()
   104  	defer teardown()
   105  
   106  	mux.HandleFunc("/repos/o/r/code-scanning/sarifs/abc", func(w http.ResponseWriter, r *http.Request) {
   107  		testMethod(t, r, "GET")
   108  		fmt.Fprint(w, `{
   109  			"processing_status": "s",
   110  			"analyses_url": "u"
   111  		}`)
   112  	})
   113  
   114  	ctx := context.Background()
   115  	sarifUpload, _, err := client.CodeScanning.GetSARIF(ctx, "o", "r", "abc")
   116  	if err != nil {
   117  		t.Errorf("CodeScanning.GetSARIF returned error: %v", err)
   118  	}
   119  
   120  	want := &SARIFUpload{
   121  		ProcessingStatus: String("s"),
   122  		AnalysesURL:      String("u"),
   123  	}
   124  	if !cmp.Equal(sarifUpload, want) {
   125  		t.Errorf("CodeScanning.GetSARIF returned %+v, want %+v", sarifUpload, want)
   126  	}
   127  
   128  	const methodName = "GetSARIF"
   129  	testBadOptions(t, methodName, func() (err error) {
   130  		_, _, err = client.CodeScanning.GetSARIF(ctx, "\n", "\n", "\n")
   131  		return err
   132  	})
   133  
   134  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   135  		got, resp, err := client.CodeScanning.GetSARIF(ctx, "o", "r", "abc")
   136  		if got != nil {
   137  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   138  		}
   139  		return resp, err
   140  	})
   141  }
   142  
   143  func TestCodeScanningService_ListAlertsForOrg(t *testing.T) {
   144  	client, mux, _, teardown := setup()
   145  	defer teardown()
   146  
   147  	mux.HandleFunc("/orgs/o/code-scanning/alerts", func(w http.ResponseWriter, r *http.Request) {
   148  		testMethod(t, r, "GET")
   149  		testFormValues(t, r, values{"state": "open", "ref": "heads/master", "severity": "warning", "tool_name": "CodeQL"})
   150  		fmt.Fprint(w, `[{
   151  				"repository": {
   152  					"id": 1,
   153  					"name": "n",
   154  					"url": "url"
   155  				},
   156  				"rule_id":"js/trivial-conditional",
   157  				"rule_severity":"warning",
   158  				"rule_description":"Useless conditional",
   159  				"tool": {
   160  					"name": "CodeQL",
   161  					"guid": null,
   162  					"version": "1.4.0"
   163  				},
   164  				"rule": {
   165  					"id": "js/trivial-conditional",
   166  					"severity": "warning",
   167  					"description": "Useless conditional",
   168  					"name": "js/trivial-conditional",
   169  					"full_description": "Expression has no effect",
   170  					"help": "Expression has no effect"
   171  				},
   172  				"most_recent_instance": {
   173  					"ref": "refs/heads/main",
   174  					"state": "open",
   175  					"commit_sha": "abcdefg12345",
   176  					"message": {
   177  						"text": "This path depends on a user-provided value."
   178  					},
   179  					"location": {
   180  						"path": "spec-main/api-session-spec.ts",
   181  						"start_line": 917,
   182  						"end_line": 917,
   183  						"start_column": 7,
   184  						"end_column": 18
   185  					},
   186  					"classifications": [
   187  						"test"
   188  					]
   189  				},
   190  				"created_at":"2020-05-06T12:00:00Z",
   191  				"state":"open",
   192  				"closed_by":null,
   193  				"closed_at":null,
   194  				"url":"https://api.github.com/repos/o/r/code-scanning/alerts/25",
   195  				"html_url":"https://github.com/o/r/security/code-scanning/25"
   196  				},
   197  				{
   198  				"rule_id":"js/useless-expression",
   199  				"rule_severity":"warning",
   200  				"rule_description":"Expression has no effect",
   201  				"tool": {
   202  					"name": "CodeQL",
   203  					"guid": null,
   204  					"version": "1.4.0"
   205  				},
   206  				"rule": {
   207  					"id": "js/useless-expression",
   208  					"severity": "warning",
   209  					"description": "Expression has no effect",
   210  					"name": "js/useless-expression",
   211  					"full_description": "Expression has no effect",
   212  					"help": "Expression has no effect"
   213  				},
   214  				"most_recent_instance": {
   215  					"ref": "refs/heads/main",
   216  					"state": "open",
   217  					"commit_sha": "abcdefg12345",
   218  					"message": {
   219  						"text": "This path depends on a user-provided value."
   220  					},
   221  					"location": {
   222  						"path": "spec-main/api-session-spec.ts",
   223  						"start_line": 917,
   224  						"end_line": 917,
   225  						"start_column": 7,
   226  						"end_column": 18
   227  					},
   228  					"classifications": [
   229  						"test"
   230  					]
   231  				},
   232  				"created_at":"2020-05-06T12:00:00Z",
   233  				"state":"open",
   234  				"closed_by":null,
   235  				"closed_at":null,
   236  				"url":"https://api.github.com/repos/o/r/code-scanning/alerts/88",
   237  				"html_url":"https://github.com/o/r/security/code-scanning/88"
   238  				}]`)
   239  	})
   240  
   241  	opts := &AlertListOptions{State: "open", Ref: "heads/master", Severity: "warning", ToolName: "CodeQL"}
   242  	ctx := context.Background()
   243  	alerts, _, err := client.CodeScanning.ListAlertsForOrg(ctx, "o", opts)
   244  	if err != nil {
   245  		t.Errorf("CodeScanning.ListAlertsForOrg returned error: %v", err)
   246  	}
   247  
   248  	date := Timestamp{time.Date(2020, time.May, 06, 12, 00, 00, 0, time.UTC)}
   249  	want := []*Alert{
   250  		{
   251  			Repository: &Repository{
   252  				ID:   Int64(1),
   253  				URL:  String("url"),
   254  				Name: String("n"),
   255  			},
   256  			RuleID:          String("js/trivial-conditional"),
   257  			RuleSeverity:    String("warning"),
   258  			RuleDescription: String("Useless conditional"),
   259  			Tool:            &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")},
   260  			Rule: &Rule{
   261  				ID:              String("js/trivial-conditional"),
   262  				Severity:        String("warning"),
   263  				Description:     String("Useless conditional"),
   264  				Name:            String("js/trivial-conditional"),
   265  				FullDescription: String("Expression has no effect"),
   266  				Help:            String("Expression has no effect"),
   267  			},
   268  			CreatedAt: &date,
   269  			State:     String("open"),
   270  			ClosedBy:  nil,
   271  			ClosedAt:  nil,
   272  			URL:       String("https://api.github.com/repos/o/r/code-scanning/alerts/25"),
   273  			HTMLURL:   String("https://github.com/o/r/security/code-scanning/25"),
   274  			MostRecentInstance: &MostRecentInstance{
   275  				Ref:       String("refs/heads/main"),
   276  				State:     String("open"),
   277  				CommitSHA: String("abcdefg12345"),
   278  				Message: &Message{
   279  					Text: String("This path depends on a user-provided value."),
   280  				},
   281  				Location: &Location{
   282  					Path:        String("spec-main/api-session-spec.ts"),
   283  					StartLine:   Int(917),
   284  					EndLine:     Int(917),
   285  					StartColumn: Int(7),
   286  					EndColumn:   Int(18),
   287  				},
   288  				Classifications: []string{"test"},
   289  			},
   290  		},
   291  		{
   292  			RuleID:          String("js/useless-expression"),
   293  			RuleSeverity:    String("warning"),
   294  			RuleDescription: String("Expression has no effect"),
   295  			Tool:            &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")},
   296  			Rule: &Rule{
   297  				ID:              String("js/useless-expression"),
   298  				Severity:        String("warning"),
   299  				Description:     String("Expression has no effect"),
   300  				Name:            String("js/useless-expression"),
   301  				FullDescription: String("Expression has no effect"),
   302  				Help:            String("Expression has no effect"),
   303  			},
   304  			CreatedAt: &date,
   305  			State:     String("open"),
   306  			ClosedBy:  nil,
   307  			ClosedAt:  nil,
   308  			URL:       String("https://api.github.com/repos/o/r/code-scanning/alerts/88"),
   309  			HTMLURL:   String("https://github.com/o/r/security/code-scanning/88"),
   310  			MostRecentInstance: &MostRecentInstance{
   311  				Ref:       String("refs/heads/main"),
   312  				State:     String("open"),
   313  				CommitSHA: String("abcdefg12345"),
   314  				Message: &Message{
   315  					Text: String("This path depends on a user-provided value."),
   316  				},
   317  				Location: &Location{
   318  					Path:        String("spec-main/api-session-spec.ts"),
   319  					StartLine:   Int(917),
   320  					EndLine:     Int(917),
   321  					StartColumn: Int(7),
   322  					EndColumn:   Int(18),
   323  				},
   324  				Classifications: []string{"test"},
   325  			},
   326  		},
   327  	}
   328  	if !cmp.Equal(alerts, want) {
   329  		t.Errorf("CodeScanning.ListAlertsForOrg returned %+v, want %+v", alerts, want)
   330  	}
   331  
   332  	const methodName = "ListAlertsForOrg"
   333  	testBadOptions(t, methodName, func() (err error) {
   334  		_, _, err = client.CodeScanning.ListAlertsForOrg(ctx, "\n", opts)
   335  		return err
   336  	})
   337  
   338  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   339  		got, resp, err := client.CodeScanning.ListAlertsForOrg(ctx, "o", opts)
   340  		if got != nil {
   341  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   342  		}
   343  		return resp, err
   344  	})
   345  }
   346  
   347  func TestCodeScanningService_ListAlertsForOrgLisCursorOptions(t *testing.T) {
   348  	client, mux, _, teardown := setup()
   349  	defer teardown()
   350  
   351  	mux.HandleFunc("/orgs/o/code-scanning/alerts", func(w http.ResponseWriter, r *http.Request) {
   352  		testMethod(t, r, "GET")
   353  		testFormValues(t, r, values{"state": "open", "ref": "heads/master", "severity": "warning", "tool_name": "CodeQL", "per_page": "1", "before": "deadbeefb", "after": "deadbeefa"})
   354  		fmt.Fprint(w, `[{
   355  				"repository": {
   356  					"id": 1,
   357  					"name": "n",
   358  					"url": "url"
   359  				},
   360  				"rule_id":"js/trivial-conditional",
   361  				"rule_severity":"warning",
   362  				"rule_description":"Useless conditional",
   363  				"tool": {
   364  					"name": "CodeQL",
   365  					"guid": null,
   366  					"version": "1.4.0"
   367  				},
   368  				"rule": {
   369  					"id": "js/trivial-conditional",
   370  					"severity": "warning",
   371  					"description": "Useless conditional",
   372  					"name": "js/trivial-conditional",
   373  					"full_description": "Expression has no effect",
   374  					"help": "Expression has no effect"
   375  				},
   376  				"most_recent_instance": {
   377  					"ref": "refs/heads/main",
   378  					"state": "open",
   379  					"commit_sha": "abcdefg12345",
   380  					"message": {
   381  						"text": "This path depends on a user-provided value."
   382  					},
   383  					"location": {
   384  						"path": "spec-main/api-session-spec.ts",
   385  						"start_line": 917,
   386  						"end_line": 917,
   387  						"start_column": 7,
   388  						"end_column": 18
   389  					},
   390  					"classifications": [
   391  						"test"
   392  					]
   393  				},
   394  				"created_at":"2020-05-06T12:00:00Z",
   395  				"state":"open",
   396  				"closed_by":null,
   397  				"closed_at":null,
   398  				"url":"https://api.github.com/repos/o/r/code-scanning/alerts/25",
   399  				"html_url":"https://github.com/o/r/security/code-scanning/25"
   400  				}]`)
   401  	})
   402  
   403  	opts := &AlertListOptions{State: "open", Ref: "heads/master", Severity: "warning", ToolName: "CodeQL", ListCursorOptions: ListCursorOptions{PerPage: 1, Before: "deadbeefb", After: "deadbeefa"}}
   404  	ctx := context.Background()
   405  	alerts, _, err := client.CodeScanning.ListAlertsForOrg(ctx, "o", opts)
   406  	if err != nil {
   407  		t.Errorf("CodeScanning.ListAlertsForOrg returned error: %v", err)
   408  	}
   409  
   410  	date := Timestamp{time.Date(2020, time.May, 06, 12, 00, 00, 0, time.UTC)}
   411  	want := []*Alert{
   412  		{
   413  			Repository: &Repository{
   414  				ID:   Int64(1),
   415  				URL:  String("url"),
   416  				Name: String("n"),
   417  			},
   418  			RuleID:          String("js/trivial-conditional"),
   419  			RuleSeverity:    String("warning"),
   420  			RuleDescription: String("Useless conditional"),
   421  			Tool:            &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")},
   422  			Rule: &Rule{
   423  				ID:              String("js/trivial-conditional"),
   424  				Severity:        String("warning"),
   425  				Description:     String("Useless conditional"),
   426  				Name:            String("js/trivial-conditional"),
   427  				FullDescription: String("Expression has no effect"),
   428  				Help:            String("Expression has no effect"),
   429  			},
   430  			CreatedAt: &date,
   431  			State:     String("open"),
   432  			ClosedBy:  nil,
   433  			ClosedAt:  nil,
   434  			URL:       String("https://api.github.com/repos/o/r/code-scanning/alerts/25"),
   435  			HTMLURL:   String("https://github.com/o/r/security/code-scanning/25"),
   436  			MostRecentInstance: &MostRecentInstance{
   437  				Ref:       String("refs/heads/main"),
   438  				State:     String("open"),
   439  				CommitSHA: String("abcdefg12345"),
   440  				Message: &Message{
   441  					Text: String("This path depends on a user-provided value."),
   442  				},
   443  				Location: &Location{
   444  					Path:        String("spec-main/api-session-spec.ts"),
   445  					StartLine:   Int(917),
   446  					EndLine:     Int(917),
   447  					StartColumn: Int(7),
   448  					EndColumn:   Int(18),
   449  				},
   450  				Classifications: []string{"test"},
   451  			},
   452  		},
   453  	}
   454  	if !cmp.Equal(alerts, want) {
   455  		t.Errorf("CodeScanning.ListAlertsForOrg returned %+v, want %+v", alerts, want)
   456  	}
   457  
   458  	const methodName = "ListAlertsForOrg"
   459  	testBadOptions(t, methodName, func() (err error) {
   460  		_, _, err = client.CodeScanning.ListAlertsForOrg(ctx, "\n", opts)
   461  		return err
   462  	})
   463  
   464  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   465  		got, resp, err := client.CodeScanning.ListAlertsForOrg(ctx, "o", opts)
   466  		if got != nil {
   467  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   468  		}
   469  		return resp, err
   470  	})
   471  }
   472  
   473  func TestCodeScanningService_ListAlertsForRepo(t *testing.T) {
   474  	client, mux, _, teardown := setup()
   475  	defer teardown()
   476  
   477  	mux.HandleFunc("/repos/o/r/code-scanning/alerts", func(w http.ResponseWriter, r *http.Request) {
   478  		testMethod(t, r, "GET")
   479  		testFormValues(t, r, values{"state": "open", "ref": "heads/master", "severity": "warning", "tool_name": "CodeQL"})
   480  		fmt.Fprint(w, `[{
   481  				"rule_id":"js/trivial-conditional",
   482  				"rule_severity":"warning",
   483  				"rule_description":"Useless conditional",
   484  				"tool": {
   485  					"name": "CodeQL",
   486  					"guid": null,
   487  					"version": "1.4.0"
   488  				},
   489  				"rule": {
   490  					"id": "js/trivial-conditional",
   491  					"severity": "warning",
   492  					"description": "Useless conditional",
   493  					"name": "js/trivial-conditional",
   494  					"full_description": "Expression has no effect",
   495  					"help": "Expression has no effect"
   496  				},
   497  				"most_recent_instance": {
   498  					"ref": "refs/heads/main",
   499  					"state": "open",
   500  					"commit_sha": "abcdefg12345",
   501  					"message": {
   502  						"text": "This path depends on a user-provided value."
   503  					},
   504  					"location": {
   505  						"path": "spec-main/api-session-spec.ts",
   506  						"start_line": 917,
   507  						"end_line": 917,
   508  						"start_column": 7,
   509  						"end_column": 18
   510  					},
   511  					"classifications": [
   512  						"test"
   513  					]
   514  				},
   515  				"created_at":"2020-05-06T12:00:00Z",
   516  				"state":"open",
   517  				"closed_by":null,
   518  				"closed_at":null,
   519  				"url":"https://api.github.com/repos/o/r/code-scanning/alerts/25",
   520  				"html_url":"https://github.com/o/r/security/code-scanning/25"
   521  				},
   522  				{
   523  				"rule_id":"js/useless-expression",
   524  				"rule_severity":"warning",
   525  				"rule_description":"Expression has no effect",
   526  				"tool": {
   527  					"name": "CodeQL",
   528  					"guid": null,
   529  					"version": "1.4.0"
   530  				},
   531  				"rule": {
   532  					"id": "js/useless-expression",
   533  					"severity": "warning",
   534  					"description": "Expression has no effect",
   535  					"name": "js/useless-expression",
   536  					"full_description": "Expression has no effect",
   537  					"help": "Expression has no effect"
   538  				},
   539  				"most_recent_instance": {
   540  					"ref": "refs/heads/main",
   541  					"state": "open",
   542  					"commit_sha": "abcdefg12345",
   543  					"message": {
   544  						"text": "This path depends on a user-provided value."
   545  					},
   546  					"location": {
   547  						"path": "spec-main/api-session-spec.ts",
   548  						"start_line": 917,
   549  						"end_line": 917,
   550  						"start_column": 7,
   551  						"end_column": 18
   552  					},
   553  					"classifications": [
   554  						"test"
   555  					]
   556  				},
   557  				"created_at":"2020-05-06T12:00:00Z",
   558  				"state":"open",
   559  				"closed_by":null,
   560  				"closed_at":null,
   561  				"url":"https://api.github.com/repos/o/r/code-scanning/alerts/88",
   562  				"html_url":"https://github.com/o/r/security/code-scanning/88"
   563  				}]`)
   564  	})
   565  
   566  	opts := &AlertListOptions{State: "open", Ref: "heads/master", Severity: "warning", ToolName: "CodeQL"}
   567  	ctx := context.Background()
   568  	alerts, _, err := client.CodeScanning.ListAlertsForRepo(ctx, "o", "r", opts)
   569  	if err != nil {
   570  		t.Errorf("CodeScanning.ListAlertsForRepo returned error: %v", err)
   571  	}
   572  
   573  	date := Timestamp{time.Date(2020, time.May, 06, 12, 00, 00, 0, time.UTC)}
   574  	want := []*Alert{
   575  		{
   576  			RuleID:          String("js/trivial-conditional"),
   577  			RuleSeverity:    String("warning"),
   578  			RuleDescription: String("Useless conditional"),
   579  			Tool:            &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")},
   580  			Rule: &Rule{
   581  				ID:              String("js/trivial-conditional"),
   582  				Severity:        String("warning"),
   583  				Description:     String("Useless conditional"),
   584  				Name:            String("js/trivial-conditional"),
   585  				FullDescription: String("Expression has no effect"),
   586  				Help:            String("Expression has no effect"),
   587  			},
   588  			CreatedAt: &date,
   589  			State:     String("open"),
   590  			ClosedBy:  nil,
   591  			ClosedAt:  nil,
   592  			URL:       String("https://api.github.com/repos/o/r/code-scanning/alerts/25"),
   593  			HTMLURL:   String("https://github.com/o/r/security/code-scanning/25"),
   594  			MostRecentInstance: &MostRecentInstance{
   595  				Ref:       String("refs/heads/main"),
   596  				State:     String("open"),
   597  				CommitSHA: String("abcdefg12345"),
   598  				Message: &Message{
   599  					Text: String("This path depends on a user-provided value."),
   600  				},
   601  				Location: &Location{
   602  					Path:        String("spec-main/api-session-spec.ts"),
   603  					StartLine:   Int(917),
   604  					EndLine:     Int(917),
   605  					StartColumn: Int(7),
   606  					EndColumn:   Int(18),
   607  				},
   608  				Classifications: []string{"test"},
   609  			},
   610  		},
   611  		{
   612  			RuleID:          String("js/useless-expression"),
   613  			RuleSeverity:    String("warning"),
   614  			RuleDescription: String("Expression has no effect"),
   615  			Tool:            &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")},
   616  			Rule: &Rule{
   617  				ID:              String("js/useless-expression"),
   618  				Severity:        String("warning"),
   619  				Description:     String("Expression has no effect"),
   620  				Name:            String("js/useless-expression"),
   621  				FullDescription: String("Expression has no effect"),
   622  				Help:            String("Expression has no effect"),
   623  			},
   624  			CreatedAt: &date,
   625  			State:     String("open"),
   626  			ClosedBy:  nil,
   627  			ClosedAt:  nil,
   628  			URL:       String("https://api.github.com/repos/o/r/code-scanning/alerts/88"),
   629  			HTMLURL:   String("https://github.com/o/r/security/code-scanning/88"),
   630  			MostRecentInstance: &MostRecentInstance{
   631  				Ref:       String("refs/heads/main"),
   632  				State:     String("open"),
   633  				CommitSHA: String("abcdefg12345"),
   634  				Message: &Message{
   635  					Text: String("This path depends on a user-provided value."),
   636  				},
   637  				Location: &Location{
   638  					Path:        String("spec-main/api-session-spec.ts"),
   639  					StartLine:   Int(917),
   640  					EndLine:     Int(917),
   641  					StartColumn: Int(7),
   642  					EndColumn:   Int(18),
   643  				},
   644  				Classifications: []string{"test"},
   645  			},
   646  		},
   647  	}
   648  	if !cmp.Equal(alerts, want) {
   649  		t.Errorf("CodeScanning.ListAlertsForRepo returned %+v, want %+v", alerts, want)
   650  	}
   651  
   652  	const methodName = "ListAlertsForRepo"
   653  	testBadOptions(t, methodName, func() (err error) {
   654  		_, _, err = client.CodeScanning.ListAlertsForRepo(ctx, "\n", "\n", opts)
   655  		return err
   656  	})
   657  
   658  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   659  		got, resp, err := client.CodeScanning.ListAlertsForRepo(ctx, "o", "r", opts)
   660  		if got != nil {
   661  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   662  		}
   663  		return resp, err
   664  	})
   665  }
   666  
   667  func TestCodeScanningService_UpdateAlert(t *testing.T) {
   668  	client, mux, _, teardown := setup()
   669  	defer teardown()
   670  	mux.HandleFunc("/repos/o/r/code-scanning/alerts/88", func(w http.ResponseWriter, r *http.Request) {
   671  		testMethod(t, r, "PATCH")
   672  		fmt.Fprint(w, `{"rule_id":"js/useless-expression",
   673  				"rule_severity":"warning",
   674  				"rule_description":"Expression has no effect",
   675  				"tool": {
   676  					"name": "CodeQL",
   677  					"guid": null,
   678  					"version": "1.4.0"
   679  				},
   680  				"rule": {
   681  					"id": "useless expression",
   682  					"severity": "warning",
   683  					"description": "Expression has no effect",
   684  					"name": "useless expression",
   685  					"full_description": "Expression has no effect",
   686  					"help": "Expression has no effect"
   687  				},
   688  				"most_recent_instance": {
   689  					"ref": "refs/heads/main",
   690  					"state": "dismissed",
   691  					"commit_sha": "abcdefg12345",
   692  					"message": {
   693  						"text": "This path depends on a user-provided value."
   694  					},
   695  					"location": {
   696  						"path": "spec-main/api-session-spec.ts",
   697  						"start_line": 917,
   698  						"end_line": 917,
   699  						"start_column": 7,
   700  						"end_column": 18
   701  					},
   702  					"classifications": [
   703  						"test"
   704  					]
   705  				},
   706  				"created_at":"2019-01-02T15:04:05Z",
   707  				"state":"dismissed",
   708  				"dismissed_reason": "false positive",
   709  				"dismissed_comment": "This alert is not actually correct as sanitizer is used",
   710  				"closed_by":null,
   711  				"closed_at":null,
   712  				"url":"https://api.github.com/repos/o/r/code-scanning/alerts/88",
   713  				"html_url":"https://github.com/o/r/security/code-scanning/88"}`)
   714  	})
   715  
   716  	ctx := context.Background()
   717  	dismissedComment := String("This alert is not actually correct as sanitizer is used")
   718  	dismissedReason := String("false positive")
   719  	state := String("dismissed")
   720  	stateInfo := &CodeScanningAlertState{State: *state, DismissedReason: dismissedReason, DismissedComment: dismissedComment}
   721  	alert, _, err := client.CodeScanning.UpdateAlert(ctx, "o", "r", 88, stateInfo)
   722  	if err != nil {
   723  		t.Errorf("CodeScanning.UpdateAlert returned error: %v", err)
   724  	}
   725  
   726  	date := Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}
   727  	want := &Alert{
   728  		RuleID:          String("js/useless-expression"),
   729  		RuleSeverity:    String("warning"),
   730  		RuleDescription: String("Expression has no effect"),
   731  		Tool:            &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")},
   732  		Rule: &Rule{
   733  			ID:              String("useless expression"),
   734  			Severity:        String("warning"),
   735  			Description:     String("Expression has no effect"),
   736  			Name:            String("useless expression"),
   737  			FullDescription: String("Expression has no effect"),
   738  			Help:            String("Expression has no effect"),
   739  		},
   740  		CreatedAt:        &date,
   741  		State:            state,
   742  		DismissedReason:  dismissedReason,
   743  		DismissedComment: dismissedComment,
   744  		ClosedBy:         nil,
   745  		ClosedAt:         nil,
   746  		URL:              String("https://api.github.com/repos/o/r/code-scanning/alerts/88"),
   747  		HTMLURL:          String("https://github.com/o/r/security/code-scanning/88"),
   748  		MostRecentInstance: &MostRecentInstance{
   749  			Ref:       String("refs/heads/main"),
   750  			State:     String("dismissed"),
   751  			CommitSHA: String("abcdefg12345"),
   752  			Message: &Message{
   753  				Text: String("This path depends on a user-provided value."),
   754  			},
   755  			Location: &Location{
   756  				Path:        String("spec-main/api-session-spec.ts"),
   757  				StartLine:   Int(917),
   758  				EndLine:     Int(917),
   759  				StartColumn: Int(7),
   760  				EndColumn:   Int(18),
   761  			},
   762  			Classifications: []string{"test"},
   763  		},
   764  	}
   765  	if !cmp.Equal(alert, want) {
   766  		t.Errorf("CodeScanning.UpdateAlert returned %+v, want %+v", alert, want)
   767  	}
   768  
   769  	const methodName = "UpdateAlert"
   770  	testBadOptions(t, methodName, func() (err error) {
   771  		_, _, err = client.CodeScanning.UpdateAlert(ctx, "\n", "\n", -88, stateInfo)
   772  		return err
   773  	})
   774  
   775  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   776  		got, resp, err := client.CodeScanning.UpdateAlert(ctx, "o", "r", 88, stateInfo)
   777  		if got != nil {
   778  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   779  		}
   780  		return resp, err
   781  	})
   782  }
   783  
   784  func TestCodeScanningService_ListAlertInstances(t *testing.T) {
   785  	client, mux, _, teardown := setup()
   786  	defer teardown()
   787  
   788  	mux.HandleFunc("/repos/o/r/code-scanning/alerts/88/instances", func(w http.ResponseWriter, r *http.Request) {
   789  		testMethod(t, r, "GET")
   790  		fmt.Fprint(w, `[
   791  			{
   792  			  "ref": "refs/heads/main",
   793  			  "analysis_key": ".github/workflows/codeql-analysis.yml:analyze",
   794  			  "environment": "",
   795  			  "category": ".github/workflows/codeql-analysis.yml:analyze",
   796  			  "state": "open",
   797  			  "fixed_at": null,
   798  			  "commit_sha": "abcdefg12345",
   799  			  "message": {
   800  				"text": "This path depends on a user-provided value."
   801  			  },
   802  			  "location": {
   803  				"path": "spec-main/api-session-spec.ts",
   804  				"start_line": 917,
   805  				"end_line": 917,
   806  				"start_column": 7,
   807  				"end_column": 18
   808  			  },
   809  			  "classifications": [
   810  				"test"
   811  			  ]
   812  			}
   813  		  ]`)
   814  	})
   815  
   816  	opts := &AlertInstancesListOptions{Ref: "heads/main", ListOptions: ListOptions{Page: 1}}
   817  	ctx := context.Background()
   818  	instances, _, err := client.CodeScanning.ListAlertInstances(ctx, "o", "r", 88, opts)
   819  	if err != nil {
   820  		t.Errorf("CodeScanning.ListAlertInstances returned error: %v", err)
   821  	}
   822  
   823  	want := []*MostRecentInstance{
   824  		{
   825  			Ref:         String("refs/heads/main"),
   826  			AnalysisKey: String(".github/workflows/codeql-analysis.yml:analyze"),
   827  			Category:    String(".github/workflows/codeql-analysis.yml:analyze"),
   828  			Environment: String(""),
   829  			State:       String("open"),
   830  			CommitSHA:   String("abcdefg12345"),
   831  			Message: &Message{
   832  				Text: String("This path depends on a user-provided value."),
   833  			},
   834  			Location: &Location{
   835  				Path:        String("spec-main/api-session-spec.ts"),
   836  				StartLine:   Int(917),
   837  				EndLine:     Int(917),
   838  				StartColumn: Int(7),
   839  				EndColumn:   Int(18),
   840  			},
   841  			Classifications: []string{"test"},
   842  		},
   843  	}
   844  	if !cmp.Equal(instances, want) {
   845  		t.Errorf("CodeScanning.ListAlertInstances returned %+v, want %+v", instances, want)
   846  	}
   847  
   848  	const methodName = "ListAlertInstances"
   849  	testBadOptions(t, methodName, func() (err error) {
   850  		_, _, err = client.CodeScanning.ListAlertInstances(ctx, "\n", "\n", -1, opts)
   851  		return err
   852  	})
   853  
   854  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   855  		got, resp, err := client.CodeScanning.ListAlertInstances(ctx, "o", "r", 88, opts)
   856  		if got != nil {
   857  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   858  		}
   859  		return resp, err
   860  	})
   861  }
   862  
   863  func TestCodeScanningService_GetAlert(t *testing.T) {
   864  	client, mux, _, teardown := setup()
   865  	defer teardown()
   866  
   867  	mux.HandleFunc("/repos/o/r/code-scanning/alerts/88", func(w http.ResponseWriter, r *http.Request) {
   868  		testMethod(t, r, "GET")
   869  		fmt.Fprint(w, `{
   870  			"rule_id":"js/useless-expression",
   871  			"rule_severity":"warning",
   872  			"rule_description":"Expression has no effect",
   873  			"tool": {
   874  				"name": "CodeQL",
   875  				"guid": null,
   876  				"version": "1.4.0"
   877  			},
   878  			"rule": {
   879  				"id": "useless expression",
   880  				"severity": "warning",
   881  				"description": "Expression has no effect",
   882  				"name": "useless expression",
   883  				"full_description": "Expression has no effect",
   884  				"help": "Expression has no effect"
   885  			},
   886  			"most_recent_instance": {
   887  				"ref": "refs/heads/main",
   888  				"state": "open",
   889  				"commit_sha": "abcdefg12345",
   890  				"message": {
   891  					"text": "This path depends on a user-provided value."
   892  				},
   893  				"location": {
   894  					"path": "spec-main/api-session-spec.ts",
   895  					"start_line": 917,
   896  					"end_line": 917,
   897  					"start_column": 7,
   898  					"end_column": 18
   899  				},
   900  				"classifications": [
   901  					"test"
   902  				]
   903  			},
   904  			"created_at":"2019-01-02T15:04:05Z",
   905  			"state":"open",
   906  			"closed_by":null,
   907  			"closed_at":null,
   908  			"url":"https://api.github.com/repos/o/r/code-scanning/alerts/88",
   909  			"html_url":"https://github.com/o/r/security/code-scanning/88"
   910  		}`)
   911  	})
   912  
   913  	ctx := context.Background()
   914  	alert, _, err := client.CodeScanning.GetAlert(ctx, "o", "r", 88)
   915  	if err != nil {
   916  		t.Errorf("CodeScanning.GetAlert returned error: %v", err)
   917  	}
   918  
   919  	date := Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}
   920  	want := &Alert{
   921  		RuleID:          String("js/useless-expression"),
   922  		RuleSeverity:    String("warning"),
   923  		RuleDescription: String("Expression has no effect"),
   924  		Tool:            &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")},
   925  		Rule: &Rule{
   926  			ID:              String("useless expression"),
   927  			Severity:        String("warning"),
   928  			Description:     String("Expression has no effect"),
   929  			Name:            String("useless expression"),
   930  			FullDescription: String("Expression has no effect"),
   931  			Help:            String("Expression has no effect"),
   932  		},
   933  		CreatedAt: &date,
   934  		State:     String("open"),
   935  		ClosedBy:  nil,
   936  		ClosedAt:  nil,
   937  		URL:       String("https://api.github.com/repos/o/r/code-scanning/alerts/88"),
   938  		HTMLURL:   String("https://github.com/o/r/security/code-scanning/88"),
   939  		MostRecentInstance: &MostRecentInstance{
   940  			Ref:       String("refs/heads/main"),
   941  			State:     String("open"),
   942  			CommitSHA: String("abcdefg12345"),
   943  			Message: &Message{
   944  				Text: String("This path depends on a user-provided value."),
   945  			},
   946  			Location: &Location{
   947  				Path:        String("spec-main/api-session-spec.ts"),
   948  				StartLine:   Int(917),
   949  				EndLine:     Int(917),
   950  				StartColumn: Int(7),
   951  				EndColumn:   Int(18),
   952  			},
   953  			Classifications: []string{"test"},
   954  		},
   955  	}
   956  	if !cmp.Equal(alert, want) {
   957  		t.Errorf("CodeScanning.GetAlert returned %+v, want %+v", alert, want)
   958  	}
   959  
   960  	const methodName = "GetAlert"
   961  	testBadOptions(t, methodName, func() (err error) {
   962  		_, _, err = client.CodeScanning.GetAlert(ctx, "\n", "\n", -88)
   963  		return err
   964  	})
   965  
   966  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   967  		got, resp, err := client.CodeScanning.GetAlert(ctx, "o", "r", 88)
   968  		if got != nil {
   969  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   970  		}
   971  		return resp, err
   972  	})
   973  }
   974  
   975  func TestAlert_Marshal(t *testing.T) {
   976  	testJSONMarshal(t, &Alert{}, "{}")
   977  
   978  	u := &Alert{
   979  		RuleID:          String("rid"),
   980  		RuleSeverity:    String("rs"),
   981  		RuleDescription: String("rd"),
   982  		Tool: &Tool{
   983  			Name:    String("n"),
   984  			GUID:    String("g"),
   985  			Version: String("v"),
   986  		},
   987  		CreatedAt: &Timestamp{referenceTime},
   988  		State:     String("fixed"),
   989  		ClosedBy: &User{
   990  			Login:     String("l"),
   991  			ID:        Int64(1),
   992  			NodeID:    String("n"),
   993  			URL:       String("u"),
   994  			ReposURL:  String("r"),
   995  			EventsURL: String("e"),
   996  			AvatarURL: String("a"),
   997  		},
   998  		ClosedAt: &Timestamp{referenceTime},
   999  		URL:      String("url"),
  1000  		HTMLURL:  String("hurl"),
  1001  	}
  1002  
  1003  	want := `{
  1004  		"rule_id": "rid",
  1005  		"rule_severity": "rs",
  1006  		"rule_description": "rd",
  1007  		"tool": {
  1008  			"name": "n",
  1009  			"guid": "g",
  1010  			"version": "v"
  1011  		},
  1012  		"created_at": ` + referenceTimeStr + `,
  1013  		"state": "fixed",
  1014  		"closed_by": {
  1015  			"login": "l",
  1016  			"id": 1,
  1017  			"node_id": "n",
  1018  			"avatar_url": "a",
  1019  			"url": "u",
  1020  			"events_url": "e",
  1021  			"repos_url": "r"
  1022  		},
  1023  		"closed_at": ` + referenceTimeStr + `,
  1024  		"url": "url",
  1025  		"html_url": "hurl"
  1026  	}`
  1027  
  1028  	testJSONMarshal(t, u, want)
  1029  }
  1030  
  1031  func TestLocation_Marshal(t *testing.T) {
  1032  	testJSONMarshal(t, &Location{}, "{}")
  1033  
  1034  	u := &Location{
  1035  		Path:        String("path"),
  1036  		StartLine:   Int(1),
  1037  		EndLine:     Int(2),
  1038  		StartColumn: Int(3),
  1039  		EndColumn:   Int(4),
  1040  	}
  1041  
  1042  	want := `{
  1043  		"path": "path",
  1044  		"start_line": 1,
  1045  		"end_line": 2,
  1046  		"start_column": 3,
  1047  		"end_column": 4
  1048  	}`
  1049  
  1050  	testJSONMarshal(t, u, want)
  1051  }
  1052  
  1053  func TestRule_Marshal(t *testing.T) {
  1054  	testJSONMarshal(t, &Rule{}, "{}")
  1055  
  1056  	u := &Rule{
  1057  		ID:                    String("1"),
  1058  		Severity:              String("3"),
  1059  		Description:           String("description"),
  1060  		Name:                  String("first"),
  1061  		SecuritySeverityLevel: String("2"),
  1062  		FullDescription:       String("summary"),
  1063  		Tags:                  []string{"tag1", "tag2"},
  1064  		Help:                  String("Help Text"),
  1065  	}
  1066  
  1067  	want := `{
  1068  		"id":                      "1",
  1069  		"severity":                "3",
  1070  		"description":             "description",
  1071  		"name":                    "first",
  1072  		"security_severity_level": "2",
  1073  		"full_description":        "summary",
  1074  		"tags":                    ["tag1", "tag2"],
  1075  		"help":                    "Help Text"
  1076  	}`
  1077  
  1078  	testJSONMarshal(t, u, want)
  1079  }
  1080  
  1081  func TestTool_Marshal(t *testing.T) {
  1082  	testJSONMarshal(t, &Tool{}, "{}")
  1083  
  1084  	u := &Tool{
  1085  		Name:    String("name"),
  1086  		GUID:    String("guid"),
  1087  		Version: String("ver"),
  1088  	}
  1089  
  1090  	want := `{
  1091  		"name": "name",
  1092  		"guid": "guid",
  1093  		"version": "ver"
  1094  	}`
  1095  
  1096  	testJSONMarshal(t, u, want)
  1097  }
  1098  
  1099  func TestMessage_Marshal(t *testing.T) {
  1100  	testJSONMarshal(t, &Message{}, "{}")
  1101  
  1102  	u := &Message{
  1103  		Text: String("text"),
  1104  	}
  1105  
  1106  	want := `{
  1107  		"text": "text"
  1108  	}`
  1109  
  1110  	testJSONMarshal(t, u, want)
  1111  }
  1112  
  1113  func TestCodeScanningService_ListAnalysesForRepo(t *testing.T) {
  1114  	client, mux, _, teardown := setup()
  1115  	defer teardown()
  1116  
  1117  	mux.HandleFunc("/repos/o/r/code-scanning/analyses", func(w http.ResponseWriter, r *http.Request) {
  1118  		testMethod(t, r, "GET")
  1119  		testFormValues(t, r, values{"sarif_id": "8981cd8e-b078-4ac3-a3be-1dad7dbd0b582", "ref": "heads/master"})
  1120  		fmt.Fprint(w, `[
  1121  			  {
  1122  				"ref": "refs/heads/main",
  1123  				"commit_sha": "d99612c3e1f2970085cfbaeadf8f010ef69bad83",
  1124  				"analysis_key": ".github/workflows/codeql-analysis.yml:analyze",
  1125  				"environment": "{\"language\":\"python\"}",
  1126  				"error": "",
  1127  				"category": ".github/workflows/codeql-analysis.yml:analyze/language:python",
  1128  				"created_at": "2020-08-27T15:05:21Z",
  1129  				"results_count": 17,
  1130  				"rules_count": 49,
  1131  				"id": 201,
  1132  				"url": "https://api.github.com/repos/o/r/code-scanning/analyses/201",
  1133  				"sarif_id": "8981cd8e-b078-4ac3-a3be-1dad7dbd0b582",
  1134  				"tool": {
  1135  				  "name": "CodeQL",
  1136  				  "guid": null,
  1137  				  "version": "2.4.0"
  1138  				},
  1139  				"deletable": true,
  1140  				"warning": ""
  1141  			  },
  1142  			  {
  1143  				"ref": "refs/heads/my-branch",
  1144  				"commit_sha": "c8cff6510d4d084fb1b4aa13b64b97ca12b07321",
  1145  				"analysis_key": ".github/workflows/shiftleft.yml:build",
  1146  				"environment": "{}",
  1147  				"error": "",
  1148  				"category": ".github/workflows/shiftleft.yml:build/",
  1149  				"created_at": "2020-08-27T15:05:21Z",
  1150  				"results_count": 17,
  1151  				"rules_count": 32,
  1152  				"id": 200,
  1153  				"url": "https://api.github.com/repos/o/r/code-scanning/analyses/200",
  1154  				"sarif_id": "8981cd8e-b078-4ac3-a3be-1dad7dbd0b582",
  1155  				"tool": {
  1156  				  "name": "Python Security ScanningAnalysis",
  1157  				  "guid": null,
  1158  				  "version": "1.2.0"
  1159  				},
  1160  				"deletable": true,
  1161  				"warning": ""
  1162  			  }
  1163  			]`)
  1164  	})
  1165  
  1166  	opts := &AnalysesListOptions{SarifID: String("8981cd8e-b078-4ac3-a3be-1dad7dbd0b582"), Ref: String("heads/master")}
  1167  	ctx := context.Background()
  1168  	analyses, _, err := client.CodeScanning.ListAnalysesForRepo(ctx, "o", "r", opts)
  1169  	if err != nil {
  1170  		t.Errorf("CodeScanning.ListAnalysesForRepo returned error: %v", err)
  1171  	}
  1172  
  1173  	date := &Timestamp{time.Date(2020, time.August, 27, 15, 05, 21, 0, time.UTC)}
  1174  	want := []*ScanningAnalysis{
  1175  		{
  1176  			ID:           Int64(201),
  1177  			Ref:          String("refs/heads/main"),
  1178  			CommitSHA:    String("d99612c3e1f2970085cfbaeadf8f010ef69bad83"),
  1179  			AnalysisKey:  String(".github/workflows/codeql-analysis.yml:analyze"),
  1180  			Environment:  String("{\"language\":\"python\"}"),
  1181  			Error:        String(""),
  1182  			Category:     String(".github/workflows/codeql-analysis.yml:analyze/language:python"),
  1183  			CreatedAt:    date,
  1184  			ResultsCount: Int(17),
  1185  			RulesCount:   Int(49),
  1186  			URL:          String("https://api.github.com/repos/o/r/code-scanning/analyses/201"),
  1187  			SarifID:      String("8981cd8e-b078-4ac3-a3be-1dad7dbd0b582"),
  1188  			Tool: &Tool{
  1189  				Name:    String("CodeQL"),
  1190  				GUID:    nil,
  1191  				Version: String("2.4.0"),
  1192  			},
  1193  			Deletable: Bool(true),
  1194  			Warning:   String(""),
  1195  		},
  1196  		{
  1197  			ID:           Int64(200),
  1198  			Ref:          String("refs/heads/my-branch"),
  1199  			CommitSHA:    String("c8cff6510d4d084fb1b4aa13b64b97ca12b07321"),
  1200  			AnalysisKey:  String(".github/workflows/shiftleft.yml:build"),
  1201  			Environment:  String("{}"),
  1202  			Error:        String(""),
  1203  			Category:     String(".github/workflows/shiftleft.yml:build/"),
  1204  			CreatedAt:    date,
  1205  			ResultsCount: Int(17),
  1206  			RulesCount:   Int(32),
  1207  			URL:          String("https://api.github.com/repos/o/r/code-scanning/analyses/200"),
  1208  			SarifID:      String("8981cd8e-b078-4ac3-a3be-1dad7dbd0b582"),
  1209  			Tool: &Tool{
  1210  				Name:    String("Python Security ScanningAnalysis"),
  1211  				GUID:    nil,
  1212  				Version: String("1.2.0"),
  1213  			},
  1214  			Deletable: Bool(true),
  1215  			Warning:   String(""),
  1216  		},
  1217  	}
  1218  	if !cmp.Equal(analyses, want) {
  1219  		t.Errorf("CodeScanning.ListAnalysesForRepo returned %+v, want %+v", analyses, want)
  1220  	}
  1221  
  1222  	const methodName = "ListAnalysesForRepo"
  1223  	testBadOptions(t, methodName, func() (err error) {
  1224  		_, _, err = client.CodeScanning.ListAnalysesForRepo(ctx, "\n", "\n", opts)
  1225  		return err
  1226  	})
  1227  
  1228  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
  1229  		got, resp, err := client.CodeScanning.ListAnalysesForRepo(ctx, "o", "r", opts)
  1230  		if got != nil {
  1231  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
  1232  		}
  1233  		return resp, err
  1234  	})
  1235  }
  1236  
  1237  func TestCodeScanningService_GetAnalysis(t *testing.T) {
  1238  	client, mux, _, teardown := setup()
  1239  	defer teardown()
  1240  
  1241  	mux.HandleFunc("/repos/o/r/code-scanning/analyses/3602840", func(w http.ResponseWriter, r *http.Request) {
  1242  		testMethod(t, r, "GET")
  1243  		fmt.Fprint(w, `{
  1244  			  "ref": "refs/heads/main",
  1245  			  "commit_sha": "c18c69115654ff0166991962832dc2bd7756e655",
  1246  			  "analysis_key": ".github/workflows/codeql-analysis.yml:analyze",
  1247  			  "environment": "{\"language\":\"javascript\"}",
  1248  			  "error": "",
  1249  			  "category": ".github/workflows/codeql-analysis.yml:analyze/language:javascript",
  1250  			  "created_at": "2021-01-13T11:55:49Z",
  1251  			  "results_count": 3,
  1252  			  "rules_count": 67,
  1253  			  "id": 3602840,
  1254  			  "url": "https://api.github.com/repos/o/r/code-scanning/analyses/201",
  1255  			  "sarif_id": "47177e22-5596-11eb-80a1-c1e54ef945c6",
  1256  			  "tool": {
  1257  				"name": "CodeQL",
  1258  				"guid": null,
  1259  				"version": "2.4.0"
  1260  			  },
  1261  			  "deletable": true,
  1262  			  "warning": ""
  1263  			}`)
  1264  	})
  1265  
  1266  	ctx := context.Background()
  1267  	analysis, _, err := client.CodeScanning.GetAnalysis(ctx, "o", "r", 3602840)
  1268  	if err != nil {
  1269  		t.Errorf("CodeScanning.GetAnalysis returned error: %v", err)
  1270  	}
  1271  
  1272  	date := &Timestamp{time.Date(2021, time.January, 13, 11, 55, 49, 0, time.UTC)}
  1273  	want := &ScanningAnalysis{
  1274  		ID:           Int64(3602840),
  1275  		Ref:          String("refs/heads/main"),
  1276  		CommitSHA:    String("c18c69115654ff0166991962832dc2bd7756e655"),
  1277  		AnalysisKey:  String(".github/workflows/codeql-analysis.yml:analyze"),
  1278  		Environment:  String("{\"language\":\"javascript\"}"),
  1279  		Error:        String(""),
  1280  		Category:     String(".github/workflows/codeql-analysis.yml:analyze/language:javascript"),
  1281  		CreatedAt:    date,
  1282  		ResultsCount: Int(3),
  1283  		RulesCount:   Int(67),
  1284  		URL:          String("https://api.github.com/repos/o/r/code-scanning/analyses/201"),
  1285  		SarifID:      String("47177e22-5596-11eb-80a1-c1e54ef945c6"),
  1286  		Tool: &Tool{
  1287  			Name:    String("CodeQL"),
  1288  			GUID:    nil,
  1289  			Version: String("2.4.0"),
  1290  		},
  1291  		Deletable: Bool(true),
  1292  		Warning:   String(""),
  1293  	}
  1294  	if !cmp.Equal(analysis, want) {
  1295  		t.Errorf("CodeScanning.GetAnalysis returned %+v, want %+v", analysis, want)
  1296  	}
  1297  
  1298  	const methodName = "GetAnalysis"
  1299  	testBadOptions(t, methodName, func() (err error) {
  1300  		_, _, err = client.CodeScanning.GetAnalysis(ctx, "\n", "\n", -123)
  1301  		return err
  1302  	})
  1303  
  1304  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
  1305  		got, resp, err := client.CodeScanning.GetAnalysis(ctx, "o", "r", 3602840)
  1306  		if got != nil {
  1307  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
  1308  		}
  1309  		return resp, err
  1310  	})
  1311  }
  1312  
  1313  func TestCodeScanningService_DeleteAnalysis(t *testing.T) {
  1314  	client, mux, _, teardown := setup()
  1315  	defer teardown()
  1316  
  1317  	mux.HandleFunc("/repos/o/r/code-scanning/analyses/40", func(w http.ResponseWriter, r *http.Request) {
  1318  		testMethod(t, r, "DELETE")
  1319  		fmt.Fprint(w, `{
  1320  			"next_analysis_url": "a",
  1321  			"confirm_delete_url": "b"
  1322  		}`)
  1323  	})
  1324  
  1325  	ctx := context.Background()
  1326  	analysis, _, err := client.CodeScanning.DeleteAnalysis(ctx, "o", "r", 40)
  1327  	if err != nil {
  1328  		t.Errorf("CodeScanning.DeleteAnalysis returned error: %v", err)
  1329  	}
  1330  
  1331  	want := &DeleteAnalysis{
  1332  		NextAnalysisURL:  String("a"),
  1333  		ConfirmDeleteURL: String("b"),
  1334  	}
  1335  	if !cmp.Equal(analysis, want) {
  1336  		t.Errorf("CodeScanning.DeleteAnalysis returned %+v, want %+v", analysis, want)
  1337  	}
  1338  
  1339  	const methodName = "DeleteAnalysis"
  1340  	testBadOptions(t, methodName, func() (err error) {
  1341  		_, _, err = client.CodeScanning.DeleteAnalysis(ctx, "\n", "\n", -123)
  1342  		return err
  1343  	})
  1344  
  1345  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
  1346  		got, resp, err := client.CodeScanning.DeleteAnalysis(ctx, "o", "r", 40)
  1347  		if got != nil {
  1348  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
  1349  		}
  1350  		return resp, err
  1351  	})
  1352  }
  1353  
  1354  func TestCodeScanningService_ListCodeQLDatabases(t *testing.T) {
  1355  	client, mux, _, teardown := setup()
  1356  	defer teardown()
  1357  
  1358  	mux.HandleFunc("/repos/o/r/code-scanning/codeql/databases", func(w http.ResponseWriter, r *http.Request) {
  1359  		testMethod(t, r, "GET")
  1360  		fmt.Fprint(w, `[
  1361  			{
  1362  				"id": 1,
  1363  				"name": "name",
  1364  				"language": "language",
  1365  				"uploader": {
  1366  					"login": "a",
  1367  					"id": 1,
  1368  					"node_id": "b",
  1369  					"avatar_url": "c",
  1370  					"gravatar_id": "d",
  1371  					"url": "e",
  1372  					"html_url": "f",
  1373  					"followers_url": "g",
  1374  					"following_url": "h",
  1375  					"gists_url": "i",
  1376  					"starred_url": "j",
  1377  					"subscriptions_url": "k",
  1378  					"organizations_url": "l",
  1379  					"repos_url": "m",
  1380  					"events_url": "n",
  1381  					"received_events_url": "o",
  1382  					"type": "p",
  1383  					"site_admin": false
  1384  				},
  1385  				"content_type": "r",
  1386  				"size": 1024,
  1387  				"created_at": "2021-01-13T11:55:49Z",
  1388  				"updated_at": "2021-01-13T11:55:49Z",
  1389  				"url": "s"
  1390  			}
  1391  		]`)
  1392  	})
  1393  
  1394  	ctx := context.Background()
  1395  	databases, _, err := client.CodeScanning.ListCodeQLDatabases(ctx, "o", "r")
  1396  	if err != nil {
  1397  		t.Errorf("CodeScanning.ListCodeQLDatabases returned error: %v", err)
  1398  	}
  1399  
  1400  	date := &Timestamp{time.Date(2021, time.January, 13, 11, 55, 49, 0, time.UTC)}
  1401  	want := []*CodeQLDatabase{
  1402  		{
  1403  			ID:       Int64(1),
  1404  			Name:     String("name"),
  1405  			Language: String("language"),
  1406  			Uploader: &User{
  1407  				Login:             String("a"),
  1408  				ID:                Int64(1),
  1409  				NodeID:            String("b"),
  1410  				AvatarURL:         String("c"),
  1411  				GravatarID:        String("d"),
  1412  				URL:               String("e"),
  1413  				HTMLURL:           String("f"),
  1414  				FollowersURL:      String("g"),
  1415  				FollowingURL:      String("h"),
  1416  				GistsURL:          String("i"),
  1417  				StarredURL:        String("j"),
  1418  				SubscriptionsURL:  String("k"),
  1419  				OrganizationsURL:  String("l"),
  1420  				ReposURL:          String("m"),
  1421  				EventsURL:         String("n"),
  1422  				ReceivedEventsURL: String("o"),
  1423  				Type:              String("p"),
  1424  				SiteAdmin:         Bool(false),
  1425  			},
  1426  			ContentType: String("r"),
  1427  			Size:        Int64(1024),
  1428  			CreatedAt:   date,
  1429  			UpdatedAt:   date,
  1430  			URL:         String("s"),
  1431  		},
  1432  	}
  1433  
  1434  	if !cmp.Equal(databases, want) {
  1435  		t.Errorf("CodeScanning.ListCodeQLDatabases returned %+v, want %+v", databases, want)
  1436  	}
  1437  
  1438  	const methodName = "ListCodeQLDatabases"
  1439  	testBadOptions(t, methodName, func() (err error) {
  1440  		_, _, err = client.CodeScanning.ListCodeQLDatabases(ctx, "\n", "\n")
  1441  		return err
  1442  	})
  1443  
  1444  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
  1445  		got, resp, err := client.CodeScanning.ListCodeQLDatabases(ctx, "o", "r")
  1446  		if got != nil {
  1447  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
  1448  		}
  1449  		return resp, err
  1450  	})
  1451  }
  1452  
  1453  func TestCodeScanningService_GetCodeQLDatabase(t *testing.T) {
  1454  	client, mux, _, teardown := setup()
  1455  	defer teardown()
  1456  
  1457  	mux.HandleFunc("/repos/o/r/code-scanning/codeql/databases/lang", func(w http.ResponseWriter, r *http.Request) {
  1458  		testMethod(t, r, "GET")
  1459  		fmt.Fprint(w, `{
  1460  			"id": 1,
  1461  			"name": "name",
  1462  			"language": "language",
  1463  			"uploader": {
  1464  				"login": "a",
  1465  				"id": 1,
  1466  				"node_id": "b",
  1467  				"avatar_url": "c",
  1468  				"gravatar_id": "d",
  1469  				"url": "e",
  1470  				"html_url": "f",
  1471  				"followers_url": "g",
  1472  				"following_url": "h",
  1473  				"gists_url": "i",
  1474  				"starred_url": "j",
  1475  				"subscriptions_url": "k",
  1476  				"organizations_url": "l",
  1477  				"repos_url": "m",
  1478  				"events_url": "n",
  1479  				"received_events_url": "o",
  1480  				"type": "p",
  1481  				"site_admin": false
  1482  			},
  1483  			"content_type": "r",
  1484  			"size": 1024,
  1485  			"created_at": "2021-01-13T11:55:49Z",
  1486  			"updated_at": "2021-01-13T11:55:49Z",
  1487  			"url": "s"
  1488  		}`)
  1489  	})
  1490  
  1491  	ctx := context.Background()
  1492  	database, _, err := client.CodeScanning.GetCodeQLDatabase(ctx, "o", "r", "lang")
  1493  	if err != nil {
  1494  		t.Errorf("CodeScanning.GetCodeQLDatabase returned error: %v", err)
  1495  	}
  1496  
  1497  	date := &Timestamp{time.Date(2021, time.January, 13, 11, 55, 49, 0, time.UTC)}
  1498  	want := &CodeQLDatabase{
  1499  		ID:       Int64(1),
  1500  		Name:     String("name"),
  1501  		Language: String("language"),
  1502  		Uploader: &User{
  1503  			Login:             String("a"),
  1504  			ID:                Int64(1),
  1505  			NodeID:            String("b"),
  1506  			AvatarURL:         String("c"),
  1507  			GravatarID:        String("d"),
  1508  			URL:               String("e"),
  1509  			HTMLURL:           String("f"),
  1510  			FollowersURL:      String("g"),
  1511  			FollowingURL:      String("h"),
  1512  			GistsURL:          String("i"),
  1513  			StarredURL:        String("j"),
  1514  			SubscriptionsURL:  String("k"),
  1515  			OrganizationsURL:  String("l"),
  1516  			ReposURL:          String("m"),
  1517  			EventsURL:         String("n"),
  1518  			ReceivedEventsURL: String("o"),
  1519  			Type:              String("p"),
  1520  			SiteAdmin:         Bool(false),
  1521  		},
  1522  		ContentType: String("r"),
  1523  		Size:        Int64(1024),
  1524  		CreatedAt:   date,
  1525  		UpdatedAt:   date,
  1526  		URL:         String("s"),
  1527  	}
  1528  
  1529  	if !cmp.Equal(database, want) {
  1530  		t.Errorf("CodeScanning.GetCodeQLDatabase returned %+v, want %+v", database, want)
  1531  	}
  1532  
  1533  	const methodName = "GetCodeQLDatabase"
  1534  	testBadOptions(t, methodName, func() (err error) {
  1535  		_, _, err = client.CodeScanning.GetCodeQLDatabase(ctx, "\n", "\n", "\n")
  1536  		return err
  1537  	})
  1538  
  1539  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
  1540  		got, resp, err := client.CodeScanning.GetCodeQLDatabase(ctx, "o", "r", "lang")
  1541  		if got != nil {
  1542  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
  1543  		}
  1544  		return resp, err
  1545  	})
  1546  }
  1547  
  1548  func TestCodeScanningService_GetDefaultSetupConfiguration(t *testing.T) {
  1549  	client, mux, _, teardown := setup()
  1550  	defer teardown()
  1551  
  1552  	mux.HandleFunc("/repos/o/r/code-scanning/default-setup", func(w http.ResponseWriter, r *http.Request) {
  1553  		testMethod(t, r, "GET")
  1554  		_, err := fmt.Fprint(w, `{
  1555  		"state": "configured",
  1556  		"languages": [
  1557  			"javascript",
  1558  			"javascript-typescript",
  1559  			"typescript"
  1560  		],
  1561  		"query_suite": "default",
  1562  		"updated_at": "2006-01-02T15:04:05Z"
  1563  		}`)
  1564  		if err != nil {
  1565  			t.Fatal(err)
  1566  		}
  1567  	})
  1568  
  1569  	ctx := context.Background()
  1570  	cfg, _, err := client.CodeScanning.GetDefaultSetupConfiguration(ctx, "o", "r")
  1571  	if err != nil {
  1572  		t.Errorf("CodeScanning.GetDefaultSetupConfiguration returned error: %v", err)
  1573  	}
  1574  
  1575  	date := &Timestamp{time.Date(2006, time.January, 02, 15, 04, 05, 0, time.UTC)}
  1576  	want := &DefaultSetupConfiguration{
  1577  		State:      String("configured"),
  1578  		Languages:  []string{"javascript", "javascript-typescript", "typescript"},
  1579  		QuerySuite: String("default"),
  1580  		UpdatedAt:  date,
  1581  	}
  1582  	if !cmp.Equal(cfg, want) {
  1583  		t.Errorf("CodeScanning.GetDefaultSetupConfiguration returned %+v, want %+v", cfg, want)
  1584  	}
  1585  
  1586  	const methodName = "GetDefaultSetupConfiguration"
  1587  	testBadOptions(t, methodName, func() (err error) {
  1588  		_, _, err = client.CodeScanning.GetDefaultSetupConfiguration(ctx, "\n", "\n")
  1589  		return err
  1590  	})
  1591  
  1592  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
  1593  		got, resp, err := client.CodeScanning.GetDefaultSetupConfiguration(ctx, "o", "r")
  1594  		if got != nil {
  1595  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
  1596  		}
  1597  		return resp, err
  1598  	})
  1599  }
  1600  
  1601  func TestCodeScanningService_UpdateDefaultSetupConfiguration(t *testing.T) {
  1602  	client, mux, _, teardown := setup()
  1603  	defer teardown()
  1604  
  1605  	mux.HandleFunc("/repos/o/r/code-scanning/default-setup", func(w http.ResponseWriter, r *http.Request) {
  1606  		testMethod(t, r, "PATCH")
  1607  		_, err := fmt.Fprint(w, `{
  1608  		"run_id": 5301214200,
  1609  		"run_url": "https://api.github.com/repos/o/r/actions/runs/5301214200"
  1610  		}`)
  1611  		if err != nil {
  1612  			t.Fatal(err)
  1613  		}
  1614  	})
  1615  
  1616  	ctx := context.Background()
  1617  	options := &UpdateDefaultSetupConfigurationOptions{
  1618  		State:      "configured",
  1619  		Languages:  []string{"go"},
  1620  		QuerySuite: String("default"),
  1621  	}
  1622  	got, _, err := client.CodeScanning.UpdateDefaultSetupConfiguration(ctx, "o", "r", options)
  1623  	if err != nil {
  1624  		t.Errorf("CodeScanning.UpdateDefaultSetupConfiguration returned error: %v", err)
  1625  	}
  1626  
  1627  	want := &UpdateDefaultSetupConfigurationResponse{
  1628  		RunID:  Int64(5301214200),
  1629  		RunURL: String("https://api.github.com/repos/o/r/actions/runs/5301214200"),
  1630  	}
  1631  	if !cmp.Equal(got, want) {
  1632  		t.Errorf("CodeScanning.UpdateDefaultSetupConfiguration returned %+v, want %+v", got, want)
  1633  	}
  1634  
  1635  	const methodName = "UpdateDefaultSetupConfiguration"
  1636  	testBadOptions(t, methodName, func() (err error) {
  1637  		_, _, err = client.CodeScanning.UpdateDefaultSetupConfiguration(ctx, "\n", "\n", nil)
  1638  		return err
  1639  	})
  1640  
  1641  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
  1642  		got, resp, err := client.CodeScanning.UpdateDefaultSetupConfiguration(ctx, "o", "r", nil)
  1643  		if got != nil {
  1644  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
  1645  		}
  1646  		return resp, err
  1647  	})
  1648  }