github.com/google/go-github/v33@v33.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 "fmt" 11 "io/ioutil" 12 "net/http" 13 "net/url" 14 "reflect" 15 "testing" 16 ) 17 18 func TestRepositoryContent_GetContent(t *testing.T) { 19 tests := []struct { 20 encoding, content *string // input encoding and content 21 want string // desired output 22 wantErr bool // whether an error is expected 23 }{ 24 { 25 encoding: String(""), 26 content: String("hello"), 27 want: "hello", 28 wantErr: false, 29 }, 30 { 31 encoding: nil, 32 content: String("hello"), 33 want: "hello", 34 wantErr: false, 35 }, 36 { 37 encoding: nil, 38 content: nil, 39 want: "", 40 wantErr: false, 41 }, 42 { 43 encoding: String("base64"), 44 content: String("aGVsbG8="), 45 want: "hello", 46 wantErr: false, 47 }, 48 { 49 encoding: String("bad"), 50 content: String("aGVsbG8="), 51 want: "", 52 wantErr: true, 53 }, 54 } 55 56 for _, tt := range tests { 57 r := RepositoryContent{Encoding: tt.encoding, Content: tt.content} 58 got, err := r.GetContent() 59 if err != nil && !tt.wantErr { 60 t.Errorf("RepositoryContent(%s, %s) returned unexpected error: %v", 61 stringOrNil(tt.encoding), stringOrNil(tt.content), err) 62 } 63 if err == nil && tt.wantErr { 64 t.Errorf("RepositoryContent(%s, %s) did not return unexpected error", 65 stringOrNil(tt.encoding), stringOrNil(tt.content)) 66 } 67 if want := tt.want; got != want { 68 t.Errorf("RepositoryContent.GetContent returned %+v, want %+v", got, want) 69 } 70 } 71 } 72 73 // stringOrNil converts a potentially null string pointer to string. 74 // For non-nil input pointer, the returned string is enclosed in double-quotes. 75 func stringOrNil(s *string) string { 76 if s == nil { 77 return "<nil>" 78 } 79 return fmt.Sprintf("%q", *s) 80 } 81 82 func TestRepositoriesService_GetReadme(t *testing.T) { 83 client, mux, _, teardown := setup() 84 defer teardown() 85 mux.HandleFunc("/repos/o/r/readme", func(w http.ResponseWriter, r *http.Request) { 86 testMethod(t, r, "GET") 87 fmt.Fprint(w, `{ 88 "type": "file", 89 "encoding": "base64", 90 "size": 5362, 91 "name": "README.md", 92 "path": "README.md" 93 }`) 94 }) 95 readme, _, err := client.Repositories.GetReadme(context.Background(), "o", "r", &RepositoryContentGetOptions{}) 96 if err != nil { 97 t.Errorf("Repositories.GetReadme returned error: %v", err) 98 } 99 want := &RepositoryContent{Type: String("file"), Name: String("README.md"), Size: Int(5362), Encoding: String("base64"), Path: String("README.md")} 100 if !reflect.DeepEqual(readme, want) { 101 t.Errorf("Repositories.GetReadme returned %+v, want %+v", readme, want) 102 } 103 } 104 105 func TestRepositoriesService_DownloadContents_Success(t *testing.T) { 106 client, mux, serverURL, teardown := setup() 107 defer teardown() 108 mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { 109 testMethod(t, r, "GET") 110 fmt.Fprint(w, `[{ 111 "type": "file", 112 "name": "f", 113 "download_url": "`+serverURL+baseURLPath+`/download/f" 114 }]`) 115 }) 116 mux.HandleFunc("/download/f", func(w http.ResponseWriter, r *http.Request) { 117 testMethod(t, r, "GET") 118 fmt.Fprint(w, "foo") 119 }) 120 121 r, resp, err := client.Repositories.DownloadContents(context.Background(), "o", "r", "d/f", nil) 122 if err != nil { 123 t.Errorf("Repositories.DownloadContents returned error: %v", err) 124 } 125 126 if got, want := resp.Response.StatusCode, http.StatusOK; got != want { 127 t.Errorf("Repositories.DownloadContents returned status code %v, want %v", got, want) 128 } 129 130 bytes, err := ioutil.ReadAll(r) 131 if err != nil { 132 t.Errorf("Error reading response body: %v", err) 133 } 134 r.Close() 135 136 if got, want := string(bytes), "foo"; got != want { 137 t.Errorf("Repositories.DownloadContents returned %v, want %v", got, want) 138 } 139 } 140 141 func TestRepositoriesService_DownloadContents_FailedResponse(t *testing.T) { 142 client, mux, serverURL, teardown := setup() 143 defer teardown() 144 mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { 145 testMethod(t, r, "GET") 146 fmt.Fprint(w, `[{ 147 "type": "file", 148 "name": "f", 149 "download_url": "`+serverURL+baseURLPath+`/download/f" 150 }]`) 151 }) 152 mux.HandleFunc("/download/f", func(w http.ResponseWriter, r *http.Request) { 153 testMethod(t, r, "GET") 154 w.WriteHeader(http.StatusInternalServerError) 155 fmt.Fprint(w, "foo error") 156 }) 157 158 r, resp, err := client.Repositories.DownloadContents(context.Background(), "o", "r", "d/f", nil) 159 if err != nil { 160 t.Errorf("Repositories.DownloadContents returned error: %v", err) 161 } 162 163 if got, want := resp.Response.StatusCode, http.StatusInternalServerError; got != want { 164 t.Errorf("Repositories.DownloadContents returned status code %v, want %v", got, want) 165 } 166 167 bytes, err := ioutil.ReadAll(r) 168 if err != nil { 169 t.Errorf("Error reading response body: %v", err) 170 } 171 r.Close() 172 173 if got, want := string(bytes), "foo error"; got != want { 174 t.Errorf("Repositories.DownloadContents returned %v, want %v", got, want) 175 } 176 } 177 178 func TestRepositoriesService_DownloadContents_NoDownloadURL(t *testing.T) { 179 client, mux, _, teardown := setup() 180 defer teardown() 181 mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { 182 testMethod(t, r, "GET") 183 fmt.Fprint(w, `[{ 184 "type": "file", 185 "name": "f", 186 }]`) 187 }) 188 189 _, resp, err := client.Repositories.DownloadContents(context.Background(), "o", "r", "d/f", nil) 190 if err == nil { 191 t.Errorf("Repositories.DownloadContents did not return expected error") 192 } 193 194 if resp == nil { 195 t.Errorf("Repositories.DownloadContents did not return expected response") 196 } 197 } 198 199 func TestRepositoriesService_DownloadContents_NoFile(t *testing.T) { 200 client, mux, _, teardown := setup() 201 defer teardown() 202 mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { 203 testMethod(t, r, "GET") 204 fmt.Fprint(w, `[]`) 205 }) 206 207 _, resp, err := client.Repositories.DownloadContents(context.Background(), "o", "r", "d/f", nil) 208 if err == nil { 209 t.Errorf("Repositories.DownloadContents did not return expected error") 210 } 211 212 if resp == nil { 213 t.Errorf("Repositories.DownloadContents did not return expected response") 214 } 215 } 216 217 func TestRepositoriesService_GetContents_File(t *testing.T) { 218 client, mux, _, teardown := setup() 219 defer teardown() 220 mux.HandleFunc("/repos/o/r/contents/p", func(w http.ResponseWriter, r *http.Request) { 221 testMethod(t, r, "GET") 222 fmt.Fprint(w, `{ 223 "type": "file", 224 "encoding": "base64", 225 "size": 20678, 226 "name": "LICENSE", 227 "path": "LICENSE" 228 }`) 229 }) 230 fileContents, _, _, err := client.Repositories.GetContents(context.Background(), "o", "r", "p", &RepositoryContentGetOptions{}) 231 if err != nil { 232 t.Errorf("Repositories.GetContents returned error: %v", err) 233 } 234 want := &RepositoryContent{Type: String("file"), Name: String("LICENSE"), Size: Int(20678), Encoding: String("base64"), Path: String("LICENSE")} 235 if !reflect.DeepEqual(fileContents, want) { 236 t.Errorf("Repositories.GetContents returned %+v, want %+v", fileContents, want) 237 } 238 } 239 240 func TestRepositoriesService_GetContents_FilenameNeedsEscape(t *testing.T) { 241 client, mux, _, teardown := setup() 242 defer teardown() 243 mux.HandleFunc("/repos/o/r/contents/p#?%/中.go", func(w http.ResponseWriter, r *http.Request) { 244 testMethod(t, r, "GET") 245 fmt.Fprint(w, `{}`) 246 }) 247 _, _, _, err := client.Repositories.GetContents(context.Background(), "o", "r", "p#?%/中.go", &RepositoryContentGetOptions{}) 248 if err != nil { 249 t.Fatalf("Repositories.GetContents returned error: %v", err) 250 } 251 } 252 253 func TestRepositoriesService_GetContents_DirectoryWithSpaces(t *testing.T) { 254 client, mux, _, teardown := setup() 255 defer teardown() 256 mux.HandleFunc("/repos/o/r/contents/some directory/file.go", func(w http.ResponseWriter, r *http.Request) { 257 testMethod(t, r, "GET") 258 fmt.Fprint(w, `{}`) 259 }) 260 _, _, _, err := client.Repositories.GetContents(context.Background(), "o", "r", "some directory/file.go", &RepositoryContentGetOptions{}) 261 if err != nil { 262 t.Fatalf("Repositories.GetContents returned error: %v", err) 263 } 264 } 265 266 func TestRepositoriesService_GetContents_DirectoryWithPlusChars(t *testing.T) { 267 client, mux, _, teardown := setup() 268 defer teardown() 269 mux.HandleFunc("/repos/o/r/contents/some directory+name/file.go", func(w http.ResponseWriter, r *http.Request) { 270 testMethod(t, r, "GET") 271 fmt.Fprint(w, `{}`) 272 }) 273 _, _, _, err := client.Repositories.GetContents(context.Background(), "o", "r", "some directory+name/file.go", &RepositoryContentGetOptions{}) 274 if err != nil { 275 t.Fatalf("Repositories.GetContents returned error: %v", err) 276 } 277 } 278 279 func TestRepositoriesService_GetContents_Directory(t *testing.T) { 280 client, mux, _, teardown := setup() 281 defer teardown() 282 mux.HandleFunc("/repos/o/r/contents/p", func(w http.ResponseWriter, r *http.Request) { 283 testMethod(t, r, "GET") 284 fmt.Fprint(w, `[{ 285 "type": "dir", 286 "name": "lib", 287 "path": "lib" 288 }, 289 { 290 "type": "file", 291 "size": 20678, 292 "name": "LICENSE", 293 "path": "LICENSE" 294 }]`) 295 }) 296 _, directoryContents, _, err := client.Repositories.GetContents(context.Background(), "o", "r", "p", &RepositoryContentGetOptions{}) 297 if err != nil { 298 t.Errorf("Repositories.GetContents returned error: %v", err) 299 } 300 want := []*RepositoryContent{{Type: String("dir"), Name: String("lib"), Path: String("lib")}, 301 {Type: String("file"), Name: String("LICENSE"), Size: Int(20678), Path: String("LICENSE")}} 302 if !reflect.DeepEqual(directoryContents, want) { 303 t.Errorf("Repositories.GetContents_Directory returned %+v, want %+v", directoryContents, want) 304 } 305 } 306 307 func TestRepositoriesService_CreateFile(t *testing.T) { 308 client, mux, _, teardown := setup() 309 defer teardown() 310 mux.HandleFunc("/repos/o/r/contents/p", func(w http.ResponseWriter, r *http.Request) { 311 testMethod(t, r, "PUT") 312 fmt.Fprint(w, `{ 313 "content":{ 314 "name":"p" 315 }, 316 "commit":{ 317 "message":"m", 318 "sha":"f5f369044773ff9c6383c087466d12adb6fa0828" 319 } 320 }`) 321 }) 322 message := "m" 323 content := []byte("c") 324 repositoryContentsOptions := &RepositoryContentFileOptions{ 325 Message: &message, 326 Content: content, 327 Committer: &CommitAuthor{Name: String("n"), Email: String("e")}, 328 } 329 createResponse, _, err := client.Repositories.CreateFile(context.Background(), "o", "r", "p", repositoryContentsOptions) 330 if err != nil { 331 t.Errorf("Repositories.CreateFile returned error: %v", err) 332 } 333 want := &RepositoryContentResponse{ 334 Content: &RepositoryContent{Name: String("p")}, 335 Commit: Commit{ 336 Message: String("m"), 337 SHA: String("f5f369044773ff9c6383c087466d12adb6fa0828"), 338 }, 339 } 340 if !reflect.DeepEqual(createResponse, want) { 341 t.Errorf("Repositories.CreateFile returned %+v, want %+v", createResponse, want) 342 } 343 } 344 345 func TestRepositoriesService_UpdateFile(t *testing.T) { 346 client, mux, _, teardown := setup() 347 defer teardown() 348 mux.HandleFunc("/repos/o/r/contents/p", func(w http.ResponseWriter, r *http.Request) { 349 testMethod(t, r, "PUT") 350 fmt.Fprint(w, `{ 351 "content":{ 352 "name":"p" 353 }, 354 "commit":{ 355 "message":"m", 356 "sha":"f5f369044773ff9c6383c087466d12adb6fa0828" 357 } 358 }`) 359 }) 360 message := "m" 361 content := []byte("c") 362 sha := "f5f369044773ff9c6383c087466d12adb6fa0828" 363 repositoryContentsOptions := &RepositoryContentFileOptions{ 364 Message: &message, 365 Content: content, 366 SHA: &sha, 367 Committer: &CommitAuthor{Name: String("n"), Email: String("e")}, 368 } 369 updateResponse, _, err := client.Repositories.UpdateFile(context.Background(), "o", "r", "p", repositoryContentsOptions) 370 if err != nil { 371 t.Errorf("Repositories.UpdateFile returned error: %v", err) 372 } 373 want := &RepositoryContentResponse{ 374 Content: &RepositoryContent{Name: String("p")}, 375 Commit: Commit{ 376 Message: String("m"), 377 SHA: String("f5f369044773ff9c6383c087466d12adb6fa0828"), 378 }, 379 } 380 if !reflect.DeepEqual(updateResponse, want) { 381 t.Errorf("Repositories.UpdateFile returned %+v, want %+v", updateResponse, want) 382 } 383 } 384 385 func TestRepositoriesService_DeleteFile(t *testing.T) { 386 client, mux, _, teardown := setup() 387 defer teardown() 388 mux.HandleFunc("/repos/o/r/contents/p", func(w http.ResponseWriter, r *http.Request) { 389 testMethod(t, r, "DELETE") 390 fmt.Fprint(w, `{ 391 "content": null, 392 "commit":{ 393 "message":"m", 394 "sha":"f5f369044773ff9c6383c087466d12adb6fa0828" 395 } 396 }`) 397 }) 398 message := "m" 399 sha := "f5f369044773ff9c6383c087466d12adb6fa0828" 400 repositoryContentsOptions := &RepositoryContentFileOptions{ 401 Message: &message, 402 SHA: &sha, 403 Committer: &CommitAuthor{Name: String("n"), Email: String("e")}, 404 } 405 deleteResponse, _, err := client.Repositories.DeleteFile(context.Background(), "o", "r", "p", repositoryContentsOptions) 406 if err != nil { 407 t.Errorf("Repositories.DeleteFile returned error: %v", err) 408 } 409 want := &RepositoryContentResponse{ 410 Content: nil, 411 Commit: Commit{ 412 Message: String("m"), 413 SHA: String("f5f369044773ff9c6383c087466d12adb6fa0828"), 414 }, 415 } 416 if !reflect.DeepEqual(deleteResponse, want) { 417 t.Errorf("Repositories.DeleteFile returned %+v, want %+v", deleteResponse, want) 418 } 419 } 420 421 func TestRepositoriesService_GetArchiveLink(t *testing.T) { 422 client, mux, _, teardown := setup() 423 defer teardown() 424 mux.HandleFunc("/repos/o/r/tarball", func(w http.ResponseWriter, r *http.Request) { 425 testMethod(t, r, "GET") 426 http.Redirect(w, r, "http://github.com/a", http.StatusFound) 427 }) 428 url, resp, err := client.Repositories.GetArchiveLink(context.Background(), "o", "r", Tarball, &RepositoryContentGetOptions{}, true) 429 if err != nil { 430 t.Errorf("Repositories.GetArchiveLink returned error: %v", err) 431 } 432 if resp.StatusCode != http.StatusFound { 433 t.Errorf("Repositories.GetArchiveLink returned status: %d, want %d", resp.StatusCode, http.StatusFound) 434 } 435 want := "http://github.com/a" 436 if url.String() != want { 437 t.Errorf("Repositories.GetArchiveLink returned %+v, want %+v", url.String(), want) 438 } 439 } 440 441 func TestRepositoriesService_GetArchiveLink_StatusMovedPermanently_dontFollowRedirects(t *testing.T) { 442 client, mux, _, teardown := setup() 443 defer teardown() 444 mux.HandleFunc("/repos/o/r/tarball", func(w http.ResponseWriter, r *http.Request) { 445 testMethod(t, r, "GET") 446 http.Redirect(w, r, "http://github.com/a", http.StatusMovedPermanently) 447 }) 448 _, resp, _ := client.Repositories.GetArchiveLink(context.Background(), "o", "r", Tarball, &RepositoryContentGetOptions{}, false) 449 if resp.StatusCode != http.StatusMovedPermanently { 450 t.Errorf("Repositories.GetArchiveLink returned status: %d, want %d", resp.StatusCode, http.StatusMovedPermanently) 451 } 452 } 453 454 func TestRepositoriesService_GetArchiveLink_StatusMovedPermanently_followRedirects(t *testing.T) { 455 client, mux, serverURL, teardown := setup() 456 defer teardown() 457 // Mock a redirect link, which leads to an archive link 458 mux.HandleFunc("/repos/o/r/tarball", func(w http.ResponseWriter, r *http.Request) { 459 testMethod(t, r, "GET") 460 redirectURL, _ := url.Parse(serverURL + baseURLPath + "/redirect") 461 http.Redirect(w, r, redirectURL.String(), http.StatusMovedPermanently) 462 }) 463 mux.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) { 464 testMethod(t, r, "GET") 465 http.Redirect(w, r, "http://github.com/a", http.StatusFound) 466 }) 467 url, resp, err := client.Repositories.GetArchiveLink(context.Background(), "o", "r", Tarball, &RepositoryContentGetOptions{}, true) 468 if err != nil { 469 t.Errorf("Repositories.GetArchiveLink returned error: %v", err) 470 } 471 if resp.StatusCode != http.StatusFound { 472 t.Errorf("Repositories.GetArchiveLink returned status: %d, want %d", resp.StatusCode, http.StatusFound) 473 } 474 want := "http://github.com/a" 475 if url.String() != want { 476 t.Errorf("Repositories.GetArchiveLink returned %+v, want %+v", url.String(), want) 477 } 478 } 479 480 func TestRepositoriesService_GetContents_NoTrailingSlashInDirectoryApiPath(t *testing.T) { 481 client, mux, _, teardown := setup() 482 defer teardown() 483 mux.HandleFunc("/repos/o/r/contents/.github", func(w http.ResponseWriter, r *http.Request) { 484 testMethod(t, r, "GET") 485 query := r.URL.Query() 486 if query.Get("ref") != "mybranch" { 487 t.Errorf("Repositories.GetContents returned %+v, want %+v", query.Get("ref"), "mybranch") 488 } 489 fmt.Fprint(w, `{}`) 490 }) 491 _, _, _, err := client.Repositories.GetContents(context.Background(), "o", "r", ".github/", &RepositoryContentGetOptions{ 492 Ref: "mybranch", 493 }) 494 if err != nil { 495 t.Fatalf("Repositories.GetContents returned error: %v", err) 496 } 497 }