github.com/google/go-github/v71@v71.0.0/github/repos_contents_test.go (about) 1 // Copyright 2014 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 "errors" 11 "fmt" 12 "io" 13 "net/http" 14 "net/url" 15 "testing" 16 17 "github.com/google/go-cmp/cmp" 18 ) 19 20 func TestRepositoryContent_GetContent(t *testing.T) { 21 t.Parallel() 22 tests := []struct { 23 encoding, content *string // input encoding and content 24 want string // desired output 25 wantErr bool // whether an error is expected 26 }{ 27 { 28 encoding: Ptr(""), 29 content: Ptr("hello"), 30 want: "hello", 31 wantErr: false, 32 }, 33 { 34 encoding: nil, 35 content: Ptr("hello"), 36 want: "hello", 37 wantErr: false, 38 }, 39 { 40 encoding: nil, 41 content: nil, 42 want: "", 43 wantErr: false, 44 }, 45 { 46 encoding: Ptr("base64"), 47 content: Ptr("aGVsbG8="), 48 want: "hello", 49 wantErr: false, 50 }, 51 { 52 encoding: Ptr("bad"), 53 content: Ptr("aGVsbG8="), 54 want: "", 55 wantErr: true, 56 }, 57 { 58 encoding: Ptr("none"), 59 content: nil, 60 want: "", 61 wantErr: true, 62 }, 63 } 64 65 for _, tt := range tests { 66 r := RepositoryContent{Encoding: tt.encoding, Content: tt.content} 67 got, err := r.GetContent() 68 if err != nil && !tt.wantErr { 69 t.Errorf("RepositoryContent(%s, %s) returned unexpected error: %v", 70 stringOrNil(tt.encoding), stringOrNil(tt.content), err) 71 } 72 if err == nil && tt.wantErr { 73 t.Errorf("RepositoryContent(%s, %s) did not return unexpected error", 74 stringOrNil(tt.encoding), stringOrNil(tt.content)) 75 } 76 if want := tt.want; got != want { 77 t.Errorf("RepositoryContent.GetContent returned %+v, want %+v", got, want) 78 } 79 } 80 } 81 82 // stringOrNil converts a potentially null string pointer to string. 83 // For non-nil input pointer, the returned string is enclosed in double-quotes. 84 func stringOrNil(s *string) string { 85 if s == nil { 86 return "<nil>" 87 } 88 return fmt.Sprintf("%q", *s) 89 } 90 91 func TestRepositoriesService_GetReadme(t *testing.T) { 92 t.Parallel() 93 client, mux, _ := setup(t) 94 95 mux.HandleFunc("/repos/o/r/readme", func(w http.ResponseWriter, r *http.Request) { 96 testMethod(t, r, "GET") 97 fmt.Fprint(w, `{ 98 "type": "file", 99 "encoding": "base64", 100 "size": 5362, 101 "name": "README.md", 102 "path": "README.md" 103 }`) 104 }) 105 ctx := context.Background() 106 readme, _, err := client.Repositories.GetReadme(ctx, "o", "r", &RepositoryContentGetOptions{}) 107 if err != nil { 108 t.Errorf("Repositories.GetReadme returned error: %v", err) 109 } 110 want := &RepositoryContent{Type: Ptr("file"), Name: Ptr("README.md"), Size: Ptr(5362), Encoding: Ptr("base64"), Path: Ptr("README.md")} 111 if !cmp.Equal(readme, want) { 112 t.Errorf("Repositories.GetReadme returned %+v, want %+v", readme, want) 113 } 114 115 const methodName = "GetReadme" 116 testBadOptions(t, methodName, func() (err error) { 117 _, _, err = client.Repositories.GetReadme(ctx, "\n", "\n", &RepositoryContentGetOptions{}) 118 return err 119 }) 120 121 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 122 got, resp, err := client.Repositories.GetReadme(ctx, "o", "r", &RepositoryContentGetOptions{}) 123 if got != nil { 124 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 125 } 126 return resp, err 127 }) 128 } 129 130 func TestRepositoriesService_DownloadContents_Success(t *testing.T) { 131 t.Parallel() 132 client, mux, serverURL := setup(t) 133 134 mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { 135 testMethod(t, r, "GET") 136 fmt.Fprint(w, `[{ 137 "type": "file", 138 "name": "f", 139 "download_url": "`+serverURL+baseURLPath+`/download/f" 140 }]`) 141 }) 142 mux.HandleFunc("/download/f", func(w http.ResponseWriter, r *http.Request) { 143 testMethod(t, r, "GET") 144 fmt.Fprint(w, "foo") 145 }) 146 147 ctx := context.Background() 148 r, resp, err := client.Repositories.DownloadContents(ctx, "o", "r", "d/f", nil) 149 if err != nil { 150 t.Errorf("Repositories.DownloadContents returned error: %v", err) 151 } 152 153 if got, want := resp.Response.StatusCode, http.StatusOK; got != want { 154 t.Errorf("Repositories.DownloadContents returned status code %v, want %v", got, want) 155 } 156 157 bytes, err := io.ReadAll(r) 158 if err != nil { 159 t.Errorf("Error reading response body: %v", err) 160 } 161 r.Close() 162 163 if got, want := string(bytes), "foo"; got != want { 164 t.Errorf("Repositories.DownloadContents returned %v, want %v", got, want) 165 } 166 167 const methodName = "DownloadContents" 168 testBadOptions(t, methodName, func() (err error) { 169 _, _, err = client.Repositories.DownloadContents(ctx, "\n", "\n", "\n", nil) 170 return err 171 }) 172 173 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 174 got, resp, err := client.Repositories.DownloadContents(ctx, "o", "r", "d/f", nil) 175 if got != nil { 176 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 177 } 178 return resp, err 179 }) 180 } 181 182 func TestRepositoriesService_DownloadContents_FailedResponse(t *testing.T) { 183 t.Parallel() 184 client, mux, serverURL := setup(t) 185 186 mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { 187 testMethod(t, r, "GET") 188 fmt.Fprint(w, `[{ 189 "type": "file", 190 "name": "f", 191 "download_url": "`+serverURL+baseURLPath+`/download/f" 192 }]`) 193 }) 194 mux.HandleFunc("/download/f", func(w http.ResponseWriter, r *http.Request) { 195 testMethod(t, r, "GET") 196 w.WriteHeader(http.StatusInternalServerError) 197 fmt.Fprint(w, "foo error") 198 }) 199 200 ctx := context.Background() 201 r, resp, err := client.Repositories.DownloadContents(ctx, "o", "r", "d/f", nil) 202 if err != nil { 203 t.Errorf("Repositories.DownloadContents returned error: %v", err) 204 } 205 206 if got, want := resp.Response.StatusCode, http.StatusInternalServerError; got != want { 207 t.Errorf("Repositories.DownloadContents returned status code %v, want %v", got, want) 208 } 209 210 bytes, err := io.ReadAll(r) 211 if err != nil { 212 t.Errorf("Error reading response body: %v", err) 213 } 214 r.Close() 215 216 if got, want := string(bytes), "foo error"; got != want { 217 t.Errorf("Repositories.DownloadContents returned %v, want %v", got, want) 218 } 219 } 220 221 func TestRepositoriesService_DownloadContents_NoDownloadURL(t *testing.T) { 222 t.Parallel() 223 client, mux, _ := setup(t) 224 225 mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { 226 testMethod(t, r, "GET") 227 fmt.Fprint(w, `[{ 228 "type": "file", 229 "name": "f", 230 }]`) 231 }) 232 233 ctx := context.Background() 234 _, resp, err := client.Repositories.DownloadContents(ctx, "o", "r", "d/f", nil) 235 if err == nil { 236 t.Errorf("Repositories.DownloadContents did not return expected error") 237 } 238 239 if resp == nil { 240 t.Errorf("Repositories.DownloadContents did not return expected response") 241 } 242 } 243 244 func TestRepositoriesService_DownloadContents_NoFile(t *testing.T) { 245 t.Parallel() 246 client, mux, _ := setup(t) 247 248 mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { 249 testMethod(t, r, "GET") 250 fmt.Fprint(w, `[]`) 251 }) 252 253 ctx := context.Background() 254 _, resp, err := client.Repositories.DownloadContents(ctx, "o", "r", "d/f", nil) 255 if err == nil { 256 t.Errorf("Repositories.DownloadContents did not return expected error") 257 } 258 259 if resp == nil { 260 t.Errorf("Repositories.DownloadContents did not return expected response") 261 } 262 } 263 264 func TestRepositoriesService_DownloadContentsWithMeta_Success(t *testing.T) { 265 t.Parallel() 266 client, mux, serverURL := setup(t) 267 268 mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { 269 testMethod(t, r, "GET") 270 fmt.Fprint(w, `[{ 271 "type": "file", 272 "name": "f", 273 "download_url": "`+serverURL+baseURLPath+`/download/f" 274 }]`) 275 }) 276 mux.HandleFunc("/download/f", func(w http.ResponseWriter, r *http.Request) { 277 testMethod(t, r, "GET") 278 fmt.Fprint(w, "foo") 279 }) 280 281 ctx := context.Background() 282 r, c, resp, err := client.Repositories.DownloadContentsWithMeta(ctx, "o", "r", "d/f", nil) 283 if err != nil { 284 t.Errorf("Repositories.DownloadContentsWithMeta returned error: %v", err) 285 } 286 287 if got, want := resp.Response.StatusCode, http.StatusOK; got != want { 288 t.Errorf("Repositories.DownloadContentsWithMeta returned status code %v, want %v", got, want) 289 } 290 291 bytes, err := io.ReadAll(r) 292 if err != nil { 293 t.Errorf("Error reading response body: %v", err) 294 } 295 r.Close() 296 297 if got, want := string(bytes), "foo"; got != want { 298 t.Errorf("Repositories.DownloadContentsWithMeta returned %v, want %v", got, want) 299 } 300 301 if c != nil && c.Name != nil { 302 if got, want := *c.Name, "f"; got != want { 303 t.Errorf("Repositories.DownloadContentsWithMeta returned content name %v, want %v", got, want) 304 } 305 } else { 306 t.Errorf("Returned RepositoryContent is null") 307 } 308 309 const methodName = "DownloadContentsWithMeta" 310 testBadOptions(t, methodName, func() (err error) { 311 _, _, _, err = client.Repositories.DownloadContentsWithMeta(ctx, "\n", "\n", "\n", nil) 312 return err 313 }) 314 315 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 316 got, cot, resp, err := client.Repositories.DownloadContentsWithMeta(ctx, "o", "r", "d/f", nil) 317 if got != nil { 318 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 319 } 320 if cot != nil { 321 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, cot) 322 } 323 return resp, err 324 }) 325 } 326 327 func TestRepositoriesService_DownloadContentsWithMeta_FailedResponse(t *testing.T) { 328 t.Parallel() 329 client, mux, serverURL := setup(t) 330 331 mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { 332 testMethod(t, r, "GET") 333 fmt.Fprint(w, `[{ 334 "type": "file", 335 "name": "f", 336 "download_url": "`+serverURL+baseURLPath+`/download/f" 337 }]`) 338 }) 339 mux.HandleFunc("/download/f", func(w http.ResponseWriter, r *http.Request) { 340 testMethod(t, r, "GET") 341 w.WriteHeader(http.StatusInternalServerError) 342 fmt.Fprint(w, "foo error") 343 }) 344 345 ctx := context.Background() 346 r, c, resp, err := client.Repositories.DownloadContentsWithMeta(ctx, "o", "r", "d/f", nil) 347 if err != nil { 348 t.Errorf("Repositories.DownloadContentsWithMeta returned error: %v", err) 349 } 350 351 if got, want := resp.Response.StatusCode, http.StatusInternalServerError; got != want { 352 t.Errorf("Repositories.DownloadContentsWithMeta returned status code %v, want %v", got, want) 353 } 354 355 bytes, err := io.ReadAll(r) 356 if err != nil { 357 t.Errorf("Error reading response body: %v", err) 358 } 359 r.Close() 360 361 if got, want := string(bytes), "foo error"; got != want { 362 t.Errorf("Repositories.DownloadContentsWithMeta returned %v, want %v", got, want) 363 } 364 365 if c != nil && c.Name != nil { 366 if got, want := *c.Name, "f"; got != want { 367 t.Errorf("Repositories.DownloadContentsWithMeta returned content name %v, want %v", got, want) 368 } 369 } else { 370 t.Errorf("Returned RepositoryContent is null") 371 } 372 } 373 374 func TestRepositoriesService_DownloadContentsWithMeta_NoDownloadURL(t *testing.T) { 375 t.Parallel() 376 client, mux, _ := setup(t) 377 378 mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { 379 testMethod(t, r, "GET") 380 fmt.Fprint(w, `[{ 381 "type": "file", 382 "name": "f", 383 }]`) 384 }) 385 386 ctx := context.Background() 387 _, _, resp, err := client.Repositories.DownloadContentsWithMeta(ctx, "o", "r", "d/f", nil) 388 if err == nil { 389 t.Errorf("Repositories.DownloadContentsWithMeta did not return expected error") 390 } 391 392 if resp == nil { 393 t.Errorf("Repositories.DownloadContentsWithMeta did not return expected response") 394 } 395 } 396 397 func TestRepositoriesService_DownloadContentsWithMeta_NoFile(t *testing.T) { 398 t.Parallel() 399 client, mux, _ := setup(t) 400 401 mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { 402 testMethod(t, r, "GET") 403 fmt.Fprint(w, `[]`) 404 }) 405 406 ctx := context.Background() 407 _, _, resp, err := client.Repositories.DownloadContentsWithMeta(ctx, "o", "r", "d/f", nil) 408 if err == nil { 409 t.Errorf("Repositories.DownloadContentsWithMeta did not return expected error") 410 } 411 412 if resp == nil { 413 t.Errorf("Repositories.DownloadContentsWithMeta did not return expected response") 414 } 415 } 416 417 func TestRepositoriesService_GetContents_File(t *testing.T) { 418 t.Parallel() 419 client, mux, _ := setup(t) 420 421 mux.HandleFunc("/repos/o/r/contents/p", func(w http.ResponseWriter, r *http.Request) { 422 testMethod(t, r, "GET") 423 fmt.Fprint(w, `{ 424 "type": "file", 425 "encoding": "base64", 426 "size": 20678, 427 "name": "LICENSE", 428 "path": "LICENSE" 429 }`) 430 }) 431 ctx := context.Background() 432 fileContents, _, _, err := client.Repositories.GetContents(ctx, "o", "r", "p", &RepositoryContentGetOptions{}) 433 if err != nil { 434 t.Errorf("Repositories.GetContents returned error: %v", err) 435 } 436 want := &RepositoryContent{Type: Ptr("file"), Name: Ptr("LICENSE"), Size: Ptr(20678), Encoding: Ptr("base64"), Path: Ptr("LICENSE")} 437 if !cmp.Equal(fileContents, want) { 438 t.Errorf("Repositories.GetContents returned %+v, want %+v", fileContents, want) 439 } 440 441 const methodName = "GetContents" 442 testBadOptions(t, methodName, func() (err error) { 443 _, _, _, err = client.Repositories.GetContents(ctx, "\n", "\n", "\n", &RepositoryContentGetOptions{}) 444 return err 445 }) 446 447 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 448 got, _, resp, err := client.Repositories.GetContents(ctx, "o", "r", "p", &RepositoryContentGetOptions{}) 449 if got != nil { 450 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 451 } 452 return resp, err 453 }) 454 } 455 456 func TestRepositoriesService_GetContents_FilenameNeedsEscape(t *testing.T) { 457 t.Parallel() 458 client, mux, _ := setup(t) 459 460 mux.HandleFunc("/repos/o/r/contents/p#?%/中.go", func(w http.ResponseWriter, r *http.Request) { 461 testMethod(t, r, "GET") 462 fmt.Fprint(w, `{}`) 463 }) 464 ctx := context.Background() 465 _, _, _, err := client.Repositories.GetContents(ctx, "o", "r", "p#?%/中.go", &RepositoryContentGetOptions{}) 466 if err != nil { 467 t.Fatalf("Repositories.GetContents returned error: %v", err) 468 } 469 } 470 471 func TestRepositoriesService_GetContents_DirectoryWithSpaces(t *testing.T) { 472 t.Parallel() 473 client, mux, _ := setup(t) 474 475 mux.HandleFunc("/repos/o/r/contents/some%20directory/file.go", func(w http.ResponseWriter, r *http.Request) { 476 testMethod(t, r, "GET") 477 fmt.Fprint(w, `{}`) 478 }) 479 ctx := context.Background() 480 _, _, _, err := client.Repositories.GetContents(ctx, "o", "r", "some directory/file.go", &RepositoryContentGetOptions{}) 481 if err != nil { 482 t.Fatalf("Repositories.GetContents returned error: %v", err) 483 } 484 } 485 486 func TestRepositoriesService_GetContents_PathWithParent(t *testing.T) { 487 t.Parallel() 488 client, mux, _ := setup(t) 489 490 mux.HandleFunc("/repos/o/r/contents/some/../directory/file.go", func(w http.ResponseWriter, r *http.Request) { 491 testMethod(t, r, "GET") 492 fmt.Fprint(w, `{}`) 493 }) 494 ctx := context.Background() 495 _, _, _, err := client.Repositories.GetContents(ctx, "o", "r", "some/../directory/file.go", &RepositoryContentGetOptions{}) 496 if err == nil { 497 t.Fatal("Repositories.GetContents expected error but got none") 498 } 499 } 500 501 func TestRepositoriesService_GetContents_DirectoryWithPlusChars(t *testing.T) { 502 t.Parallel() 503 client, mux, _ := setup(t) 504 505 mux.HandleFunc("/repos/o/r/contents/some%20directory%2Bname/file.go", func(w http.ResponseWriter, r *http.Request) { 506 testMethod(t, r, "GET") 507 fmt.Fprint(w, `{}`) 508 }) 509 ctx := context.Background() 510 _, _, _, err := client.Repositories.GetContents(ctx, "o", "r", "some directory+name/file.go", &RepositoryContentGetOptions{}) 511 if err != nil { 512 t.Fatalf("Repositories.GetContents returned error: %v", err) 513 } 514 } 515 516 func TestRepositoriesService_GetContents_Directory(t *testing.T) { 517 t.Parallel() 518 client, mux, _ := setup(t) 519 520 mux.HandleFunc("/repos/o/r/contents/p", func(w http.ResponseWriter, r *http.Request) { 521 testMethod(t, r, "GET") 522 fmt.Fprint(w, `[{ 523 "type": "dir", 524 "name": "lib", 525 "path": "lib" 526 }, 527 { 528 "type": "file", 529 "size": 20678, 530 "name": "LICENSE", 531 "path": "LICENSE" 532 }]`) 533 }) 534 ctx := context.Background() 535 _, directoryContents, _, err := client.Repositories.GetContents(ctx, "o", "r", "p", &RepositoryContentGetOptions{}) 536 if err != nil { 537 t.Errorf("Repositories.GetContents returned error: %v", err) 538 } 539 want := []*RepositoryContent{{Type: Ptr("dir"), Name: Ptr("lib"), Path: Ptr("lib")}, 540 {Type: Ptr("file"), Name: Ptr("LICENSE"), Size: Ptr(20678), Path: Ptr("LICENSE")}} 541 if !cmp.Equal(directoryContents, want) { 542 t.Errorf("Repositories.GetContents_Directory returned %+v, want %+v", directoryContents, want) 543 } 544 } 545 546 func TestRepositoriesService_CreateFile(t *testing.T) { 547 t.Parallel() 548 client, mux, _ := setup(t) 549 550 mux.HandleFunc("/repos/o/r/contents/p", func(w http.ResponseWriter, r *http.Request) { 551 testMethod(t, r, "PUT") 552 fmt.Fprint(w, `{ 553 "content":{ 554 "name":"p" 555 }, 556 "commit":{ 557 "message":"m", 558 "sha":"f5f369044773ff9c6383c087466d12adb6fa0828" 559 } 560 }`) 561 }) 562 message := "m" 563 content := []byte("c") 564 repositoryContentsOptions := &RepositoryContentFileOptions{ 565 Message: &message, 566 Content: content, 567 Committer: &CommitAuthor{Name: Ptr("n"), Email: Ptr("e")}, 568 } 569 ctx := context.Background() 570 createResponse, _, err := client.Repositories.CreateFile(ctx, "o", "r", "p", repositoryContentsOptions) 571 if err != nil { 572 t.Errorf("Repositories.CreateFile returned error: %v", err) 573 } 574 want := &RepositoryContentResponse{ 575 Content: &RepositoryContent{Name: Ptr("p")}, 576 Commit: Commit{ 577 Message: Ptr("m"), 578 SHA: Ptr("f5f369044773ff9c6383c087466d12adb6fa0828"), 579 }, 580 } 581 if !cmp.Equal(createResponse, want) { 582 t.Errorf("Repositories.CreateFile returned %+v, want %+v", createResponse, want) 583 } 584 585 const methodName = "CreateFile" 586 testBadOptions(t, methodName, func() (err error) { 587 _, _, err = client.Repositories.CreateFile(ctx, "\n", "\n", "\n", repositoryContentsOptions) 588 return err 589 }) 590 591 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 592 got, resp, err := client.Repositories.CreateFile(ctx, "o", "r", "p", repositoryContentsOptions) 593 if got != nil { 594 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 595 } 596 return resp, err 597 }) 598 } 599 600 func TestRepositoriesService_UpdateFile(t *testing.T) { 601 t.Parallel() 602 client, mux, _ := setup(t) 603 604 mux.HandleFunc("/repos/o/r/contents/p", func(w http.ResponseWriter, r *http.Request) { 605 testMethod(t, r, "PUT") 606 fmt.Fprint(w, `{ 607 "content":{ 608 "name":"p" 609 }, 610 "commit":{ 611 "message":"m", 612 "sha":"f5f369044773ff9c6383c087466d12adb6fa0828" 613 } 614 }`) 615 }) 616 message := "m" 617 content := []byte("c") 618 sha := "f5f369044773ff9c6383c087466d12adb6fa0828" 619 repositoryContentsOptions := &RepositoryContentFileOptions{ 620 Message: &message, 621 Content: content, 622 SHA: &sha, 623 Committer: &CommitAuthor{Name: Ptr("n"), Email: Ptr("e")}, 624 } 625 ctx := context.Background() 626 updateResponse, _, err := client.Repositories.UpdateFile(ctx, "o", "r", "p", repositoryContentsOptions) 627 if err != nil { 628 t.Errorf("Repositories.UpdateFile returned error: %v", err) 629 } 630 want := &RepositoryContentResponse{ 631 Content: &RepositoryContent{Name: Ptr("p")}, 632 Commit: Commit{ 633 Message: Ptr("m"), 634 SHA: Ptr("f5f369044773ff9c6383c087466d12adb6fa0828"), 635 }, 636 } 637 if !cmp.Equal(updateResponse, want) { 638 t.Errorf("Repositories.UpdateFile returned %+v, want %+v", updateResponse, want) 639 } 640 641 const methodName = "UpdateFile" 642 testBadOptions(t, methodName, func() (err error) { 643 _, _, err = client.Repositories.UpdateFile(ctx, "\n", "\n", "\n", repositoryContentsOptions) 644 return err 645 }) 646 647 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 648 got, resp, err := client.Repositories.UpdateFile(ctx, "o", "r", "p", repositoryContentsOptions) 649 if got != nil { 650 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 651 } 652 return resp, err 653 }) 654 } 655 656 func TestRepositoriesService_DeleteFile(t *testing.T) { 657 t.Parallel() 658 client, mux, _ := setup(t) 659 660 mux.HandleFunc("/repos/o/r/contents/p", func(w http.ResponseWriter, r *http.Request) { 661 testMethod(t, r, "DELETE") 662 fmt.Fprint(w, `{ 663 "content": null, 664 "commit":{ 665 "message":"m", 666 "sha":"f5f369044773ff9c6383c087466d12adb6fa0828" 667 } 668 }`) 669 }) 670 message := "m" 671 sha := "f5f369044773ff9c6383c087466d12adb6fa0828" 672 repositoryContentsOptions := &RepositoryContentFileOptions{ 673 Message: &message, 674 SHA: &sha, 675 Committer: &CommitAuthor{Name: Ptr("n"), Email: Ptr("e")}, 676 } 677 ctx := context.Background() 678 deleteResponse, _, err := client.Repositories.DeleteFile(ctx, "o", "r", "p", repositoryContentsOptions) 679 if err != nil { 680 t.Errorf("Repositories.DeleteFile returned error: %v", err) 681 } 682 want := &RepositoryContentResponse{ 683 Content: nil, 684 Commit: Commit{ 685 Message: Ptr("m"), 686 SHA: Ptr("f5f369044773ff9c6383c087466d12adb6fa0828"), 687 }, 688 } 689 if !cmp.Equal(deleteResponse, want) { 690 t.Errorf("Repositories.DeleteFile returned %+v, want %+v", deleteResponse, want) 691 } 692 693 const methodName = "DeleteFile" 694 testBadOptions(t, methodName, func() (err error) { 695 _, _, err = client.Repositories.DeleteFile(ctx, "\n", "\n", "\n", repositoryContentsOptions) 696 return err 697 }) 698 699 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 700 got, resp, err := client.Repositories.DeleteFile(ctx, "o", "r", "p", repositoryContentsOptions) 701 if got != nil { 702 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 703 } 704 return resp, err 705 }) 706 } 707 708 func TestRepositoriesService_GetArchiveLink(t *testing.T) { 709 t.Parallel() 710 tcs := []struct { 711 name string 712 respectRateLimits bool 713 }{ 714 { 715 name: "withoutRateLimits", 716 respectRateLimits: false, 717 }, 718 { 719 name: "withRateLimits", 720 respectRateLimits: true, 721 }, 722 } 723 724 for _, tc := range tcs { 725 t.Run(tc.name, func(t *testing.T) { 726 t.Parallel() 727 client, mux, _ := setup(t) 728 client.RateLimitRedirectionalEndpoints = tc.respectRateLimits 729 730 mux.HandleFunc("/repos/o/r/tarball/yo", func(w http.ResponseWriter, r *http.Request) { 731 testMethod(t, r, "GET") 732 http.Redirect(w, r, "http://github.com/a", http.StatusFound) 733 }) 734 ctx := context.Background() 735 url, resp, err := client.Repositories.GetArchiveLink(ctx, "o", "r", Tarball, &RepositoryContentGetOptions{Ref: "yo"}, 1) 736 if err != nil { 737 t.Errorf("Repositories.GetArchiveLink returned error: %v", err) 738 } 739 if resp.StatusCode != http.StatusFound { 740 t.Errorf("Repositories.GetArchiveLink returned status: %d, want %d", resp.StatusCode, http.StatusFound) 741 } 742 want := "http://github.com/a" 743 if url.String() != want { 744 t.Errorf("Repositories.GetArchiveLink returned %+v, want %+v", url.String(), want) 745 } 746 747 const methodName = "GetArchiveLink" 748 testBadOptions(t, methodName, func() (err error) { 749 _, _, err = client.Repositories.GetArchiveLink(ctx, "\n", "\n", Tarball, &RepositoryContentGetOptions{}, 1) 750 return err 751 }) 752 753 // Add custom round tripper 754 client.client.Transport = roundTripperFunc(func(r *http.Request) (*http.Response, error) { 755 return nil, errors.New("failed to get archive link") 756 }) 757 testBadOptions(t, methodName, func() (err error) { 758 _, _, err = client.Repositories.GetArchiveLink(ctx, "o", "r", Tarball, &RepositoryContentGetOptions{}, 1) 759 return err 760 }) 761 }) 762 } 763 } 764 765 func TestRepositoriesService_GetArchiveLink_StatusMovedPermanently_dontFollowRedirects(t *testing.T) { 766 t.Parallel() 767 tcs := []struct { 768 name string 769 respectRateLimits bool 770 }{ 771 { 772 name: "withoutRateLimits", 773 respectRateLimits: false, 774 }, 775 { 776 name: "withRateLimits", 777 respectRateLimits: true, 778 }, 779 } 780 781 for _, tc := range tcs { 782 t.Run(tc.name, func(t *testing.T) { 783 t.Parallel() 784 client, mux, _ := setup(t) 785 client.RateLimitRedirectionalEndpoints = tc.respectRateLimits 786 787 mux.HandleFunc("/repos/o/r/tarball", func(w http.ResponseWriter, r *http.Request) { 788 testMethod(t, r, "GET") 789 http.Redirect(w, r, "http://github.com/a", http.StatusMovedPermanently) 790 }) 791 ctx := context.Background() 792 _, resp, _ := client.Repositories.GetArchiveLink(ctx, "o", "r", Tarball, &RepositoryContentGetOptions{}, 0) 793 if resp.StatusCode != http.StatusMovedPermanently { 794 t.Errorf("Repositories.GetArchiveLink returned status: %d, want %d", resp.StatusCode, http.StatusMovedPermanently) 795 } 796 }) 797 } 798 } 799 800 func TestRepositoriesService_GetArchiveLink_StatusMovedPermanently_followRedirects(t *testing.T) { 801 t.Parallel() 802 tcs := []struct { 803 name string 804 respectRateLimits bool 805 }{ 806 { 807 name: "withoutRateLimits", 808 respectRateLimits: false, 809 }, 810 { 811 name: "withRateLimits", 812 respectRateLimits: true, 813 }, 814 } 815 816 for _, tc := range tcs { 817 t.Run(tc.name, func(t *testing.T) { 818 t.Parallel() 819 client, mux, serverURL := setup(t) 820 client.RateLimitRedirectionalEndpoints = tc.respectRateLimits 821 822 // Mock a redirect link, which leads to an archive link 823 mux.HandleFunc("/repos/o/r/tarball", func(w http.ResponseWriter, r *http.Request) { 824 testMethod(t, r, "GET") 825 redirectURL, _ := url.Parse(serverURL + baseURLPath + "/redirect") 826 http.Redirect(w, r, redirectURL.String(), http.StatusMovedPermanently) 827 }) 828 mux.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) { 829 testMethod(t, r, "GET") 830 http.Redirect(w, r, "http://github.com/a", http.StatusFound) 831 }) 832 ctx := context.Background() 833 url, resp, err := client.Repositories.GetArchiveLink(ctx, "o", "r", Tarball, &RepositoryContentGetOptions{}, 1) 834 if err != nil { 835 t.Errorf("Repositories.GetArchiveLink returned error: %v", err) 836 } 837 if resp.StatusCode != http.StatusFound { 838 t.Errorf("Repositories.GetArchiveLink returned status: %d, want %d", resp.StatusCode, http.StatusFound) 839 } 840 want := "http://github.com/a" 841 if url.String() != want { 842 t.Errorf("Repositories.GetArchiveLink returned %+v, want %+v", url.String(), want) 843 } 844 }) 845 } 846 } 847 848 func TestRepositoriesService_GetContents_NoTrailingSlashInDirectoryApiPath(t *testing.T) { 849 t.Parallel() 850 client, mux, _ := setup(t) 851 852 mux.HandleFunc("/repos/o/r/contents/.github", func(w http.ResponseWriter, r *http.Request) { 853 testMethod(t, r, "GET") 854 query := r.URL.Query() 855 if query.Get("ref") != "mybranch" { 856 t.Errorf("Repositories.GetContents returned %+v, want %+v", query.Get("ref"), "mybranch") 857 } 858 fmt.Fprint(w, `{}`) 859 }) 860 ctx := context.Background() 861 _, _, _, err := client.Repositories.GetContents(ctx, "o", "r", ".github/", &RepositoryContentGetOptions{ 862 Ref: "mybranch", 863 }) 864 if err != nil { 865 t.Fatalf("Repositories.GetContents returned error: %v", err) 866 } 867 } 868 869 func TestRepositoryContent_Marshal(t *testing.T) { 870 t.Parallel() 871 testJSONMarshal(t, &RepositoryContent{}, "{}") 872 873 r := &RepositoryContent{ 874 Type: Ptr("type"), 875 Target: Ptr("target"), 876 Encoding: Ptr("encoding"), 877 Size: Ptr(1), 878 Name: Ptr("name"), 879 Path: Ptr("path"), 880 Content: Ptr("content"), 881 SHA: Ptr("sha"), 882 URL: Ptr("url"), 883 GitURL: Ptr("gurl"), 884 HTMLURL: Ptr("hurl"), 885 DownloadURL: Ptr("durl"), 886 SubmoduleGitURL: Ptr("smgurl"), 887 } 888 889 want := `{ 890 "type": "type", 891 "target": "target", 892 "encoding": "encoding", 893 "size": 1, 894 "name": "name", 895 "path": "path", 896 "content": "content", 897 "sha": "sha", 898 "url": "url", 899 "git_url": "gurl", 900 "html_url": "hurl", 901 "download_url": "durl", 902 "submodule_git_url": "smgurl" 903 }` 904 905 testJSONMarshal(t, r, want) 906 } 907 908 func TestRepositoryContentResponse_Marshal(t *testing.T) { 909 t.Parallel() 910 testJSONMarshal(t, &RepositoryContentResponse{}, "{}") 911 912 r := &RepositoryContentResponse{ 913 Content: &RepositoryContent{ 914 Type: Ptr("type"), 915 Target: Ptr("target"), 916 Encoding: Ptr("encoding"), 917 Size: Ptr(1), 918 Name: Ptr("name"), 919 Path: Ptr("path"), 920 Content: Ptr("content"), 921 SHA: Ptr("sha"), 922 URL: Ptr("url"), 923 GitURL: Ptr("gurl"), 924 HTMLURL: Ptr("hurl"), 925 DownloadURL: Ptr("durl"), 926 SubmoduleGitURL: Ptr("smgurl"), 927 }, 928 Commit: Commit{ 929 SHA: Ptr("s"), 930 Author: &CommitAuthor{ 931 Date: &Timestamp{referenceTime}, 932 Name: Ptr("n"), 933 Email: Ptr("e"), 934 Login: Ptr("u"), 935 }, 936 Committer: &CommitAuthor{ 937 Date: &Timestamp{referenceTime}, 938 Name: Ptr("n"), 939 Email: Ptr("e"), 940 Login: Ptr("u"), 941 }, 942 Message: Ptr("m"), 943 Tree: &Tree{ 944 SHA: Ptr("s"), 945 Entries: []*TreeEntry{{ 946 SHA: Ptr("s"), 947 Path: Ptr("p"), 948 Mode: Ptr("m"), 949 Type: Ptr("t"), 950 Size: Ptr(1), 951 Content: Ptr("c"), 952 URL: Ptr("u"), 953 }}, 954 Truncated: Ptr(false), 955 }, 956 Parents: nil, 957 HTMLURL: Ptr("h"), 958 URL: Ptr("u"), 959 Verification: &SignatureVerification{ 960 Verified: Ptr(false), 961 Reason: Ptr("r"), 962 Signature: Ptr("s"), 963 Payload: Ptr("p"), 964 }, 965 NodeID: Ptr("n"), 966 CommentCount: Ptr(1), 967 }, 968 } 969 970 want := `{ 971 "content": { 972 "type": "type", 973 "target": "target", 974 "encoding": "encoding", 975 "size": 1, 976 "name": "name", 977 "path": "path", 978 "content": "content", 979 "sha": "sha", 980 "url": "url", 981 "git_url": "gurl", 982 "html_url": "hurl", 983 "download_url": "durl", 984 "submodule_git_url": "smgurl" 985 }, 986 "commit": { 987 "sha": "s", 988 "author": { 989 "date": ` + referenceTimeStr + `, 990 "name": "n", 991 "email": "e", 992 "username": "u" 993 }, 994 "committer": { 995 "date": ` + referenceTimeStr + `, 996 "name": "n", 997 "email": "e", 998 "username": "u" 999 }, 1000 "message": "m", 1001 "tree": { 1002 "sha": "s", 1003 "tree": [ 1004 { 1005 "sha": "s", 1006 "path": "p", 1007 "mode": "m", 1008 "type": "t", 1009 "size": 1, 1010 "content": "c", 1011 "url": "u" 1012 } 1013 ], 1014 "truncated": false 1015 }, 1016 "html_url": "h", 1017 "url": "u", 1018 "verification": { 1019 "verified": false, 1020 "reason": "r", 1021 "signature": "s", 1022 "payload": "p" 1023 }, 1024 "node_id": "n", 1025 "comment_count": 1 1026 } 1027 }` 1028 1029 testJSONMarshal(t, r, want) 1030 } 1031 1032 func TestRepositoryContentFileOptions_Marshal(t *testing.T) { 1033 t.Parallel() 1034 testJSONMarshal(t, &RepositoryContentFileOptions{}, "{}") 1035 1036 r := &RepositoryContentFileOptions{ 1037 Message: Ptr("type"), 1038 Content: []byte{1}, 1039 SHA: Ptr("type"), 1040 Branch: Ptr("type"), 1041 Author: &CommitAuthor{ 1042 Date: &Timestamp{referenceTime}, 1043 Name: Ptr("name"), 1044 Email: Ptr("email"), 1045 Login: Ptr("login"), 1046 }, 1047 Committer: &CommitAuthor{ 1048 Date: &Timestamp{referenceTime}, 1049 Name: Ptr("name"), 1050 Email: Ptr("email"), 1051 Login: Ptr("login"), 1052 }, 1053 } 1054 1055 want := `{ 1056 "message": "type", 1057 "content": "AQ==", 1058 "sha": "type", 1059 "branch": "type", 1060 "author": { 1061 "date": ` + referenceTimeStr + `, 1062 "name": "name", 1063 "email": "email", 1064 "username": "login" 1065 }, 1066 "committer": { 1067 "date": ` + referenceTimeStr + `, 1068 "name": "name", 1069 "email": "email", 1070 "username": "login" 1071 } 1072 }` 1073 1074 testJSONMarshal(t, r, want) 1075 }