github.com/google/go-github/v49@v49.1.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  	mux.HandleFunc("/repos/o/r/code-scanning/sarifs", func(w http.ResponseWriter, r *http.Request) {
    62  		v := new(SarifAnalysis)
    63  		json.NewDecoder(r.Body).Decode(v)
    64  		testMethod(t, r, "POST")
    65  		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")}
    66  		if !cmp.Equal(v, want) {
    67  			t.Errorf("Request body = %+v, want %+v", v, want)
    68  		}
    69  
    70  		fmt.Fprint(w, `{"commit_sha":"abc","ref":"ref/head/main","sarif":"abc"}`)
    71  	})
    72  
    73  	ctx := context.Background()
    74  	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")}
    75  	_, _, err := client.CodeScanning.UploadSarif(ctx, "o", "r", sarifAnalysis)
    76  	if err != nil {
    77  		t.Errorf("CodeScanning.UploadSarif returned error: %v", err)
    78  	}
    79  
    80  	const methodName = "UploadSarif"
    81  	testBadOptions(t, methodName, func() (err error) {
    82  		_, _, err = client.CodeScanning.UploadSarif(ctx, "\n", "\n", sarifAnalysis)
    83  		return err
    84  	})
    85  
    86  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
    87  		_, resp, err := client.CodeScanning.UploadSarif(ctx, "o", "r", sarifAnalysis)
    88  		return resp, err
    89  	})
    90  }
    91  
    92  func TestCodeScanningService_ListAlertsForOrg(t *testing.T) {
    93  	client, mux, _, teardown := setup()
    94  	defer teardown()
    95  
    96  	mux.HandleFunc("/orgs/o/code-scanning/alerts", func(w http.ResponseWriter, r *http.Request) {
    97  		testMethod(t, r, "GET")
    98  		testFormValues(t, r, values{"state": "open", "ref": "heads/master"})
    99  		fmt.Fprint(w, `[{
   100  				"repository": {
   101  					"id": 1,
   102  					"name": "n",
   103  					"url": "url"
   104  				},
   105  				"rule_id":"js/trivial-conditional",
   106  				"rule_severity":"warning",
   107  				"rule_description":"Useless conditional",
   108  				"tool": {
   109  					"name": "CodeQL",
   110  					"guid": null,
   111  					"version": "1.4.0"
   112  				},
   113  				"rule": {
   114  					"id": "js/trivial-conditional",
   115  					"severity": "warning",
   116  					"description": "Useless conditional",
   117  					"name": "js/trivial-conditional",
   118  					"full_description": "Expression has no effect",
   119  					"help": "Expression has no effect"
   120  				},
   121  				"most_recent_instance": {
   122  					"ref": "refs/heads/main",
   123  					"state": "open",
   124  					"commit_sha": "abcdefg12345",
   125  					"message": {
   126  						"text": "This path depends on a user-provided value."
   127  					},
   128  					"location": {
   129  						"path": "spec-main/api-session-spec.ts",
   130  						"start_line": 917,
   131  						"end_line": 917,
   132  						"start_column": 7,
   133  						"end_column": 18
   134  					},
   135  					"classifications": [
   136  						"test"
   137  					]
   138  				},
   139  				"created_at":"2020-05-06T12:00:00Z",
   140  				"state":"open",
   141  				"closed_by":null,
   142  				"closed_at":null,
   143  				"url":"https://api.github.com/repos/o/r/code-scanning/alerts/25",
   144  				"html_url":"https://github.com/o/r/security/code-scanning/25"
   145  				},
   146  				{
   147  				"rule_id":"js/useless-expression",
   148  				"rule_severity":"warning",
   149  				"rule_description":"Expression has no effect",
   150  				"tool": {
   151  					"name": "CodeQL",
   152  					"guid": null,
   153  					"version": "1.4.0"
   154  				},
   155  				"rule": {
   156  					"id": "js/useless-expression",
   157  					"severity": "warning",
   158  					"description": "Expression has no effect",
   159  					"name": "js/useless-expression",
   160  					"full_description": "Expression has no effect",
   161  					"help": "Expression has no effect"
   162  				},
   163  				"most_recent_instance": {
   164  					"ref": "refs/heads/main",
   165  					"state": "open",
   166  					"commit_sha": "abcdefg12345",
   167  					"message": {
   168  						"text": "This path depends on a user-provided value."
   169  					},
   170  					"location": {
   171  						"path": "spec-main/api-session-spec.ts",
   172  						"start_line": 917,
   173  						"end_line": 917,
   174  						"start_column": 7,
   175  						"end_column": 18
   176  					},
   177  					"classifications": [
   178  						"test"
   179  					]
   180  				},
   181  				"created_at":"2020-05-06T12:00:00Z",
   182  				"state":"open",
   183  				"closed_by":null,
   184  				"closed_at":null,
   185  				"url":"https://api.github.com/repos/o/r/code-scanning/alerts/88",
   186  				"html_url":"https://github.com/o/r/security/code-scanning/88"
   187  				}]`)
   188  	})
   189  
   190  	opts := &AlertListOptions{State: "open", Ref: "heads/master"}
   191  	ctx := context.Background()
   192  	alerts, _, err := client.CodeScanning.ListAlertsForOrg(ctx, "o", opts)
   193  	if err != nil {
   194  		t.Errorf("CodeScanning.ListAlertsForOrg returned error: %v", err)
   195  	}
   196  
   197  	date := Timestamp{time.Date(2020, time.May, 06, 12, 00, 00, 0, time.UTC)}
   198  	want := []*Alert{
   199  		{
   200  			Repository: &Repository{
   201  				ID:   Int64(1),
   202  				URL:  String("url"),
   203  				Name: String("n"),
   204  			},
   205  			RuleID:          String("js/trivial-conditional"),
   206  			RuleSeverity:    String("warning"),
   207  			RuleDescription: String("Useless conditional"),
   208  			Tool:            &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")},
   209  			Rule: &Rule{
   210  				ID:              String("js/trivial-conditional"),
   211  				Severity:        String("warning"),
   212  				Description:     String("Useless conditional"),
   213  				Name:            String("js/trivial-conditional"),
   214  				FullDescription: String("Expression has no effect"),
   215  				Help:            String("Expression has no effect"),
   216  			},
   217  			CreatedAt: &date,
   218  			State:     String("open"),
   219  			ClosedBy:  nil,
   220  			ClosedAt:  nil,
   221  			URL:       String("https://api.github.com/repos/o/r/code-scanning/alerts/25"),
   222  			HTMLURL:   String("https://github.com/o/r/security/code-scanning/25"),
   223  			MostRecentInstance: &MostRecentInstance{
   224  				Ref:       String("refs/heads/main"),
   225  				State:     String("open"),
   226  				CommitSHA: String("abcdefg12345"),
   227  				Message: &Message{
   228  					Text: String("This path depends on a user-provided value."),
   229  				},
   230  				Location: &Location{
   231  					Path:        String("spec-main/api-session-spec.ts"),
   232  					StartLine:   Int(917),
   233  					EndLine:     Int(917),
   234  					StartColumn: Int(7),
   235  					EndColumn:   Int(18),
   236  				},
   237  				Classifications: []string{"test"},
   238  			},
   239  		},
   240  		{
   241  			RuleID:          String("js/useless-expression"),
   242  			RuleSeverity:    String("warning"),
   243  			RuleDescription: String("Expression has no effect"),
   244  			Tool:            &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")},
   245  			Rule: &Rule{
   246  				ID:              String("js/useless-expression"),
   247  				Severity:        String("warning"),
   248  				Description:     String("Expression has no effect"),
   249  				Name:            String("js/useless-expression"),
   250  				FullDescription: String("Expression has no effect"),
   251  				Help:            String("Expression has no effect"),
   252  			},
   253  			CreatedAt: &date,
   254  			State:     String("open"),
   255  			ClosedBy:  nil,
   256  			ClosedAt:  nil,
   257  			URL:       String("https://api.github.com/repos/o/r/code-scanning/alerts/88"),
   258  			HTMLURL:   String("https://github.com/o/r/security/code-scanning/88"),
   259  			MostRecentInstance: &MostRecentInstance{
   260  				Ref:       String("refs/heads/main"),
   261  				State:     String("open"),
   262  				CommitSHA: String("abcdefg12345"),
   263  				Message: &Message{
   264  					Text: String("This path depends on a user-provided value."),
   265  				},
   266  				Location: &Location{
   267  					Path:        String("spec-main/api-session-spec.ts"),
   268  					StartLine:   Int(917),
   269  					EndLine:     Int(917),
   270  					StartColumn: Int(7),
   271  					EndColumn:   Int(18),
   272  				},
   273  				Classifications: []string{"test"},
   274  			},
   275  		},
   276  	}
   277  	if !cmp.Equal(alerts, want) {
   278  		t.Errorf("CodeScanning.ListAlertsForOrg returned %+v, want %+v", *&alerts, *&want)
   279  	}
   280  
   281  	const methodName = "ListAlertsForOrg"
   282  	testBadOptions(t, methodName, func() (err error) {
   283  		_, _, err = client.CodeScanning.ListAlertsForOrg(ctx, "\n", opts)
   284  		return err
   285  	})
   286  
   287  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   288  		got, resp, err := client.CodeScanning.ListAlertsForOrg(ctx, "o", opts)
   289  		if got != nil {
   290  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   291  		}
   292  		return resp, err
   293  	})
   294  }
   295  
   296  func TestCodeScanningService_ListAlertsForOrgLisCursorOptions(t *testing.T) {
   297  	client, mux, _, teardown := setup()
   298  	defer teardown()
   299  
   300  	mux.HandleFunc("/orgs/o/code-scanning/alerts", func(w http.ResponseWriter, r *http.Request) {
   301  		testMethod(t, r, "GET")
   302  		testFormValues(t, r, values{"state": "open", "ref": "heads/master", "per_page": "1", "before": "deadbeefb", "after": "deadbeefa"})
   303  		fmt.Fprint(w, `[{
   304  				"repository": {
   305  					"id": 1,
   306  					"name": "n",
   307  					"url": "url"
   308  				},
   309  				"rule_id":"js/trivial-conditional",
   310  				"rule_severity":"warning",
   311  				"rule_description":"Useless conditional",
   312  				"tool": {
   313  					"name": "CodeQL",
   314  					"guid": null,
   315  					"version": "1.4.0"
   316  				},
   317  				"rule": {
   318  					"id": "js/trivial-conditional",
   319  					"severity": "warning",
   320  					"description": "Useless conditional",
   321  					"name": "js/trivial-conditional",
   322  					"full_description": "Expression has no effect",
   323  					"help": "Expression has no effect"
   324  				},
   325  				"most_recent_instance": {
   326  					"ref": "refs/heads/main",
   327  					"state": "open",
   328  					"commit_sha": "abcdefg12345",
   329  					"message": {
   330  						"text": "This path depends on a user-provided value."
   331  					},
   332  					"location": {
   333  						"path": "spec-main/api-session-spec.ts",
   334  						"start_line": 917,
   335  						"end_line": 917,
   336  						"start_column": 7,
   337  						"end_column": 18
   338  					},
   339  					"classifications": [
   340  						"test"
   341  					]
   342  				},
   343  				"created_at":"2020-05-06T12:00:00Z",
   344  				"state":"open",
   345  				"closed_by":null,
   346  				"closed_at":null,
   347  				"url":"https://api.github.com/repos/o/r/code-scanning/alerts/25",
   348  				"html_url":"https://github.com/o/r/security/code-scanning/25"
   349  				}]`)
   350  	})
   351  
   352  	opts := &AlertListOptions{State: "open", Ref: "heads/master", ListCursorOptions: ListCursorOptions{PerPage: 1, Before: "deadbeefb", After: "deadbeefa"}}
   353  	ctx := context.Background()
   354  	alerts, _, err := client.CodeScanning.ListAlertsForOrg(ctx, "o", opts)
   355  	if err != nil {
   356  		t.Errorf("CodeScanning.ListAlertsForOrg returned error: %v", err)
   357  	}
   358  
   359  	date := Timestamp{time.Date(2020, time.May, 06, 12, 00, 00, 0, time.UTC)}
   360  	want := []*Alert{
   361  		{
   362  			Repository: &Repository{
   363  				ID:   Int64(1),
   364  				URL:  String("url"),
   365  				Name: String("n"),
   366  			},
   367  			RuleID:          String("js/trivial-conditional"),
   368  			RuleSeverity:    String("warning"),
   369  			RuleDescription: String("Useless conditional"),
   370  			Tool:            &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")},
   371  			Rule: &Rule{
   372  				ID:              String("js/trivial-conditional"),
   373  				Severity:        String("warning"),
   374  				Description:     String("Useless conditional"),
   375  				Name:            String("js/trivial-conditional"),
   376  				FullDescription: String("Expression has no effect"),
   377  				Help:            String("Expression has no effect"),
   378  			},
   379  			CreatedAt: &date,
   380  			State:     String("open"),
   381  			ClosedBy:  nil,
   382  			ClosedAt:  nil,
   383  			URL:       String("https://api.github.com/repos/o/r/code-scanning/alerts/25"),
   384  			HTMLURL:   String("https://github.com/o/r/security/code-scanning/25"),
   385  			MostRecentInstance: &MostRecentInstance{
   386  				Ref:       String("refs/heads/main"),
   387  				State:     String("open"),
   388  				CommitSHA: String("abcdefg12345"),
   389  				Message: &Message{
   390  					Text: String("This path depends on a user-provided value."),
   391  				},
   392  				Location: &Location{
   393  					Path:        String("spec-main/api-session-spec.ts"),
   394  					StartLine:   Int(917),
   395  					EndLine:     Int(917),
   396  					StartColumn: Int(7),
   397  					EndColumn:   Int(18),
   398  				},
   399  				Classifications: []string{"test"},
   400  			},
   401  		},
   402  	}
   403  	if !cmp.Equal(alerts, want) {
   404  		t.Errorf("CodeScanning.ListAlertsForOrg returned %+v, want %+v", *&alerts, *&want)
   405  	}
   406  
   407  	const methodName = "ListAlertsForOrg"
   408  	testBadOptions(t, methodName, func() (err error) {
   409  		_, _, err = client.CodeScanning.ListAlertsForOrg(ctx, "\n", opts)
   410  		return err
   411  	})
   412  
   413  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   414  		got, resp, err := client.CodeScanning.ListAlertsForOrg(ctx, "o", opts)
   415  		if got != nil {
   416  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   417  		}
   418  		return resp, err
   419  	})
   420  }
   421  
   422  func TestCodeScanningService_ListAlertsForRepo(t *testing.T) {
   423  	client, mux, _, teardown := setup()
   424  	defer teardown()
   425  
   426  	mux.HandleFunc("/repos/o/r/code-scanning/alerts", func(w http.ResponseWriter, r *http.Request) {
   427  		testMethod(t, r, "GET")
   428  		testFormValues(t, r, values{"state": "open", "ref": "heads/master"})
   429  		fmt.Fprint(w, `[{
   430  				"rule_id":"js/trivial-conditional",
   431  				"rule_severity":"warning",
   432  				"rule_description":"Useless conditional",
   433  				"tool": {
   434  					"name": "CodeQL",
   435  					"guid": null,
   436  					"version": "1.4.0"
   437  				},
   438  				"rule": {
   439  					"id": "js/trivial-conditional",
   440  					"severity": "warning",
   441  					"description": "Useless conditional",
   442  					"name": "js/trivial-conditional",
   443  					"full_description": "Expression has no effect",
   444  					"help": "Expression has no effect"
   445  				},
   446  				"most_recent_instance": {
   447  					"ref": "refs/heads/main",
   448  					"state": "open",
   449  					"commit_sha": "abcdefg12345",
   450  					"message": {
   451  						"text": "This path depends on a user-provided value."
   452  					},
   453  					"location": {
   454  						"path": "spec-main/api-session-spec.ts",
   455  						"start_line": 917,
   456  						"end_line": 917,
   457  						"start_column": 7,
   458  						"end_column": 18
   459  					},
   460  					"classifications": [
   461  						"test"
   462  					]
   463  				},
   464  				"created_at":"2020-05-06T12:00:00Z",
   465  				"state":"open",
   466  				"closed_by":null,
   467  				"closed_at":null,
   468  				"url":"https://api.github.com/repos/o/r/code-scanning/alerts/25",
   469  				"html_url":"https://github.com/o/r/security/code-scanning/25"
   470  				},
   471  				{
   472  				"rule_id":"js/useless-expression",
   473  				"rule_severity":"warning",
   474  				"rule_description":"Expression has no effect",
   475  				"tool": {
   476  					"name": "CodeQL",
   477  					"guid": null,
   478  					"version": "1.4.0"
   479  				},
   480  				"rule": {
   481  					"id": "js/useless-expression",
   482  					"severity": "warning",
   483  					"description": "Expression has no effect",
   484  					"name": "js/useless-expression",
   485  					"full_description": "Expression has no effect",
   486  					"help": "Expression has no effect"
   487  				},
   488  				"most_recent_instance": {
   489  					"ref": "refs/heads/main",
   490  					"state": "open",
   491  					"commit_sha": "abcdefg12345",
   492  					"message": {
   493  						"text": "This path depends on a user-provided value."
   494  					},
   495  					"location": {
   496  						"path": "spec-main/api-session-spec.ts",
   497  						"start_line": 917,
   498  						"end_line": 917,
   499  						"start_column": 7,
   500  						"end_column": 18
   501  					},
   502  					"classifications": [
   503  						"test"
   504  					]
   505  				},
   506  				"created_at":"2020-05-06T12:00:00Z",
   507  				"state":"open",
   508  				"closed_by":null,
   509  				"closed_at":null,
   510  				"url":"https://api.github.com/repos/o/r/code-scanning/alerts/88",
   511  				"html_url":"https://github.com/o/r/security/code-scanning/88"
   512  				}]`)
   513  	})
   514  
   515  	opts := &AlertListOptions{State: "open", Ref: "heads/master"}
   516  	ctx := context.Background()
   517  	alerts, _, err := client.CodeScanning.ListAlertsForRepo(ctx, "o", "r", opts)
   518  	if err != nil {
   519  		t.Errorf("CodeScanning.ListAlertsForRepo returned error: %v", err)
   520  	}
   521  
   522  	date := Timestamp{time.Date(2020, time.May, 06, 12, 00, 00, 0, time.UTC)}
   523  	want := []*Alert{
   524  		{
   525  			RuleID:          String("js/trivial-conditional"),
   526  			RuleSeverity:    String("warning"),
   527  			RuleDescription: String("Useless conditional"),
   528  			Tool:            &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")},
   529  			Rule: &Rule{
   530  				ID:              String("js/trivial-conditional"),
   531  				Severity:        String("warning"),
   532  				Description:     String("Useless conditional"),
   533  				Name:            String("js/trivial-conditional"),
   534  				FullDescription: String("Expression has no effect"),
   535  				Help:            String("Expression has no effect"),
   536  			},
   537  			CreatedAt: &date,
   538  			State:     String("open"),
   539  			ClosedBy:  nil,
   540  			ClosedAt:  nil,
   541  			URL:       String("https://api.github.com/repos/o/r/code-scanning/alerts/25"),
   542  			HTMLURL:   String("https://github.com/o/r/security/code-scanning/25"),
   543  			MostRecentInstance: &MostRecentInstance{
   544  				Ref:       String("refs/heads/main"),
   545  				State:     String("open"),
   546  				CommitSHA: String("abcdefg12345"),
   547  				Message: &Message{
   548  					Text: String("This path depends on a user-provided value."),
   549  				},
   550  				Location: &Location{
   551  					Path:        String("spec-main/api-session-spec.ts"),
   552  					StartLine:   Int(917),
   553  					EndLine:     Int(917),
   554  					StartColumn: Int(7),
   555  					EndColumn:   Int(18),
   556  				},
   557  				Classifications: []string{"test"},
   558  			},
   559  		},
   560  		{
   561  			RuleID:          String("js/useless-expression"),
   562  			RuleSeverity:    String("warning"),
   563  			RuleDescription: String("Expression has no effect"),
   564  			Tool:            &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")},
   565  			Rule: &Rule{
   566  				ID:              String("js/useless-expression"),
   567  				Severity:        String("warning"),
   568  				Description:     String("Expression has no effect"),
   569  				Name:            String("js/useless-expression"),
   570  				FullDescription: String("Expression has no effect"),
   571  				Help:            String("Expression has no effect"),
   572  			},
   573  			CreatedAt: &date,
   574  			State:     String("open"),
   575  			ClosedBy:  nil,
   576  			ClosedAt:  nil,
   577  			URL:       String("https://api.github.com/repos/o/r/code-scanning/alerts/88"),
   578  			HTMLURL:   String("https://github.com/o/r/security/code-scanning/88"),
   579  			MostRecentInstance: &MostRecentInstance{
   580  				Ref:       String("refs/heads/main"),
   581  				State:     String("open"),
   582  				CommitSHA: String("abcdefg12345"),
   583  				Message: &Message{
   584  					Text: String("This path depends on a user-provided value."),
   585  				},
   586  				Location: &Location{
   587  					Path:        String("spec-main/api-session-spec.ts"),
   588  					StartLine:   Int(917),
   589  					EndLine:     Int(917),
   590  					StartColumn: Int(7),
   591  					EndColumn:   Int(18),
   592  				},
   593  				Classifications: []string{"test"},
   594  			},
   595  		},
   596  	}
   597  	if !cmp.Equal(alerts, want) {
   598  		t.Errorf("CodeScanning.ListAlertsForRepo returned %+v, want %+v", alerts, want)
   599  	}
   600  
   601  	const methodName = "ListAlertsForRepo"
   602  	testBadOptions(t, methodName, func() (err error) {
   603  		_, _, err = client.CodeScanning.ListAlertsForRepo(ctx, "\n", "\n", opts)
   604  		return err
   605  	})
   606  
   607  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   608  		got, resp, err := client.CodeScanning.ListAlertsForRepo(ctx, "o", "r", opts)
   609  		if got != nil {
   610  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   611  		}
   612  		return resp, err
   613  	})
   614  }
   615  
   616  func TestCodeScanningService_GetAlert(t *testing.T) {
   617  	client, mux, _, teardown := setup()
   618  	defer teardown()
   619  
   620  	mux.HandleFunc("/repos/o/r/code-scanning/alerts/88", func(w http.ResponseWriter, r *http.Request) {
   621  		testMethod(t, r, "GET")
   622  		fmt.Fprint(w, `{"rule_id":"js/useless-expression",
   623  				"rule_severity":"warning",
   624  				"rule_description":"Expression has no effect",
   625  				"tool": {
   626  					"name": "CodeQL",
   627  					"guid": null,
   628  					"version": "1.4.0"
   629  				},
   630  				"rule": {
   631  					"id": "useless expression",
   632  					"severity": "warning",
   633  					"description": "Expression has no effect",
   634  					"name": "useless expression",
   635  					"full_description": "Expression has no effect",
   636  					"help": "Expression has no effect"
   637  				},
   638  				"most_recent_instance": {
   639  					"ref": "refs/heads/main",
   640  					"state": "open",
   641  					"commit_sha": "abcdefg12345",
   642  					"message": {
   643  						"text": "This path depends on a user-provided value."
   644  					},
   645  					"location": {
   646  						"path": "spec-main/api-session-spec.ts",
   647  						"start_line": 917,
   648  						"end_line": 917,
   649  						"start_column": 7,
   650  						"end_column": 18
   651  					},
   652  					"classifications": [
   653  						"test"
   654  					]
   655  				},
   656  				"created_at":"2019-01-02T15:04:05Z",
   657  				"state":"open",
   658  				"closed_by":null,
   659  				"closed_at":null,
   660  				"url":"https://api.github.com/repos/o/r/code-scanning/alerts/88",
   661  				"html_url":"https://github.com/o/r/security/code-scanning/88"}`)
   662  	})
   663  
   664  	ctx := context.Background()
   665  	alert, _, err := client.CodeScanning.GetAlert(ctx, "o", "r", 88)
   666  	if err != nil {
   667  		t.Errorf("CodeScanning.GetAlert returned error: %v", err)
   668  	}
   669  
   670  	date := Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}
   671  	want := &Alert{
   672  		RuleID:          String("js/useless-expression"),
   673  		RuleSeverity:    String("warning"),
   674  		RuleDescription: String("Expression has no effect"),
   675  		Tool:            &Tool{Name: String("CodeQL"), GUID: nil, Version: String("1.4.0")},
   676  		Rule: &Rule{
   677  			ID:              String("useless expression"),
   678  			Severity:        String("warning"),
   679  			Description:     String("Expression has no effect"),
   680  			Name:            String("useless expression"),
   681  			FullDescription: String("Expression has no effect"),
   682  			Help:            String("Expression has no effect"),
   683  		},
   684  		CreatedAt: &date,
   685  		State:     String("open"),
   686  		ClosedBy:  nil,
   687  		ClosedAt:  nil,
   688  		URL:       String("https://api.github.com/repos/o/r/code-scanning/alerts/88"),
   689  		HTMLURL:   String("https://github.com/o/r/security/code-scanning/88"),
   690  		MostRecentInstance: &MostRecentInstance{
   691  			Ref:       String("refs/heads/main"),
   692  			State:     String("open"),
   693  			CommitSHA: String("abcdefg12345"),
   694  			Message: &Message{
   695  				Text: String("This path depends on a user-provided value."),
   696  			},
   697  			Location: &Location{
   698  				Path:        String("spec-main/api-session-spec.ts"),
   699  				StartLine:   Int(917),
   700  				EndLine:     Int(917),
   701  				StartColumn: Int(7),
   702  				EndColumn:   Int(18),
   703  			},
   704  			Classifications: []string{"test"},
   705  		},
   706  	}
   707  	if !cmp.Equal(alert, want) {
   708  		t.Errorf("CodeScanning.GetAlert returned %+v, want %+v", alert, want)
   709  	}
   710  
   711  	const methodName = "GetAlert"
   712  	testBadOptions(t, methodName, func() (err error) {
   713  		_, _, err = client.CodeScanning.GetAlert(ctx, "\n", "\n", -88)
   714  		return err
   715  	})
   716  
   717  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   718  		got, resp, err := client.CodeScanning.GetAlert(ctx, "o", "r", 88)
   719  		if got != nil {
   720  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   721  		}
   722  		return resp, err
   723  	})
   724  }
   725  
   726  func TestAlert_Marshal(t *testing.T) {
   727  	testJSONMarshal(t, &Alert{}, "{}")
   728  
   729  	u := &Alert{
   730  		RuleID:          String("rid"),
   731  		RuleSeverity:    String("rs"),
   732  		RuleDescription: String("rd"),
   733  		Tool: &Tool{
   734  			Name:    String("n"),
   735  			GUID:    String("g"),
   736  			Version: String("v"),
   737  		},
   738  		CreatedAt: &Timestamp{referenceTime},
   739  		State:     String("fixed"),
   740  		ClosedBy: &User{
   741  			Login:     String("l"),
   742  			ID:        Int64(1),
   743  			NodeID:    String("n"),
   744  			URL:       String("u"),
   745  			ReposURL:  String("r"),
   746  			EventsURL: String("e"),
   747  			AvatarURL: String("a"),
   748  		},
   749  		ClosedAt: &Timestamp{referenceTime},
   750  		URL:      String("url"),
   751  		HTMLURL:  String("hurl"),
   752  	}
   753  
   754  	want := `{
   755  		"rule_id": "rid",
   756  		"rule_severity": "rs",
   757  		"rule_description": "rd",
   758  		"tool": {
   759  			"name": "n",
   760  			"guid": "g",
   761  			"version": "v"
   762  		},
   763  		"created_at": ` + referenceTimeStr + `,
   764  		"state": "fixed",
   765  		"closed_by": {
   766  			"login": "l",
   767  			"id": 1,
   768  			"node_id": "n",
   769  			"avatar_url": "a",
   770  			"url": "u",
   771  			"events_url": "e",
   772  			"repos_url": "r"
   773  		},
   774  		"closed_at": ` + referenceTimeStr + `,
   775  		"url": "url",
   776  		"html_url": "hurl"
   777  	}`
   778  
   779  	testJSONMarshal(t, u, want)
   780  }
   781  
   782  func TestLocation_Marshal(t *testing.T) {
   783  	testJSONMarshal(t, &Location{}, "{}")
   784  
   785  	u := &Location{
   786  		Path:        String("path"),
   787  		StartLine:   Int(1),
   788  		EndLine:     Int(2),
   789  		StartColumn: Int(3),
   790  		EndColumn:   Int(4),
   791  	}
   792  
   793  	want := `{
   794  		"path": "path",
   795  		"start_line": 1,
   796  		"end_line": 2,
   797  		"start_column": 3,
   798  		"end_column": 4
   799  	}`
   800  
   801  	testJSONMarshal(t, u, want)
   802  }
   803  
   804  func TestRule_Marshal(t *testing.T) {
   805  	testJSONMarshal(t, &Rule{}, "{}")
   806  
   807  	u := &Rule{
   808  		ID:                    String("1"),
   809  		Severity:              String("3"),
   810  		Description:           String("description"),
   811  		Name:                  String("first"),
   812  		SecuritySeverityLevel: String("2"),
   813  		FullDescription:       String("summary"),
   814  		Tags:                  []string{"tag1", "tag2"},
   815  		Help:                  String("Help Text"),
   816  	}
   817  
   818  	want := `{
   819  		"id":                      "1",
   820  		"severity":                "3",
   821  		"description":             "description",
   822  		"name":                    "first",
   823  		"security_severity_level": "2",
   824  		"full_description":        "summary",
   825  		"tags":                    ["tag1", "tag2"],
   826  		"help":                    "Help Text"
   827  	}`
   828  
   829  	testJSONMarshal(t, u, want)
   830  }
   831  
   832  func TestTool_Marshal(t *testing.T) {
   833  	testJSONMarshal(t, &Tool{}, "{}")
   834  
   835  	u := &Tool{
   836  		Name:    String("name"),
   837  		GUID:    String("guid"),
   838  		Version: String("ver"),
   839  	}
   840  
   841  	want := `{
   842  		"name": "name",
   843  		"guid": "guid",
   844  		"version": "ver"
   845  	}`
   846  
   847  	testJSONMarshal(t, u, want)
   848  }
   849  
   850  func TestMessage_Marshal(t *testing.T) {
   851  	testJSONMarshal(t, &Message{}, "{}")
   852  
   853  	u := &Message{
   854  		Text: String("text"),
   855  	}
   856  
   857  	want := `{
   858  		"text": "text"
   859  	}`
   860  
   861  	testJSONMarshal(t, u, want)
   862  }
   863  
   864  func TestCodeScanningService_ListAnalysesForRepo(t *testing.T) {
   865  	client, mux, _, teardown := setup()
   866  	defer teardown()
   867  
   868  	mux.HandleFunc("/repos/o/r/code-scanning/analyses", func(w http.ResponseWriter, r *http.Request) {
   869  		testMethod(t, r, "GET")
   870  		testFormValues(t, r, values{"sarif_id": "8981cd8e-b078-4ac3-a3be-1dad7dbd0b582", "ref": "heads/master"})
   871  		fmt.Fprint(w, `[
   872  			  {
   873  				"ref": "refs/heads/main",
   874  				"commit_sha": "d99612c3e1f2970085cfbaeadf8f010ef69bad83",
   875  				"analysis_key": ".github/workflows/codeql-analysis.yml:analyze",
   876  				"environment": "{\"language\":\"python\"}",
   877  				"error": "",
   878  				"category": ".github/workflows/codeql-analysis.yml:analyze/language:python",
   879  				"created_at": "2020-08-27T15:05:21Z",
   880  				"results_count": 17,
   881  				"rules_count": 49,
   882  				"id": 201,
   883  				"url": "https://api.github.com/repos/o/r/code-scanning/analyses/201",
   884  				"sarif_id": "8981cd8e-b078-4ac3-a3be-1dad7dbd0b582",
   885  				"tool": {
   886  				  "name": "CodeQL",
   887  				  "guid": null,
   888  				  "version": "2.4.0"
   889  				},
   890  				"deletable": true,
   891  				"warning": ""
   892  			  },
   893  			  {
   894  				"ref": "refs/heads/my-branch",
   895  				"commit_sha": "c8cff6510d4d084fb1b4aa13b64b97ca12b07321",
   896  				"analysis_key": ".github/workflows/shiftleft.yml:build",
   897  				"environment": "{}",
   898  				"error": "",
   899  				"category": ".github/workflows/shiftleft.yml:build/",
   900  				"created_at": "2020-08-27T15:05:21Z",
   901  				"results_count": 17,
   902  				"rules_count": 32,
   903  				"id": 200,
   904  				"url": "https://api.github.com/repos/o/r/code-scanning/analyses/200",
   905  				"sarif_id": "8981cd8e-b078-4ac3-a3be-1dad7dbd0b582",
   906  				"tool": {
   907  				  "name": "Python Security ScanningAnalysis",
   908  				  "guid": null,
   909  				  "version": "1.2.0"
   910  				},
   911  				"deletable": true,
   912  				"warning": ""
   913  			  }
   914  			]`)
   915  	})
   916  
   917  	opts := &AnalysesListOptions{SarifID: String("8981cd8e-b078-4ac3-a3be-1dad7dbd0b582"), Ref: String("heads/master")}
   918  	ctx := context.Background()
   919  	analyses, _, err := client.CodeScanning.ListAnalysesForRepo(ctx, "o", "r", opts)
   920  	if err != nil {
   921  		t.Errorf("CodeScanning.ListAnalysesForRepo returned error: %v", err)
   922  	}
   923  
   924  	date := &Timestamp{time.Date(2020, time.August, 27, 15, 05, 21, 0, time.UTC)}
   925  	want := []*ScanningAnalysis{
   926  		{
   927  			ID:           Int64(201),
   928  			Ref:          String("refs/heads/main"),
   929  			CommitSHA:    String("d99612c3e1f2970085cfbaeadf8f010ef69bad83"),
   930  			AnalysisKey:  String(".github/workflows/codeql-analysis.yml:analyze"),
   931  			Environment:  String("{\"language\":\"python\"}"),
   932  			Error:        String(""),
   933  			Category:     String(".github/workflows/codeql-analysis.yml:analyze/language:python"),
   934  			CreatedAt:    date,
   935  			ResultsCount: Int(17),
   936  			RulesCount:   Int(49),
   937  			URL:          String("https://api.github.com/repos/o/r/code-scanning/analyses/201"),
   938  			SarifID:      String("8981cd8e-b078-4ac3-a3be-1dad7dbd0b582"),
   939  			Tool: &Tool{
   940  				Name:    String("CodeQL"),
   941  				GUID:    nil,
   942  				Version: String("2.4.0"),
   943  			},
   944  			Deletable: Bool(true),
   945  			Warning:   String(""),
   946  		},
   947  		{
   948  			ID:           Int64(200),
   949  			Ref:          String("refs/heads/my-branch"),
   950  			CommitSHA:    String("c8cff6510d4d084fb1b4aa13b64b97ca12b07321"),
   951  			AnalysisKey:  String(".github/workflows/shiftleft.yml:build"),
   952  			Environment:  String("{}"),
   953  			Error:        String(""),
   954  			Category:     String(".github/workflows/shiftleft.yml:build/"),
   955  			CreatedAt:    date,
   956  			ResultsCount: Int(17),
   957  			RulesCount:   Int(32),
   958  			URL:          String("https://api.github.com/repos/o/r/code-scanning/analyses/200"),
   959  			SarifID:      String("8981cd8e-b078-4ac3-a3be-1dad7dbd0b582"),
   960  			Tool: &Tool{
   961  				Name:    String("Python Security ScanningAnalysis"),
   962  				GUID:    nil,
   963  				Version: String("1.2.0"),
   964  			},
   965  			Deletable: Bool(true),
   966  			Warning:   String(""),
   967  		},
   968  	}
   969  	if !cmp.Equal(analyses, want) {
   970  		t.Errorf("CodeScanning.ListAnalysesForRepo returned %+v, want %+v", analyses, want)
   971  	}
   972  
   973  	const methodName = "ListAnalysesForRepo"
   974  	testBadOptions(t, methodName, func() (err error) {
   975  		_, _, err = client.CodeScanning.ListAnalysesForRepo(ctx, "\n", "\n", opts)
   976  		return err
   977  	})
   978  
   979  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   980  		got, resp, err := client.CodeScanning.ListAnalysesForRepo(ctx, "o", "r", opts)
   981  		if got != nil {
   982  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   983  		}
   984  		return resp, err
   985  	})
   986  }
   987  
   988  func TestCodeScanningService_GetAnalysis(t *testing.T) {
   989  	client, mux, _, teardown := setup()
   990  	defer teardown()
   991  
   992  	mux.HandleFunc("/repos/o/r/code-scanning/analyses/3602840", func(w http.ResponseWriter, r *http.Request) {
   993  		testMethod(t, r, "GET")
   994  		fmt.Fprint(w, `{
   995  			  "ref": "refs/heads/main",
   996  			  "commit_sha": "c18c69115654ff0166991962832dc2bd7756e655",
   997  			  "analysis_key": ".github/workflows/codeql-analysis.yml:analyze",
   998  			  "environment": "{\"language\":\"javascript\"}",
   999  			  "error": "",
  1000  			  "category": ".github/workflows/codeql-analysis.yml:analyze/language:javascript",
  1001  			  "created_at": "2021-01-13T11:55:49Z",
  1002  			  "results_count": 3,
  1003  			  "rules_count": 67,
  1004  			  "id": 3602840,
  1005  			  "url": "https://api.github.com/repos/o/r/code-scanning/analyses/201",
  1006  			  "sarif_id": "47177e22-5596-11eb-80a1-c1e54ef945c6",
  1007  			  "tool": {
  1008  				"name": "CodeQL",
  1009  				"guid": null,
  1010  				"version": "2.4.0"
  1011  			  },
  1012  			  "deletable": true,
  1013  			  "warning": ""
  1014  			}`)
  1015  	})
  1016  
  1017  	ctx := context.Background()
  1018  	analysis, _, err := client.CodeScanning.GetAnalysis(ctx, "o", "r", 3602840)
  1019  	if err != nil {
  1020  		t.Errorf("CodeScanning.GetAnalysis returned error: %v", err)
  1021  	}
  1022  
  1023  	date := &Timestamp{time.Date(2021, time.January, 13, 11, 55, 49, 0, time.UTC)}
  1024  	want := &ScanningAnalysis{
  1025  		ID:           Int64(3602840),
  1026  		Ref:          String("refs/heads/main"),
  1027  		CommitSHA:    String("c18c69115654ff0166991962832dc2bd7756e655"),
  1028  		AnalysisKey:  String(".github/workflows/codeql-analysis.yml:analyze"),
  1029  		Environment:  String("{\"language\":\"javascript\"}"),
  1030  		Error:        String(""),
  1031  		Category:     String(".github/workflows/codeql-analysis.yml:analyze/language:javascript"),
  1032  		CreatedAt:    date,
  1033  		ResultsCount: Int(3),
  1034  		RulesCount:   Int(67),
  1035  		URL:          String("https://api.github.com/repos/o/r/code-scanning/analyses/201"),
  1036  		SarifID:      String("47177e22-5596-11eb-80a1-c1e54ef945c6"),
  1037  		Tool: &Tool{
  1038  			Name:    String("CodeQL"),
  1039  			GUID:    nil,
  1040  			Version: String("2.4.0"),
  1041  		},
  1042  		Deletable: Bool(true),
  1043  		Warning:   String(""),
  1044  	}
  1045  	if !cmp.Equal(analysis, want) {
  1046  		t.Errorf("CodeScanning.GetAnalysis returned %+v, want %+v", analysis, want)
  1047  	}
  1048  
  1049  	const methodName = "GetAnalysis"
  1050  	testBadOptions(t, methodName, func() (err error) {
  1051  		_, _, err = client.CodeScanning.GetAnalysis(ctx, "\n", "\n", -123)
  1052  		return err
  1053  	})
  1054  
  1055  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
  1056  		got, resp, err := client.CodeScanning.GetAnalysis(ctx, "o", "r", 3602840)
  1057  		if got != nil {
  1058  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
  1059  		}
  1060  		return resp, err
  1061  	})
  1062  }