github.com/google/go-github/v71@v71.0.0/github/repos_releases_test.go (about) 1 // Copyright 2013 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 "bytes" 10 "context" 11 "encoding/json" 12 "fmt" 13 "io" 14 "net/http" 15 "strings" 16 "testing" 17 18 "github.com/google/go-cmp/cmp" 19 ) 20 21 func TestRepositoriesService_ListReleases(t *testing.T) { 22 t.Parallel() 23 client, mux, _ := setup(t) 24 25 mux.HandleFunc("/repos/o/r/releases", func(w http.ResponseWriter, r *http.Request) { 26 testMethod(t, r, "GET") 27 testFormValues(t, r, values{"page": "2"}) 28 fmt.Fprint(w, `[{"id":1}]`) 29 }) 30 31 opt := &ListOptions{Page: 2} 32 ctx := context.Background() 33 releases, _, err := client.Repositories.ListReleases(ctx, "o", "r", opt) 34 if err != nil { 35 t.Errorf("Repositories.ListReleases returned error: %v", err) 36 } 37 want := []*RepositoryRelease{{ID: Ptr(int64(1))}} 38 if !cmp.Equal(releases, want) { 39 t.Errorf("Repositories.ListReleases returned %+v, want %+v", releases, want) 40 } 41 42 const methodName = "ListReleases" 43 testBadOptions(t, methodName, func() (err error) { 44 _, _, err = client.Repositories.ListReleases(ctx, "\n", "\n", opt) 45 return err 46 }) 47 48 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 49 got, resp, err := client.Repositories.ListReleases(ctx, "o", "r", opt) 50 if got != nil { 51 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 52 } 53 return resp, err 54 }) 55 } 56 57 func TestRepositoriesService_GenerateReleaseNotes(t *testing.T) { 58 t.Parallel() 59 client, mux, _ := setup(t) 60 61 mux.HandleFunc("/repos/o/r/releases/generate-notes", func(w http.ResponseWriter, r *http.Request) { 62 testMethod(t, r, "POST") 63 testBody(t, r, `{"tag_name":"v1.0.0"}`+"\n") 64 fmt.Fprint(w, `{"name":"v1.0.0","body":"**Full Changelog**: https://github.com/o/r/compare/v0.9.0...v1.0.0"}`) 65 }) 66 67 opt := &GenerateNotesOptions{ 68 TagName: "v1.0.0", 69 } 70 ctx := context.Background() 71 releases, _, err := client.Repositories.GenerateReleaseNotes(ctx, "o", "r", opt) 72 if err != nil { 73 t.Errorf("Repositories.GenerateReleaseNotes returned error: %v", err) 74 } 75 want := &RepositoryReleaseNotes{ 76 Name: "v1.0.0", 77 Body: "**Full Changelog**: https://github.com/o/r/compare/v0.9.0...v1.0.0", 78 } 79 if !cmp.Equal(releases, want) { 80 t.Errorf("Repositories.GenerateReleaseNotes returned %+v, want %+v", releases, want) 81 } 82 83 const methodName = "GenerateReleaseNotes" 84 testBadOptions(t, methodName, func() (err error) { 85 _, _, err = client.Repositories.GenerateReleaseNotes(ctx, "\n", "\n", opt) 86 return err 87 }) 88 89 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 90 got, resp, err := client.Repositories.GenerateReleaseNotes(ctx, "o", "r", opt) 91 if got != nil { 92 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 93 } 94 return resp, err 95 }) 96 } 97 98 func TestRepositoriesService_GetRelease(t *testing.T) { 99 t.Parallel() 100 client, mux, _ := setup(t) 101 102 mux.HandleFunc("/repos/o/r/releases/1", func(w http.ResponseWriter, r *http.Request) { 103 testMethod(t, r, "GET") 104 fmt.Fprint(w, `{"id":1,"author":{"login":"l"}}`) 105 }) 106 107 ctx := context.Background() 108 release, resp, err := client.Repositories.GetRelease(ctx, "o", "r", 1) 109 if err != nil { 110 t.Errorf("Repositories.GetRelease returned error: %v\n%v", err, resp.Body) 111 } 112 113 want := &RepositoryRelease{ID: Ptr(int64(1)), Author: &User{Login: Ptr("l")}} 114 if !cmp.Equal(release, want) { 115 t.Errorf("Repositories.GetRelease returned %+v, want %+v", release, want) 116 } 117 118 const methodName = "GetRelease" 119 testBadOptions(t, methodName, func() (err error) { 120 _, _, err = client.Repositories.GetRelease(ctx, "\n", "\n", 1) 121 return err 122 }) 123 124 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 125 got, resp, err := client.Repositories.GetRelease(ctx, "o", "r", 1) 126 if got != nil { 127 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 128 } 129 return resp, err 130 }) 131 } 132 133 func TestRepositoriesService_GetLatestRelease(t *testing.T) { 134 t.Parallel() 135 client, mux, _ := setup(t) 136 137 mux.HandleFunc("/repos/o/r/releases/latest", func(w http.ResponseWriter, r *http.Request) { 138 testMethod(t, r, "GET") 139 fmt.Fprint(w, `{"id":3}`) 140 }) 141 142 ctx := context.Background() 143 release, resp, err := client.Repositories.GetLatestRelease(ctx, "o", "r") 144 if err != nil { 145 t.Errorf("Repositories.GetLatestRelease returned error: %v\n%v", err, resp.Body) 146 } 147 148 want := &RepositoryRelease{ID: Ptr(int64(3))} 149 if !cmp.Equal(release, want) { 150 t.Errorf("Repositories.GetLatestRelease returned %+v, want %+v", release, want) 151 } 152 153 const methodName = "GetLatestRelease" 154 testBadOptions(t, methodName, func() (err error) { 155 _, _, err = client.Repositories.GetLatestRelease(ctx, "\n", "\n") 156 return err 157 }) 158 159 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 160 got, resp, err := client.Repositories.GetLatestRelease(ctx, "o", "r") 161 if got != nil { 162 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 163 } 164 return resp, err 165 }) 166 } 167 168 func TestRepositoriesService_GetReleaseByTag(t *testing.T) { 169 t.Parallel() 170 client, mux, _ := setup(t) 171 172 mux.HandleFunc("/repos/o/r/releases/tags/foo", func(w http.ResponseWriter, r *http.Request) { 173 testMethod(t, r, "GET") 174 fmt.Fprint(w, `{"id":13}`) 175 }) 176 177 ctx := context.Background() 178 release, resp, err := client.Repositories.GetReleaseByTag(ctx, "o", "r", "foo") 179 if err != nil { 180 t.Errorf("Repositories.GetReleaseByTag returned error: %v\n%v", err, resp.Body) 181 } 182 183 want := &RepositoryRelease{ID: Ptr(int64(13))} 184 if !cmp.Equal(release, want) { 185 t.Errorf("Repositories.GetReleaseByTag returned %+v, want %+v", release, want) 186 } 187 188 const methodName = "GetReleaseByTag" 189 testBadOptions(t, methodName, func() (err error) { 190 _, _, err = client.Repositories.GetReleaseByTag(ctx, "\n", "\n", "foo") 191 return err 192 }) 193 194 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 195 got, resp, err := client.Repositories.GetReleaseByTag(ctx, "o", "r", "foo") 196 if got != nil { 197 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 198 } 199 return resp, err 200 }) 201 } 202 203 func TestRepositoriesService_CreateRelease(t *testing.T) { 204 t.Parallel() 205 client, mux, _ := setup(t) 206 207 input := &RepositoryRelease{ 208 Name: Ptr("v1.0"), 209 DiscussionCategoryName: Ptr("General"), 210 GenerateReleaseNotes: Ptr(true), 211 // Fields to be removed: 212 ID: Ptr(int64(2)), 213 CreatedAt: &Timestamp{referenceTime}, 214 PublishedAt: &Timestamp{referenceTime}, 215 URL: Ptr("http://url/"), 216 HTMLURL: Ptr("http://htmlurl/"), 217 AssetsURL: Ptr("http://assetsurl/"), 218 Assets: []*ReleaseAsset{{ID: Ptr(int64(5))}}, 219 UploadURL: Ptr("http://uploadurl/"), 220 ZipballURL: Ptr("http://zipballurl/"), 221 TarballURL: Ptr("http://tarballurl/"), 222 Author: &User{Name: Ptr("octocat")}, 223 NodeID: Ptr("nodeid"), 224 } 225 226 mux.HandleFunc("/repos/o/r/releases", func(w http.ResponseWriter, r *http.Request) { 227 v := new(repositoryReleaseRequest) 228 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 229 230 testMethod(t, r, "POST") 231 want := &repositoryReleaseRequest{ 232 Name: Ptr("v1.0"), 233 DiscussionCategoryName: Ptr("General"), 234 GenerateReleaseNotes: Ptr(true), 235 } 236 if !cmp.Equal(v, want) { 237 t.Errorf("Request body = %+v, want %+v", v, want) 238 } 239 fmt.Fprint(w, `{"id":1}`) 240 }) 241 242 ctx := context.Background() 243 release, _, err := client.Repositories.CreateRelease(ctx, "o", "r", input) 244 if err != nil { 245 t.Errorf("Repositories.CreateRelease returned error: %v", err) 246 } 247 248 want := &RepositoryRelease{ID: Ptr(int64(1))} 249 if !cmp.Equal(release, want) { 250 t.Errorf("Repositories.CreateRelease returned %+v, want %+v", release, want) 251 } 252 253 const methodName = "CreateRelease" 254 testBadOptions(t, methodName, func() (err error) { 255 _, _, err = client.Repositories.CreateRelease(ctx, "\n", "\n", input) 256 return err 257 }) 258 259 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 260 got, resp, err := client.Repositories.CreateRelease(ctx, "o", "r", input) 261 if got != nil { 262 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 263 } 264 return resp, err 265 }) 266 } 267 268 func TestRepositoriesService_EditRelease(t *testing.T) { 269 t.Parallel() 270 client, mux, _ := setup(t) 271 272 input := &RepositoryRelease{ 273 Name: Ptr("n"), 274 DiscussionCategoryName: Ptr("General"), 275 // Fields to be removed: 276 GenerateReleaseNotes: Ptr(true), 277 ID: Ptr(int64(2)), 278 CreatedAt: &Timestamp{referenceTime}, 279 PublishedAt: &Timestamp{referenceTime}, 280 URL: Ptr("http://url/"), 281 HTMLURL: Ptr("http://htmlurl/"), 282 AssetsURL: Ptr("http://assetsurl/"), 283 Assets: []*ReleaseAsset{{ID: Ptr(int64(5))}}, 284 UploadURL: Ptr("http://uploadurl/"), 285 ZipballURL: Ptr("http://zipballurl/"), 286 TarballURL: Ptr("http://tarballurl/"), 287 Author: &User{Name: Ptr("octocat")}, 288 NodeID: Ptr("nodeid"), 289 } 290 291 mux.HandleFunc("/repos/o/r/releases/1", func(w http.ResponseWriter, r *http.Request) { 292 v := new(repositoryReleaseRequest) 293 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 294 295 testMethod(t, r, "PATCH") 296 want := &repositoryReleaseRequest{ 297 Name: Ptr("n"), 298 DiscussionCategoryName: Ptr("General"), 299 } 300 if !cmp.Equal(v, want) { 301 t.Errorf("Request body = %+v, want %+v", v, want) 302 } 303 fmt.Fprint(w, `{"id":1}`) 304 }) 305 306 ctx := context.Background() 307 release, _, err := client.Repositories.EditRelease(ctx, "o", "r", 1, input) 308 if err != nil { 309 t.Errorf("Repositories.EditRelease returned error: %v", err) 310 } 311 want := &RepositoryRelease{ID: Ptr(int64(1))} 312 if !cmp.Equal(release, want) { 313 t.Errorf("Repositories.EditRelease returned = %+v, want %+v", release, want) 314 } 315 316 const methodName = "EditRelease" 317 testBadOptions(t, methodName, func() (err error) { 318 _, _, err = client.Repositories.EditRelease(ctx, "\n", "\n", 1, input) 319 return err 320 }) 321 322 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 323 got, resp, err := client.Repositories.EditRelease(ctx, "o", "r", 1, input) 324 if got != nil { 325 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 326 } 327 return resp, err 328 }) 329 } 330 331 func TestRepositoriesService_DeleteRelease(t *testing.T) { 332 t.Parallel() 333 client, mux, _ := setup(t) 334 335 mux.HandleFunc("/repos/o/r/releases/1", func(w http.ResponseWriter, r *http.Request) { 336 testMethod(t, r, "DELETE") 337 }) 338 339 ctx := context.Background() 340 _, err := client.Repositories.DeleteRelease(ctx, "o", "r", 1) 341 if err != nil { 342 t.Errorf("Repositories.DeleteRelease returned error: %v", err) 343 } 344 345 const methodName = "DeleteRelease" 346 testBadOptions(t, methodName, func() (err error) { 347 _, err = client.Repositories.DeleteRelease(ctx, "\n", "\n", 1) 348 return err 349 }) 350 351 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 352 return client.Repositories.DeleteRelease(ctx, "o", "r", 1) 353 }) 354 } 355 356 func TestRepositoriesService_ListReleaseAssets(t *testing.T) { 357 t.Parallel() 358 client, mux, _ := setup(t) 359 360 mux.HandleFunc("/repos/o/r/releases/1/assets", func(w http.ResponseWriter, r *http.Request) { 361 testMethod(t, r, "GET") 362 testFormValues(t, r, values{"page": "2"}) 363 fmt.Fprint(w, `[{"id":1}]`) 364 }) 365 366 opt := &ListOptions{Page: 2} 367 ctx := context.Background() 368 assets, _, err := client.Repositories.ListReleaseAssets(ctx, "o", "r", 1, opt) 369 if err != nil { 370 t.Errorf("Repositories.ListReleaseAssets returned error: %v", err) 371 } 372 want := []*ReleaseAsset{{ID: Ptr(int64(1))}} 373 if !cmp.Equal(assets, want) { 374 t.Errorf("Repositories.ListReleaseAssets returned %+v, want %+v", assets, want) 375 } 376 377 const methodName = "ListReleaseAssets" 378 testBadOptions(t, methodName, func() (err error) { 379 _, _, err = client.Repositories.ListReleaseAssets(ctx, "\n", "\n", 1, opt) 380 return err 381 }) 382 383 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 384 got, resp, err := client.Repositories.ListReleaseAssets(ctx, "o", "r", 1, opt) 385 if got != nil { 386 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 387 } 388 return resp, err 389 }) 390 } 391 392 func TestRepositoriesService_GetReleaseAsset(t *testing.T) { 393 t.Parallel() 394 client, mux, _ := setup(t) 395 396 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 397 testMethod(t, r, "GET") 398 fmt.Fprint(w, `{"id":1}`) 399 }) 400 401 ctx := context.Background() 402 asset, _, err := client.Repositories.GetReleaseAsset(ctx, "o", "r", 1) 403 if err != nil { 404 t.Errorf("Repositories.GetReleaseAsset returned error: %v", err) 405 } 406 want := &ReleaseAsset{ID: Ptr(int64(1))} 407 if !cmp.Equal(asset, want) { 408 t.Errorf("Repositories.GetReleaseAsset returned %+v, want %+v", asset, want) 409 } 410 411 const methodName = "GetReleaseAsset" 412 testBadOptions(t, methodName, func() (err error) { 413 _, _, err = client.Repositories.GetReleaseAsset(ctx, "\n", "\n", 1) 414 return err 415 }) 416 417 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 418 got, resp, err := client.Repositories.GetReleaseAsset(ctx, "o", "r", 1) 419 if got != nil { 420 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 421 } 422 return resp, err 423 }) 424 } 425 426 func TestRepositoriesService_DownloadReleaseAsset_Stream(t *testing.T) { 427 t.Parallel() 428 client, mux, _ := setup(t) 429 430 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 431 testMethod(t, r, "GET") 432 testHeader(t, r, "Accept", defaultMediaType) 433 w.Header().Set("Content-Type", "application/octet-stream") 434 w.Header().Set("Content-Disposition", "attachment; filename=hello-world.txt") 435 fmt.Fprint(w, "Hello World") 436 }) 437 438 ctx := context.Background() 439 reader, _, err := client.Repositories.DownloadReleaseAsset(ctx, "o", "r", 1, nil) 440 if err != nil { 441 t.Errorf("Repositories.DownloadReleaseAsset returned error: %v", err) 442 } 443 want := []byte("Hello World") 444 content, err := io.ReadAll(reader) 445 if err != nil { 446 t.Errorf("Repositories.DownloadReleaseAsset returned bad reader: %v", err) 447 } 448 if !bytes.Equal(want, content) { 449 t.Errorf("Repositories.DownloadReleaseAsset returned %+v, want %+v", content, want) 450 } 451 452 const methodName = "DownloadReleaseAsset" 453 testBadOptions(t, methodName, func() (err error) { 454 _, _, err = client.Repositories.DownloadReleaseAsset(ctx, "\n", "\n", -1, nil) 455 return err 456 }) 457 } 458 459 func TestRepositoriesService_DownloadReleaseAsset_Redirect(t *testing.T) { 460 t.Parallel() 461 client, mux, _ := setup(t) 462 463 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 464 testMethod(t, r, "GET") 465 testHeader(t, r, "Accept", defaultMediaType) 466 http.Redirect(w, r, "/yo", http.StatusFound) 467 }) 468 469 ctx := context.Background() 470 _, got, err := client.Repositories.DownloadReleaseAsset(ctx, "o", "r", 1, nil) 471 if err != nil { 472 t.Errorf("Repositories.DownloadReleaseAsset returned error: %v", err) 473 } 474 want := "/yo" 475 if !strings.HasSuffix(got, want) { 476 t.Errorf("Repositories.DownloadReleaseAsset returned %+v, want %+v", got, want) 477 } 478 } 479 480 func TestRepositoriesService_DownloadReleaseAsset_FollowRedirect(t *testing.T) { 481 t.Parallel() 482 client, mux, _ := setup(t) 483 484 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 485 testMethod(t, r, "GET") 486 testHeader(t, r, "Accept", defaultMediaType) 487 // /yo, below will be served as baseURLPath/yo 488 http.Redirect(w, r, baseURLPath+"/yo", http.StatusFound) 489 }) 490 mux.HandleFunc("/yo", func(w http.ResponseWriter, r *http.Request) { 491 testMethod(t, r, "GET") 492 testHeader(t, r, "Accept", defaultMediaType) 493 w.Header().Set("Content-Type", "application/octet-stream") 494 w.Header().Set("Content-Disposition", "attachment; filename=hello-world.txt") 495 fmt.Fprint(w, "Hello World") 496 }) 497 498 ctx := context.Background() 499 reader, _, err := client.Repositories.DownloadReleaseAsset(ctx, "o", "r", 1, http.DefaultClient) 500 if err != nil { 501 t.Errorf("Repositories.DownloadReleaseAsset returned error: %v", err) 502 } 503 content, err := io.ReadAll(reader) 504 if err != nil { 505 t.Errorf("Reading Repositories.DownloadReleaseAsset returned error: %v", err) 506 } 507 reader.Close() 508 want := []byte("Hello World") 509 if !bytes.Equal(want, content) { 510 t.Errorf("Repositories.DownloadReleaseAsset returned %+v, want %+v", content, want) 511 } 512 } 513 514 func TestRepositoriesService_DownloadReleaseAsset_FollowMultipleRedirects(t *testing.T) { 515 t.Parallel() 516 client, mux, _ := setup(t) 517 518 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 519 w.Header().Set("Content-Type", "application/json; charset=utf-8") 520 testMethod(t, r, "GET") 521 testHeader(t, r, "Accept", defaultMediaType) 522 // /yo, below will be served as baseURLPath/yo 523 http.Redirect(w, r, baseURLPath+"/yo", http.StatusMovedPermanently) 524 }) 525 mux.HandleFunc("/yo", func(w http.ResponseWriter, r *http.Request) { 526 w.Header().Set("Content-Type", "text/html;charset=utf-8") 527 testMethod(t, r, "GET") 528 testHeader(t, r, "Accept", defaultMediaType) 529 // /yo2, below will be served as baseURLPath/yo2 530 http.Redirect(w, r, baseURLPath+"/yo2", http.StatusFound) 531 }) 532 mux.HandleFunc("/yo2", func(w http.ResponseWriter, r *http.Request) { 533 w.Header().Set("Content-Type", "application/octet-stream") 534 w.Header().Set("Content-Disposition", "attachment; filename=hello-world.txt") 535 testMethod(t, r, "GET") 536 testHeader(t, r, "Accept", defaultMediaType) 537 fmt.Fprint(w, "Hello World") 538 }) 539 540 ctx := context.Background() 541 reader, _, err := client.Repositories.DownloadReleaseAsset(ctx, "o", "r", 1, http.DefaultClient) 542 if err != nil { 543 t.Errorf("Repositories.DownloadReleaseAsset returned error: %v", err) 544 } 545 content, err := io.ReadAll(reader) 546 if err != nil { 547 t.Errorf("Reading Repositories.DownloadReleaseAsset returned error: %v", err) 548 } 549 reader.Close() 550 want := []byte("Hello World") 551 if !bytes.Equal(want, content) { 552 t.Errorf("Repositories.DownloadReleaseAsset returned %+v, want %+v", content, want) 553 } 554 } 555 556 func TestRepositoriesService_DownloadReleaseAsset_FollowRedirectToError(t *testing.T) { 557 t.Parallel() 558 client, mux, _ := setup(t) 559 560 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 561 testMethod(t, r, "GET") 562 testHeader(t, r, "Accept", defaultMediaType) 563 // /yo, below will be served as baseURLPath/yo 564 http.Redirect(w, r, baseURLPath+"/yo", http.StatusFound) 565 }) 566 mux.HandleFunc("/yo", func(w http.ResponseWriter, r *http.Request) { 567 testMethod(t, r, "GET") 568 testHeader(t, r, "Accept", defaultMediaType) 569 w.WriteHeader(http.StatusNotFound) 570 }) 571 572 ctx := context.Background() 573 resp, loc, err := client.Repositories.DownloadReleaseAsset(ctx, "o", "r", 1, http.DefaultClient) 574 if err == nil { 575 t.Error("Repositories.DownloadReleaseAsset did not return an error") 576 } 577 if resp != nil { 578 resp.Close() 579 t.Error("Repositories.DownloadReleaseAsset returned stream, want nil") 580 } 581 if loc != "" { 582 t.Errorf(`Repositories.DownloadReleaseAsset returned "%s", want empty ""`, loc) 583 } 584 } 585 586 func TestRepositoriesService_DownloadReleaseAsset_APIError(t *testing.T) { 587 t.Parallel() 588 client, mux, _ := setup(t) 589 590 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 591 testMethod(t, r, "GET") 592 testHeader(t, r, "Accept", defaultMediaType) 593 w.WriteHeader(http.StatusNotFound) 594 fmt.Fprint(w, `{"message":"Not Found","documentation_url":"https://developer.github.com/v3"}`) 595 }) 596 597 ctx := context.Background() 598 resp, loc, err := client.Repositories.DownloadReleaseAsset(ctx, "o", "r", 1, nil) 599 if err == nil { 600 t.Error("Repositories.DownloadReleaseAsset did not return an error") 601 } 602 603 if resp != nil { 604 resp.Close() 605 t.Error("Repositories.DownloadReleaseAsset returned stream, want nil") 606 } 607 608 if loc != "" { 609 t.Errorf(`Repositories.DownloadReleaseAsset returned "%s", want empty ""`, loc) 610 } 611 } 612 613 func TestRepositoriesService_EditReleaseAsset(t *testing.T) { 614 t.Parallel() 615 client, mux, _ := setup(t) 616 617 input := &ReleaseAsset{Name: Ptr("n")} 618 619 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 620 v := new(ReleaseAsset) 621 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 622 623 testMethod(t, r, "PATCH") 624 if !cmp.Equal(v, input) { 625 t.Errorf("Request body = %+v, want %+v", v, input) 626 } 627 fmt.Fprint(w, `{"id":1}`) 628 }) 629 630 ctx := context.Background() 631 asset, _, err := client.Repositories.EditReleaseAsset(ctx, "o", "r", 1, input) 632 if err != nil { 633 t.Errorf("Repositories.EditReleaseAsset returned error: %v", err) 634 } 635 want := &ReleaseAsset{ID: Ptr(int64(1))} 636 if !cmp.Equal(asset, want) { 637 t.Errorf("Repositories.EditReleaseAsset returned = %+v, want %+v", asset, want) 638 } 639 640 const methodName = "EditReleaseAsset" 641 testBadOptions(t, methodName, func() (err error) { 642 _, _, err = client.Repositories.EditReleaseAsset(ctx, "\n", "\n", 1, input) 643 return err 644 }) 645 646 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 647 got, resp, err := client.Repositories.EditReleaseAsset(ctx, "o", "r", 1, input) 648 if got != nil { 649 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 650 } 651 return resp, err 652 }) 653 } 654 655 func TestRepositoriesService_DeleteReleaseAsset(t *testing.T) { 656 t.Parallel() 657 client, mux, _ := setup(t) 658 659 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 660 testMethod(t, r, "DELETE") 661 }) 662 663 ctx := context.Background() 664 _, err := client.Repositories.DeleteReleaseAsset(ctx, "o", "r", 1) 665 if err != nil { 666 t.Errorf("Repositories.DeleteReleaseAsset returned error: %v", err) 667 } 668 669 const methodName = "DeleteReleaseAsset" 670 testBadOptions(t, methodName, func() (err error) { 671 _, err = client.Repositories.DeleteReleaseAsset(ctx, "\n", "\n", 1) 672 return err 673 }) 674 675 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 676 return client.Repositories.DeleteReleaseAsset(ctx, "o", "r", 1) 677 }) 678 } 679 680 func TestRepositoriesService_UploadReleaseAsset(t *testing.T) { 681 t.Parallel() 682 var ( 683 defaultUploadOptions = &UploadOptions{Name: "n"} 684 defaultExpectedFormValue = values{"name": "n"} 685 mediaTypeTextPlain = "text/plain; charset=utf-8" 686 ) 687 uploadTests := []struct { 688 uploadOpts *UploadOptions 689 fileName string 690 expectedFormValues values 691 expectedMediaType string 692 }{ 693 // No file extension and no explicit media type. 694 { 695 defaultUploadOptions, 696 "upload", 697 defaultExpectedFormValue, 698 defaultMediaType, 699 }, 700 // File extension and no explicit media type. 701 { 702 defaultUploadOptions, 703 "upload.txt", 704 defaultExpectedFormValue, 705 mediaTypeTextPlain, 706 }, 707 // No file extension and explicit media type. 708 { 709 &UploadOptions{Name: "n", MediaType: "image/png"}, 710 "upload", 711 defaultExpectedFormValue, 712 "image/png", 713 }, 714 // File extension and explicit media type. 715 { 716 &UploadOptions{Name: "n", MediaType: "image/png"}, 717 "upload.png", 718 defaultExpectedFormValue, 719 "image/png", 720 }, 721 // Label provided. 722 { 723 &UploadOptions{Name: "n", Label: "l"}, 724 "upload.txt", 725 values{"name": "n", "label": "l"}, 726 mediaTypeTextPlain, 727 }, 728 // No label provided. 729 { 730 defaultUploadOptions, 731 "upload.txt", 732 defaultExpectedFormValue, 733 mediaTypeTextPlain, 734 }, 735 } 736 737 client, mux, _ := setup(t) 738 739 for key, test := range uploadTests { 740 releaseEndpoint := fmt.Sprintf("/repos/o/r/releases/%d/assets", key) 741 mux.HandleFunc(releaseEndpoint, func(w http.ResponseWriter, r *http.Request) { 742 testMethod(t, r, "POST") 743 testHeader(t, r, "Content-Type", test.expectedMediaType) 744 testHeader(t, r, "Content-Length", "12") 745 testFormValues(t, r, test.expectedFormValues) 746 testBody(t, r, "Upload me !\n") 747 748 fmt.Fprintf(w, `{"id":1}`) 749 }) 750 751 file := openTestFile(t, test.fileName, "Upload me !\n") 752 753 ctx := context.Background() 754 asset, _, err := client.Repositories.UploadReleaseAsset(ctx, "o", "r", int64(key), test.uploadOpts, file) 755 if err != nil { 756 t.Errorf("Repositories.UploadReleaseAssert returned error: %v", err) 757 } 758 want := &ReleaseAsset{ID: Ptr(int64(1))} 759 if !cmp.Equal(asset, want) { 760 t.Errorf("Repositories.UploadReleaseAssert returned %+v, want %+v", asset, want) 761 } 762 763 const methodName = "UploadReleaseAsset" 764 testBadOptions(t, methodName, func() (err error) { 765 _, _, err = client.Repositories.UploadReleaseAsset(ctx, "\n", "\n", int64(key), test.uploadOpts, file) 766 return err 767 }) 768 } 769 } 770 771 func TestRepositoryReleaseRequest_Marshal(t *testing.T) { 772 t.Parallel() 773 testJSONMarshal(t, &repositoryReleaseRequest{}, "{}") 774 775 u := &repositoryReleaseRequest{ 776 TagName: Ptr("tn"), 777 TargetCommitish: Ptr("tc"), 778 Name: Ptr("name"), 779 Body: Ptr("body"), 780 Draft: Ptr(false), 781 Prerelease: Ptr(false), 782 MakeLatest: Ptr("legacy"), 783 DiscussionCategoryName: Ptr("dcn"), 784 } 785 786 want := `{ 787 "tag_name": "tn", 788 "target_commitish": "tc", 789 "name": "name", 790 "body": "body", 791 "draft": false, 792 "prerelease": false, 793 "make_latest": "legacy", 794 "discussion_category_name": "dcn" 795 }` 796 797 testJSONMarshal(t, u, want) 798 } 799 800 func TestReleaseAsset_Marshal(t *testing.T) { 801 t.Parallel() 802 testJSONMarshal(t, &ReleaseAsset{}, "{}") 803 804 u := &ReleaseAsset{ 805 ID: Ptr(int64(1)), 806 URL: Ptr("url"), 807 Name: Ptr("name"), 808 Label: Ptr("label"), 809 State: Ptr("state"), 810 ContentType: Ptr("ct"), 811 Size: Ptr(1), 812 DownloadCount: Ptr(1), 813 CreatedAt: &Timestamp{referenceTime}, 814 UpdatedAt: &Timestamp{referenceTime}, 815 BrowserDownloadURL: Ptr("bdu"), 816 Uploader: &User{ID: Ptr(int64(1))}, 817 NodeID: Ptr("nid"), 818 } 819 820 want := `{ 821 "id": 1, 822 "url": "url", 823 "name": "name", 824 "label": "label", 825 "state": "state", 826 "content_type": "ct", 827 "size": 1, 828 "download_count": 1, 829 "created_at": ` + referenceTimeStr + `, 830 "updated_at": ` + referenceTimeStr + `, 831 "browser_download_url": "bdu", 832 "uploader": { 833 "id": 1 834 }, 835 "node_id": "nid" 836 }` 837 838 testJSONMarshal(t, u, want) 839 } 840 841 func TestRepositoryRelease_Marshal(t *testing.T) { 842 t.Parallel() 843 testJSONMarshal(t, &RepositoryRelease{}, "{}") 844 845 u := &RepositoryRelease{ 846 TagName: Ptr("tn"), 847 TargetCommitish: Ptr("tc"), 848 Name: Ptr("name"), 849 Body: Ptr("body"), 850 Draft: Ptr(false), 851 Prerelease: Ptr(false), 852 MakeLatest: Ptr("legacy"), 853 DiscussionCategoryName: Ptr("dcn"), 854 ID: Ptr(int64(1)), 855 CreatedAt: &Timestamp{referenceTime}, 856 PublishedAt: &Timestamp{referenceTime}, 857 URL: Ptr("url"), 858 HTMLURL: Ptr("hurl"), 859 AssetsURL: Ptr("aurl"), 860 Assets: []*ReleaseAsset{{ID: Ptr(int64(1))}}, 861 UploadURL: Ptr("uurl"), 862 ZipballURL: Ptr("zurl"), 863 TarballURL: Ptr("turl"), 864 Author: &User{ID: Ptr(int64(1))}, 865 NodeID: Ptr("nid"), 866 } 867 868 want := `{ 869 "tag_name": "tn", 870 "target_commitish": "tc", 871 "name": "name", 872 "body": "body", 873 "draft": false, 874 "prerelease": false, 875 "make_latest": "legacy", 876 "discussion_category_name": "dcn", 877 "id": 1, 878 "created_at": ` + referenceTimeStr + `, 879 "published_at": ` + referenceTimeStr + `, 880 "url": "url", 881 "html_url": "hurl", 882 "assets_url": "aurl", 883 "assets": [ 884 { 885 "id": 1 886 } 887 ], 888 "upload_url": "uurl", 889 "zipball_url": "zurl", 890 "tarball_url": "turl", 891 "author": { 892 "id": 1 893 }, 894 "node_id": "nid" 895 }` 896 897 testJSONMarshal(t, u, want) 898 } 899 900 func TestGenerateNotesOptions_Marshal(t *testing.T) { 901 t.Parallel() 902 testJSONMarshal(t, &GenerateNotesOptions{}, "{}") 903 904 u := &GenerateNotesOptions{ 905 TagName: "tag_name", 906 PreviousTagName: Ptr("previous_tag_name"), 907 TargetCommitish: Ptr("target_commitish"), 908 } 909 910 want := `{ 911 "tag_name": "tag_name", 912 "previous_tag_name": "previous_tag_name", 913 "target_commitish": "target_commitish" 914 }` 915 916 testJSONMarshal(t, u, want) 917 }