...

Source file src/github.com/google/go-github/v55/github/code-scanning_test.go

Documentation: github.com/google/go-github/v55/github

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

View as plain text