github.com/google/go-github/v49@v49.1.0/github/secret_scanning_test.go (about) 1 // Copyright 2022 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 TestSecretScanningService_ListAlertsForEnterprise(t *testing.T) { 20 client, mux, _, teardown := setup() 21 defer teardown() 22 23 mux.HandleFunc("/enterprises/e/secret-scanning/alerts", func(w http.ResponseWriter, r *http.Request) { 24 testMethod(t, r, "GET") 25 testFormValues(t, r, values{"state": "open", "secret_type": "mailchimp_api_key"}) 26 27 fmt.Fprint(w, `[{ 28 "number": 1, 29 "created_at": "1996-06-20T00:00:00Z", 30 "url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1", 31 "html_url": "https://github.com/o/r/security/secret-scanning/1", 32 "locations_url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations", 33 "state": "open", 34 "resolution": null, 35 "resolved_at": null, 36 "resolved_by": null, 37 "secret_type": "mailchimp_api_key", 38 "secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2" 39 }]`) 40 }) 41 42 ctx := context.Background() 43 opts := &SecretScanningAlertListOptions{State: "open", SecretType: "mailchimp_api_key"} 44 45 alerts, _, err := client.SecretScanning.ListAlertsForEnterprise(ctx, "e", opts) 46 if err != nil { 47 t.Errorf("SecretScanning.ListAlertsForEnterprise returned error: %v", err) 48 } 49 50 date := Timestamp{time.Date(1996, time.June, 20, 00, 00, 00, 0, time.UTC)} 51 want := []*SecretScanningAlert{ 52 { 53 Number: Int(1), 54 CreatedAt: &date, 55 URL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1"), 56 HTMLURL: String("https://github.com/o/r/security/secret-scanning/1"), 57 LocationsURL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations"), 58 State: String("open"), 59 Resolution: nil, 60 ResolvedAt: nil, 61 ResolvedBy: nil, 62 SecretType: String("mailchimp_api_key"), 63 Secret: String("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2"), 64 }, 65 } 66 67 if !cmp.Equal(alerts, want) { 68 t.Errorf("SecretScanning.ListAlertsForEnterprise returned %+v, want %+v", alerts, want) 69 } 70 71 const methodName = "ListAlertsForEnterprise" 72 73 testBadOptions(t, methodName, func() (err error) { 74 _, _, err = client.SecretScanning.ListAlertsForEnterprise(ctx, "\n", opts) 75 return err 76 }) 77 78 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 79 _, resp, err := client.SecretScanning.ListAlertsForEnterprise(ctx, "e", opts) 80 return resp, err 81 }) 82 } 83 84 func TestSecretScanningService_ListAlertsForOrg(t *testing.T) { 85 client, mux, _, teardown := setup() 86 defer teardown() 87 88 mux.HandleFunc("/orgs/o/secret-scanning/alerts", func(w http.ResponseWriter, r *http.Request) { 89 testMethod(t, r, "GET") 90 testFormValues(t, r, values{"state": "open", "secret_type": "mailchimp_api_key"}) 91 92 fmt.Fprint(w, `[{ 93 "number": 1, 94 "created_at": "1996-06-20T00:00:00Z", 95 "url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1", 96 "html_url": "https://github.com/o/r/security/secret-scanning/1", 97 "locations_url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations", 98 "state": "open", 99 "resolution": null, 100 "resolved_at": null, 101 "resolved_by": null, 102 "secret_type": "mailchimp_api_key", 103 "secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2" 104 }]`) 105 }) 106 107 ctx := context.Background() 108 opts := &SecretScanningAlertListOptions{State: "open", SecretType: "mailchimp_api_key"} 109 110 alerts, _, err := client.SecretScanning.ListAlertsForOrg(ctx, "o", opts) 111 if err != nil { 112 t.Errorf("SecretScanning.ListAlertsForOrg returned error: %v", err) 113 } 114 115 date := Timestamp{time.Date(1996, time.June, 20, 00, 00, 00, 0, time.UTC)} 116 want := []*SecretScanningAlert{ 117 { 118 Number: Int(1), 119 CreatedAt: &date, 120 URL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1"), 121 HTMLURL: String("https://github.com/o/r/security/secret-scanning/1"), 122 LocationsURL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations"), 123 State: String("open"), 124 Resolution: nil, 125 ResolvedAt: nil, 126 ResolvedBy: nil, 127 SecretType: String("mailchimp_api_key"), 128 Secret: String("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2"), 129 }, 130 } 131 132 if !cmp.Equal(alerts, want) { 133 t.Errorf("SecretScanning.ListAlertsForOrg returned %+v, want %+v", alerts, want) 134 } 135 136 const methodName = "ListAlertsForOrg" 137 138 testBadOptions(t, methodName, func() (err error) { 139 _, _, err = client.SecretScanning.ListAlertsForOrg(ctx, "\n", opts) 140 return err 141 }) 142 143 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 144 _, resp, err := client.SecretScanning.ListAlertsForOrg(ctx, "o", opts) 145 return resp, err 146 }) 147 } 148 149 func TestSecretScanningService_ListAlertsForOrgListOptions(t *testing.T) { 150 client, mux, _, teardown := setup() 151 defer teardown() 152 153 mux.HandleFunc("/orgs/o/secret-scanning/alerts", func(w http.ResponseWriter, r *http.Request) { 154 testMethod(t, r, "GET") 155 testFormValues(t, r, values{"state": "open", "secret_type": "mailchimp_api_key", "per_page": "1", "page": "1"}) 156 157 fmt.Fprint(w, `[{ 158 "number": 1, 159 "created_at": "1996-06-20T00:00:00Z", 160 "url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1", 161 "html_url": "https://github.com/o/r/security/secret-scanning/1", 162 "locations_url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations", 163 "state": "open", 164 "resolution": null, 165 "resolved_at": null, 166 "resolved_by": null, 167 "secret_type": "mailchimp_api_key", 168 "secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2" 169 }]`) 170 }) 171 172 ctx := context.Background() 173 174 // Testing pagination by index 175 opts := &SecretScanningAlertListOptions{State: "open", SecretType: "mailchimp_api_key", ListOptions: ListOptions{Page: 1, PerPage: 1}} 176 177 alerts, _, err := client.SecretScanning.ListAlertsForOrg(ctx, "o", opts) 178 if err != nil { 179 t.Errorf("SecretScanning.ListAlertsForOrg returned error: %v", err) 180 } 181 182 date := Timestamp{time.Date(1996, time.June, 20, 00, 00, 00, 0, time.UTC)} 183 want := []*SecretScanningAlert{ 184 { 185 Number: Int(1), 186 CreatedAt: &date, 187 URL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1"), 188 HTMLURL: String("https://github.com/o/r/security/secret-scanning/1"), 189 LocationsURL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations"), 190 State: String("open"), 191 Resolution: nil, 192 ResolvedAt: nil, 193 ResolvedBy: nil, 194 SecretType: String("mailchimp_api_key"), 195 Secret: String("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2"), 196 }, 197 } 198 199 if !cmp.Equal(alerts, want) { 200 t.Errorf("SecretScanning.ListAlertsForOrg returned %+v, want %+v", alerts, want) 201 } 202 203 const methodName = "ListAlertsForOrg" 204 205 testBadOptions(t, methodName, func() (err error) { 206 _, _, err = client.SecretScanning.ListAlertsForOrg(ctx, "\n", opts) 207 return err 208 }) 209 210 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 211 _, resp, err := client.SecretScanning.ListAlertsForOrg(ctx, "o", opts) 212 return resp, err 213 }) 214 } 215 216 func TestSecretScanningService_ListAlertsForRepo(t *testing.T) { 217 client, mux, _, teardown := setup() 218 defer teardown() 219 220 mux.HandleFunc("/repos/o/r/secret-scanning/alerts", func(w http.ResponseWriter, r *http.Request) { 221 testMethod(t, r, "GET") 222 testFormValues(t, r, values{"state": "open", "secret_type": "mailchimp_api_key"}) 223 224 fmt.Fprint(w, `[{ 225 "number": 1, 226 "created_at": "1996-06-20T00:00:00Z", 227 "url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1", 228 "html_url": "https://github.com/o/r/security/secret-scanning/1", 229 "locations_url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations", 230 "state": "open", 231 "resolution": null, 232 "resolved_at": null, 233 "resolved_by": null, 234 "secret_type": "mailchimp_api_key", 235 "secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2" 236 }]`) 237 }) 238 239 ctx := context.Background() 240 opts := &SecretScanningAlertListOptions{State: "open", SecretType: "mailchimp_api_key"} 241 242 alerts, _, err := client.SecretScanning.ListAlertsForRepo(ctx, "o", "r", opts) 243 if err != nil { 244 t.Errorf("SecretScanning.ListAlertsForRepo returned error: %v", err) 245 } 246 247 date := Timestamp{time.Date(1996, time.June, 20, 00, 00, 00, 0, time.UTC)} 248 want := []*SecretScanningAlert{ 249 { 250 Number: Int(1), 251 CreatedAt: &date, 252 URL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1"), 253 HTMLURL: String("https://github.com/o/r/security/secret-scanning/1"), 254 LocationsURL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations"), 255 State: String("open"), 256 Resolution: nil, 257 ResolvedAt: nil, 258 ResolvedBy: nil, 259 SecretType: String("mailchimp_api_key"), 260 Secret: String("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2"), 261 }, 262 } 263 264 if !cmp.Equal(alerts, want) { 265 t.Errorf("SecretScanning.ListAlertsForRepo returned %+v, want %+v", alerts, want) 266 } 267 268 const methodName = "ListAlertsForRepo" 269 270 testBadOptions(t, methodName, func() (err error) { 271 _, _, err = client.SecretScanning.ListAlertsForRepo(ctx, "\n", "\n", opts) 272 return err 273 }) 274 275 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 276 _, resp, err := client.SecretScanning.ListAlertsForRepo(ctx, "o", "r", opts) 277 return resp, err 278 }) 279 } 280 281 func TestSecretScanningService_GetAlert(t *testing.T) { 282 client, mux, _, teardown := setup() 283 defer teardown() 284 285 mux.HandleFunc("/repos/o/r/secret-scanning/alerts/1", func(w http.ResponseWriter, r *http.Request) { 286 testMethod(t, r, "GET") 287 288 fmt.Fprint(w, `{ 289 "number": 1, 290 "created_at": "1996-06-20T00:00:00Z", 291 "url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1", 292 "html_url": "https://github.com/o/r/security/secret-scanning/1", 293 "locations_url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations", 294 "state": "open", 295 "resolution": null, 296 "resolved_at": null, 297 "resolved_by": null, 298 "secret_type": "mailchimp_api_key", 299 "secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2" 300 }`) 301 }) 302 303 ctx := context.Background() 304 305 alert, _, err := client.SecretScanning.GetAlert(ctx, "o", "r", 1) 306 if err != nil { 307 t.Errorf("SecretScanning.GetAlert returned error: %v", err) 308 } 309 310 date := Timestamp{time.Date(1996, time.June, 20, 00, 00, 00, 0, time.UTC)} 311 want := &SecretScanningAlert{ 312 Number: Int(1), 313 CreatedAt: &date, 314 URL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1"), 315 HTMLURL: String("https://github.com/o/r/security/secret-scanning/1"), 316 LocationsURL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations"), 317 State: String("open"), 318 Resolution: nil, 319 ResolvedAt: nil, 320 ResolvedBy: nil, 321 SecretType: String("mailchimp_api_key"), 322 Secret: String("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2"), 323 } 324 325 if !cmp.Equal(alert, want) { 326 t.Errorf("SecretScanning.GetAlert returned %+v, want %+v", alert, want) 327 } 328 329 const methodName = "GetAlert" 330 331 testBadOptions(t, methodName, func() (err error) { 332 _, _, err = client.SecretScanning.GetAlert(ctx, "\n", "\n", 0) 333 return err 334 }) 335 336 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 337 _, resp, err := client.SecretScanning.GetAlert(ctx, "o", "r", 1) 338 return resp, err 339 }) 340 } 341 342 func TestSecretScanningService_UpdateAlert(t *testing.T) { 343 client, mux, _, teardown := setup() 344 defer teardown() 345 346 mux.HandleFunc("/repos/o/r/secret-scanning/alerts/1", func(w http.ResponseWriter, r *http.Request) { 347 testMethod(t, r, "PATCH") 348 349 v := new(SecretScanningAlertUpdateOptions) 350 json.NewDecoder(r.Body).Decode(v) 351 352 want := &SecretScanningAlertUpdateOptions{State: String("resolved"), Resolution: String("used_in_tests")} 353 354 if !cmp.Equal(v, want) { 355 t.Errorf("Request body = %+v, want %+v", v, want) 356 } 357 358 fmt.Fprint(w, `{ 359 "number": 1, 360 "created_at": "1996-06-20T00:00:00Z", 361 "url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1", 362 "html_url": "https://github.com/o/r/security/secret-scanning/1", 363 "locations_url": "https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations", 364 "state": "resolved", 365 "resolution": "used_in_tests", 366 "resolved_at": "1996-06-20T00:00:00Z", 367 "resolved_by": null, 368 "secret_type": "mailchimp_api_key", 369 "secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2" 370 }`) 371 }) 372 373 ctx := context.Background() 374 opts := &SecretScanningAlertUpdateOptions{State: String("resolved"), Resolution: String("used_in_tests")} 375 376 alert, _, err := client.SecretScanning.UpdateAlert(ctx, "o", "r", 1, opts) 377 if err != nil { 378 t.Errorf("SecretScanning.UpdateAlert returned error: %v", err) 379 } 380 381 date := Timestamp{time.Date(1996, time.June, 20, 00, 00, 00, 0, time.UTC)} 382 want := &SecretScanningAlert{ 383 Number: Int(1), 384 CreatedAt: &date, 385 URL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1"), 386 HTMLURL: String("https://github.com/o/r/security/secret-scanning/1"), 387 LocationsURL: String("https://api.github.com/repos/o/r/secret-scanning/alerts/1/locations"), 388 State: String("resolved"), 389 Resolution: String("used_in_tests"), 390 ResolvedAt: &date, 391 ResolvedBy: nil, 392 SecretType: String("mailchimp_api_key"), 393 Secret: String("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us2"), 394 } 395 396 if !cmp.Equal(alert, want) { 397 t.Errorf("SecretScanning.UpdateAlert returned %+v, want %+v", alert, want) 398 } 399 400 const methodName = "UpdateAlert" 401 402 testBadOptions(t, methodName, func() (err error) { 403 _, _, err = client.SecretScanning.UpdateAlert(ctx, "\n", "\n", 1, opts) 404 return err 405 }) 406 407 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 408 _, resp, err := client.SecretScanning.UpdateAlert(ctx, "o", "r", 1, opts) 409 return resp, err 410 }) 411 } 412 413 func TestSecretScanningService_ListLocationsForAlert(t *testing.T) { 414 client, mux, _, teardown := setup() 415 defer teardown() 416 417 mux.HandleFunc("/repos/o/r/secret-scanning/alerts/1/locations", func(w http.ResponseWriter, r *http.Request) { 418 testMethod(t, r, "GET") 419 testFormValues(t, r, values{"page": "1", "per_page": "100"}) 420 421 fmt.Fprint(w, `[{ 422 "type": "commit", 423 "details": { 424 "path": "/example/secrets.txt", 425 "start_line": 1, 426 "end_line": 1, 427 "start_column": 1, 428 "end_column": 64, 429 "blob_sha": "af5626b4a114abcb82d63db7c8082c3c4756e51b", 430 "blob_url": "https://api.github.com/repos/o/r/git/blobs/af5626b4a114abcb82d63db7c8082c3c4756e51b", 431 "commit_sha": "f14d7debf9775f957cf4f1e8176da0786431f72b", 432 "commit_url": "https://api.github.com/repos/o/r/git/commits/f14d7debf9775f957cf4f1e8176da0786431f72b" 433 } 434 }]`) 435 }) 436 437 ctx := context.Background() 438 opts := &ListOptions{Page: 1, PerPage: 100} 439 440 locations, _, err := client.SecretScanning.ListLocationsForAlert(ctx, "o", "r", 1, opts) 441 if err != nil { 442 t.Errorf("SecretScanning.ListLocationsForAlert returned error: %v", err) 443 } 444 445 want := []*SecretScanningAlertLocation{ 446 { 447 Type: String("commit"), 448 Details: &SecretScanningAlertLocationDetails{ 449 Path: String("/example/secrets.txt"), 450 Startline: Int(1), 451 EndLine: Int(1), 452 StartColumn: Int(1), 453 EndColumn: Int(64), 454 BlobSHA: String("af5626b4a114abcb82d63db7c8082c3c4756e51b"), 455 BlobURL: String("https://api.github.com/repos/o/r/git/blobs/af5626b4a114abcb82d63db7c8082c3c4756e51b"), 456 CommitSHA: String("f14d7debf9775f957cf4f1e8176da0786431f72b"), 457 CommitURL: String("https://api.github.com/repos/o/r/git/commits/f14d7debf9775f957cf4f1e8176da0786431f72b"), 458 }, 459 }, 460 } 461 462 if !cmp.Equal(locations, want) { 463 t.Errorf("SecretScanning.ListLocationsForAlert returned %+v, want %+v", locations, want) 464 } 465 466 const methodName = "ListLocationsForAlert" 467 468 testBadOptions(t, methodName, func() (err error) { 469 _, _, err = client.SecretScanning.ListLocationsForAlert(ctx, "\n", "\n", 1, opts) 470 return err 471 }) 472 473 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 474 _, resp, err := client.SecretScanning.ListLocationsForAlert(ctx, "o", "r", 1, opts) 475 return resp, err 476 }) 477 } 478 479 func TestSecretScanningAlert_Marshal(t *testing.T) { 480 testJSONMarshal(t, &SecretScanningAlert{}, `{}`) 481 482 u := &SecretScanningAlert{ 483 Number: Int(1), 484 CreatedAt: &Timestamp{referenceTime}, 485 URL: String("https://api.github.com/teams/2/discussions/3/comments"), 486 HTMLURL: String("https://api.github.com/teams/2/discussions/3/comments"), 487 LocationsURL: String("https://api.github.com/teams/2/discussions/3/comments"), 488 State: String("test_state"), 489 Resolution: String("test_resolution"), 490 ResolvedAt: &Timestamp{referenceTime}, 491 ResolvedBy: &User{ 492 Login: String("test"), 493 ID: Int64(10), 494 NodeID: String("A123"), 495 AvatarURL: String("https://api.github.com/teams/2/discussions/3/comments"), 496 }, 497 SecretType: String("test"), 498 Secret: String("test"), 499 } 500 501 want := `{ 502 "number": 1, 503 "created_at": ` + referenceTimeStr + `, 504 "url": "https://api.github.com/teams/2/discussions/3/comments", 505 "html_url": "https://api.github.com/teams/2/discussions/3/comments", 506 "locations_url": "https://api.github.com/teams/2/discussions/3/comments", 507 "state": "test_state", 508 "resolution": "test_resolution", 509 "resolved_at": ` + referenceTimeStr + `, 510 "resolved_by": { 511 "login": "test", 512 "id": 10, 513 "node_id": "A123", 514 "avatar_url": "https://api.github.com/teams/2/discussions/3/comments" 515 }, 516 "secret_type": "test", 517 "secret": "test" 518 }` 519 520 testJSONMarshal(t, u, want) 521 } 522 523 func TestSecretScanningAlertLocation_Marshal(t *testing.T) { 524 testJSONMarshal(t, &SecretScanningAlertLocation{}, `{}`) 525 526 u := &SecretScanningAlertLocation{ 527 Type: String("test"), 528 Details: &SecretScanningAlertLocationDetails{ 529 Path: String("test_path"), 530 Startline: Int(10), 531 EndLine: Int(20), 532 StartColumn: Int(30), 533 EndColumn: Int(40), 534 BlobSHA: String("test_sha"), 535 BlobURL: String("https://api.github.com/repos/o/r/git/commits/f14d7debf9775f957cf4f1e8176da0786431f72b"), 536 CommitSHA: String("test_sha"), 537 CommitURL: String("https://api.github.com/repos/o/r/git/commits/f14d7debf9775f957cf4f1e8176da0786431f72b"), 538 }, 539 } 540 541 want := `{ 542 "type": "test", 543 "details": { 544 "path": "test_path", 545 "start_line": 10, 546 "end_line": 20, 547 "start_column": 30, 548 "end_column": 40, 549 "blob_sha": "test_sha", 550 "blob_url": "https://api.github.com/repos/o/r/git/commits/f14d7debf9775f957cf4f1e8176da0786431f72b", 551 "commit_sha": "test_sha", 552 "commit_url": "https://api.github.com/repos/o/r/git/commits/f14d7debf9775f957cf4f1e8176da0786431f72b" 553 } 554 }` 555 556 testJSONMarshal(t, u, want) 557 } 558 559 func TestSecretScanningAlertLocationDetails_Marshal(t *testing.T) { 560 testJSONMarshal(t, &SecretScanningAlertLocationDetails{}, `{}`) 561 562 u := &SecretScanningAlertLocationDetails{ 563 Path: String("test_path"), 564 Startline: Int(10), 565 EndLine: Int(20), 566 StartColumn: Int(30), 567 EndColumn: Int(40), 568 BlobSHA: String("test_sha"), 569 BlobURL: String("https://api.github.com/repos/o/r/git/commits/f14d7debf9775f957cf4f1e8176da0786431f72b"), 570 CommitSHA: String("test_sha"), 571 CommitURL: String("https://api.github.com/repos/o/r/git/commits/f14d7debf9775f957cf4f1e8176da0786431f72b"), 572 } 573 574 want := `{ 575 "path": "test_path", 576 "start_line": 10, 577 "end_line": 20, 578 "start_column": 30, 579 "end_column": 40, 580 "blob_sha": "test_sha", 581 "blob_url": "https://api.github.com/repos/o/r/git/commits/f14d7debf9775f957cf4f1e8176da0786431f72b", 582 "commit_sha": "test_sha", 583 "commit_url": "https://api.github.com/repos/o/r/git/commits/f14d7debf9775f957cf4f1e8176da0786431f72b" 584 }` 585 586 testJSONMarshal(t, u, want) 587 }