github.com/google/go-github/v66@v66.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: 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: Int64(1), Author: &User{Login: String("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: 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: 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: String("v1.0"), 209 DiscussionCategoryName: String("General"), 210 GenerateReleaseNotes: Bool(true), 211 // Fields to be removed: 212 ID: Int64(2), 213 CreatedAt: &Timestamp{referenceTime}, 214 PublishedAt: &Timestamp{referenceTime}, 215 URL: String("http://url/"), 216 HTMLURL: String("http://htmlurl/"), 217 AssetsURL: String("http://assetsurl/"), 218 Assets: []*ReleaseAsset{{ID: Int64(5)}}, 219 UploadURL: String("http://uploadurl/"), 220 ZipballURL: String("http://zipballurl/"), 221 TarballURL: String("http://tarballurl/"), 222 Author: &User{Name: String("octocat")}, 223 NodeID: String("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: String("v1.0"), 233 DiscussionCategoryName: String("General"), 234 GenerateReleaseNotes: Bool(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: 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: String("n"), 274 DiscussionCategoryName: String("General"), 275 // Fields to be removed: 276 GenerateReleaseNotes: Bool(true), 277 ID: Int64(2), 278 CreatedAt: &Timestamp{referenceTime}, 279 PublishedAt: &Timestamp{referenceTime}, 280 URL: String("http://url/"), 281 HTMLURL: String("http://htmlurl/"), 282 AssetsURL: String("http://assetsurl/"), 283 Assets: []*ReleaseAsset{{ID: Int64(5)}}, 284 UploadURL: String("http://uploadurl/"), 285 ZipballURL: String("http://zipballurl/"), 286 TarballURL: String("http://tarballurl/"), 287 Author: &User{Name: String("octocat")}, 288 NodeID: String("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: String("n"), 298 DiscussionCategoryName: String("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: 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: 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: 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", "*/*") 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_FollowRedirectToError(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 testMethod(t, r, "GET") 520 testHeader(t, r, "Accept", defaultMediaType) 521 // /yo, below will be served as baseURLPath/yo 522 http.Redirect(w, r, baseURLPath+"/yo", http.StatusFound) 523 }) 524 mux.HandleFunc("/yo", func(w http.ResponseWriter, r *http.Request) { 525 testMethod(t, r, "GET") 526 testHeader(t, r, "Accept", "*/*") 527 w.WriteHeader(http.StatusNotFound) 528 }) 529 530 ctx := context.Background() 531 resp, loc, err := client.Repositories.DownloadReleaseAsset(ctx, "o", "r", 1, http.DefaultClient) 532 if err == nil { 533 t.Error("Repositories.DownloadReleaseAsset did not return an error") 534 } 535 if resp != nil { 536 resp.Close() 537 t.Error("Repositories.DownloadReleaseAsset returned stream, want nil") 538 } 539 if loc != "" { 540 t.Errorf(`Repositories.DownloadReleaseAsset returned "%s", want empty ""`, loc) 541 } 542 } 543 544 func TestRepositoriesService_DownloadReleaseAsset_APIError(t *testing.T) { 545 t.Parallel() 546 client, mux, _ := setup(t) 547 548 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 549 testMethod(t, r, "GET") 550 testHeader(t, r, "Accept", defaultMediaType) 551 w.WriteHeader(http.StatusNotFound) 552 fmt.Fprint(w, `{"message":"Not Found","documentation_url":"https://developer.github.com/v3"}`) 553 }) 554 555 ctx := context.Background() 556 resp, loc, err := client.Repositories.DownloadReleaseAsset(ctx, "o", "r", 1, nil) 557 if err == nil { 558 t.Error("Repositories.DownloadReleaseAsset did not return an error") 559 } 560 561 if resp != nil { 562 resp.Close() 563 t.Error("Repositories.DownloadReleaseAsset returned stream, want nil") 564 } 565 566 if loc != "" { 567 t.Errorf(`Repositories.DownloadReleaseAsset returned "%s", want empty ""`, loc) 568 } 569 } 570 571 func TestRepositoriesService_EditReleaseAsset(t *testing.T) { 572 t.Parallel() 573 client, mux, _ := setup(t) 574 575 input := &ReleaseAsset{Name: String("n")} 576 577 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 578 v := new(ReleaseAsset) 579 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 580 581 testMethod(t, r, "PATCH") 582 if !cmp.Equal(v, input) { 583 t.Errorf("Request body = %+v, want %+v", v, input) 584 } 585 fmt.Fprint(w, `{"id":1}`) 586 }) 587 588 ctx := context.Background() 589 asset, _, err := client.Repositories.EditReleaseAsset(ctx, "o", "r", 1, input) 590 if err != nil { 591 t.Errorf("Repositories.EditReleaseAsset returned error: %v", err) 592 } 593 want := &ReleaseAsset{ID: Int64(1)} 594 if !cmp.Equal(asset, want) { 595 t.Errorf("Repositories.EditReleaseAsset returned = %+v, want %+v", asset, want) 596 } 597 598 const methodName = "EditReleaseAsset" 599 testBadOptions(t, methodName, func() (err error) { 600 _, _, err = client.Repositories.EditReleaseAsset(ctx, "\n", "\n", 1, input) 601 return err 602 }) 603 604 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 605 got, resp, err := client.Repositories.EditReleaseAsset(ctx, "o", "r", 1, input) 606 if got != nil { 607 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 608 } 609 return resp, err 610 }) 611 } 612 613 func TestRepositoriesService_DeleteReleaseAsset(t *testing.T) { 614 t.Parallel() 615 client, mux, _ := setup(t) 616 617 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 618 testMethod(t, r, "DELETE") 619 }) 620 621 ctx := context.Background() 622 _, err := client.Repositories.DeleteReleaseAsset(ctx, "o", "r", 1) 623 if err != nil { 624 t.Errorf("Repositories.DeleteReleaseAsset returned error: %v", err) 625 } 626 627 const methodName = "DeleteReleaseAsset" 628 testBadOptions(t, methodName, func() (err error) { 629 _, err = client.Repositories.DeleteReleaseAsset(ctx, "\n", "\n", 1) 630 return err 631 }) 632 633 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 634 return client.Repositories.DeleteReleaseAsset(ctx, "o", "r", 1) 635 }) 636 } 637 638 func TestRepositoriesService_UploadReleaseAsset(t *testing.T) { 639 t.Parallel() 640 var ( 641 defaultUploadOptions = &UploadOptions{Name: "n"} 642 defaultExpectedFormValue = values{"name": "n"} 643 mediaTypeTextPlain = "text/plain; charset=utf-8" 644 ) 645 uploadTests := []struct { 646 uploadOpts *UploadOptions 647 fileName string 648 expectedFormValues values 649 expectedMediaType string 650 }{ 651 // No file extension and no explicit media type. 652 { 653 defaultUploadOptions, 654 "upload", 655 defaultExpectedFormValue, 656 defaultMediaType, 657 }, 658 // File extension and no explicit media type. 659 { 660 defaultUploadOptions, 661 "upload.txt", 662 defaultExpectedFormValue, 663 mediaTypeTextPlain, 664 }, 665 // No file extension and explicit media type. 666 { 667 &UploadOptions{Name: "n", MediaType: "image/png"}, 668 "upload", 669 defaultExpectedFormValue, 670 "image/png", 671 }, 672 // File extension and explicit media type. 673 { 674 &UploadOptions{Name: "n", MediaType: "image/png"}, 675 "upload.png", 676 defaultExpectedFormValue, 677 "image/png", 678 }, 679 // Label provided. 680 { 681 &UploadOptions{Name: "n", Label: "l"}, 682 "upload.txt", 683 values{"name": "n", "label": "l"}, 684 mediaTypeTextPlain, 685 }, 686 // No label provided. 687 { 688 defaultUploadOptions, 689 "upload.txt", 690 defaultExpectedFormValue, 691 mediaTypeTextPlain, 692 }, 693 } 694 695 client, mux, _ := setup(t) 696 697 for key, test := range uploadTests { 698 releaseEndpoint := fmt.Sprintf("/repos/o/r/releases/%d/assets", key) 699 mux.HandleFunc(releaseEndpoint, func(w http.ResponseWriter, r *http.Request) { 700 testMethod(t, r, "POST") 701 testHeader(t, r, "Content-Type", test.expectedMediaType) 702 testHeader(t, r, "Content-Length", "12") 703 testFormValues(t, r, test.expectedFormValues) 704 testBody(t, r, "Upload me !\n") 705 706 fmt.Fprintf(w, `{"id":1}`) 707 }) 708 709 file := openTestFile(t, test.fileName, "Upload me !\n") 710 711 ctx := context.Background() 712 asset, _, err := client.Repositories.UploadReleaseAsset(ctx, "o", "r", int64(key), test.uploadOpts, file) 713 if err != nil { 714 t.Errorf("Repositories.UploadReleaseAssert returned error: %v", err) 715 } 716 want := &ReleaseAsset{ID: Int64(1)} 717 if !cmp.Equal(asset, want) { 718 t.Errorf("Repositories.UploadReleaseAssert returned %+v, want %+v", asset, want) 719 } 720 721 const methodName = "UploadReleaseAsset" 722 testBadOptions(t, methodName, func() (err error) { 723 _, _, err = client.Repositories.UploadReleaseAsset(ctx, "\n", "\n", int64(key), test.uploadOpts, file) 724 return err 725 }) 726 } 727 } 728 729 func TestRepositoryReleaseRequest_Marshal(t *testing.T) { 730 t.Parallel() 731 testJSONMarshal(t, &repositoryReleaseRequest{}, "{}") 732 733 u := &repositoryReleaseRequest{ 734 TagName: String("tn"), 735 TargetCommitish: String("tc"), 736 Name: String("name"), 737 Body: String("body"), 738 Draft: Bool(false), 739 Prerelease: Bool(false), 740 MakeLatest: String("legacy"), 741 DiscussionCategoryName: String("dcn"), 742 } 743 744 want := `{ 745 "tag_name": "tn", 746 "target_commitish": "tc", 747 "name": "name", 748 "body": "body", 749 "draft": false, 750 "prerelease": false, 751 "make_latest": "legacy", 752 "discussion_category_name": "dcn" 753 }` 754 755 testJSONMarshal(t, u, want) 756 } 757 758 func TestReleaseAsset_Marshal(t *testing.T) { 759 t.Parallel() 760 testJSONMarshal(t, &ReleaseAsset{}, "{}") 761 762 u := &ReleaseAsset{ 763 ID: Int64(1), 764 URL: String("url"), 765 Name: String("name"), 766 Label: String("label"), 767 State: String("state"), 768 ContentType: String("ct"), 769 Size: Int(1), 770 DownloadCount: Int(1), 771 CreatedAt: &Timestamp{referenceTime}, 772 UpdatedAt: &Timestamp{referenceTime}, 773 BrowserDownloadURL: String("bdu"), 774 Uploader: &User{ID: Int64(1)}, 775 NodeID: String("nid"), 776 } 777 778 want := `{ 779 "id": 1, 780 "url": "url", 781 "name": "name", 782 "label": "label", 783 "state": "state", 784 "content_type": "ct", 785 "size": 1, 786 "download_count": 1, 787 "created_at": ` + referenceTimeStr + `, 788 "updated_at": ` + referenceTimeStr + `, 789 "browser_download_url": "bdu", 790 "uploader": { 791 "id": 1 792 }, 793 "node_id": "nid" 794 }` 795 796 testJSONMarshal(t, u, want) 797 } 798 799 func TestRepositoryRelease_Marshal(t *testing.T) { 800 t.Parallel() 801 testJSONMarshal(t, &RepositoryRelease{}, "{}") 802 803 u := &RepositoryRelease{ 804 TagName: String("tn"), 805 TargetCommitish: String("tc"), 806 Name: String("name"), 807 Body: String("body"), 808 Draft: Bool(false), 809 Prerelease: Bool(false), 810 MakeLatest: String("legacy"), 811 DiscussionCategoryName: String("dcn"), 812 ID: Int64(1), 813 CreatedAt: &Timestamp{referenceTime}, 814 PublishedAt: &Timestamp{referenceTime}, 815 URL: String("url"), 816 HTMLURL: String("hurl"), 817 AssetsURL: String("aurl"), 818 Assets: []*ReleaseAsset{{ID: Int64(1)}}, 819 UploadURL: String("uurl"), 820 ZipballURL: String("zurl"), 821 TarballURL: String("turl"), 822 Author: &User{ID: Int64(1)}, 823 NodeID: String("nid"), 824 } 825 826 want := `{ 827 "tag_name": "tn", 828 "target_commitish": "tc", 829 "name": "name", 830 "body": "body", 831 "draft": false, 832 "prerelease": false, 833 "make_latest": "legacy", 834 "discussion_category_name": "dcn", 835 "id": 1, 836 "created_at": ` + referenceTimeStr + `, 837 "published_at": ` + referenceTimeStr + `, 838 "url": "url", 839 "html_url": "hurl", 840 "assets_url": "aurl", 841 "assets": [ 842 { 843 "id": 1 844 } 845 ], 846 "upload_url": "uurl", 847 "zipball_url": "zurl", 848 "tarball_url": "turl", 849 "author": { 850 "id": 1 851 }, 852 "node_id": "nid" 853 }` 854 855 testJSONMarshal(t, u, want) 856 } 857 858 func TestGenerateNotesOptions_Marshal(t *testing.T) { 859 t.Parallel() 860 testJSONMarshal(t, &GenerateNotesOptions{}, "{}") 861 862 u := &GenerateNotesOptions{ 863 TagName: "tag_name", 864 PreviousTagName: String("previous_tag_name"), 865 TargetCommitish: String("target_commitish"), 866 } 867 868 want := `{ 869 "tag_name": "tag_name", 870 "previous_tag_name": "previous_tag_name", 871 "target_commitish": "target_commitish" 872 }` 873 874 testJSONMarshal(t, u, want) 875 }