github.com/line/line-bot-sdk-go/v7@v7.21.0/linebot/richmenu_test.go (about) 1 // Copyright 2016 LINE Corporation 2 // 3 // LINE Corporation licenses this file to you under the Apache License, 4 // version 2.0 (the "License"); you may not use this file except in compliance 5 // with the License. You may obtain a copy of the License at: 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations 13 // under the License. 14 15 package linebot 16 17 import ( 18 "bytes" 19 "fmt" 20 "io" 21 "net/http" 22 "net/http/httptest" 23 "os" 24 "path/filepath" 25 "reflect" 26 "strconv" 27 "testing" 28 ) 29 30 // TestGetRichMenu tests GetRichMenu, GetUserRichMenu 31 func TestGetRichMenu(t *testing.T) { 32 type want struct { 33 URLPath string 34 RequestBody []byte 35 Response *RichMenuResponse 36 Error error 37 } 38 testCases := []struct { 39 Label string 40 UserID string 41 RichMenuID string 42 ResponseCode int 43 Response []byte 44 Want want 45 }{ 46 { 47 Label: "Without UserID", 48 RichMenuID: "123456", 49 ResponseCode: 200, 50 Response: []byte(`{"richMenuId":"123456","size":{"width":2500,"height":1686},"selected":false,"areas":[{"bounds":{"x":0,"y":0,"width":2500,"height":1686},"action":{"type":"postback","data":"action=buy&itemid=123"}}]}`), 51 Want: want{ 52 URLPath: fmt.Sprintf(APIEndpointGetRichMenu, "123456"), 53 Response: &RichMenuResponse{ 54 RichMenuID: "123456", 55 Size: RichMenuSize{Width: 2500, Height: 1686}, 56 Selected: false, 57 ChatBarText: "", 58 Areas: []AreaDetail{ 59 { 60 Bounds: RichMenuBounds{X: 0, Y: 0, Width: 2500, Height: 1686}, 61 Action: RichMenuAction{Type: RichMenuActionTypePostback, Data: "action=buy&itemid=123"}, 62 }, 63 }, 64 }, 65 }, 66 }, 67 { 68 Label: "With UserID", 69 RichMenuID: "654321", 70 UserID: "user1", 71 ResponseCode: 200, 72 Response: []byte(`{"richMenuId":"654321","size":{"width":2500,"height":1686},"selected":false,"areas":[{"bounds":{"x":0,"y":0,"width":2500,"height":1686},"action":{"type":"postback","data":"action=buy&itemid=123"}}]}`), 73 Want: want{ 74 URLPath: fmt.Sprintf(APIEndpointGetUserRichMenu, "user1"), 75 Response: &RichMenuResponse{ 76 RichMenuID: "654321", 77 Size: RichMenuSize{Width: 2500, Height: 1686}, 78 Selected: false, 79 ChatBarText: "", 80 Areas: []AreaDetail{ 81 { 82 Bounds: RichMenuBounds{X: 0, Y: 0, Width: 2500, Height: 1686}, 83 Action: RichMenuAction{Type: RichMenuActionTypePostback, Data: "action=buy&itemid=123"}, 84 }, 85 }, 86 }, 87 }, 88 }, 89 } 90 91 var currentTestIdx int 92 server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 93 defer r.Body.Close() 94 tc := testCases[currentTestIdx] 95 if r.Method != http.MethodGet { 96 t.Errorf("Method %s; want %s", r.Method, http.MethodGet) 97 } 98 if r.URL.Path != tc.Want.URLPath { 99 t.Errorf("URLPath %s; want %s", r.URL.Path, tc.Want.URLPath) 100 } 101 _, err := io.ReadAll(r.Body) 102 if err != nil { 103 t.Fatal(err) 104 } 105 w.WriteHeader(tc.ResponseCode) 106 w.Write(tc.Response) 107 })) 108 defer server.Close() 109 110 dataServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 111 defer r.Body.Close() 112 t.Error("Unexpected data API call") 113 w.WriteHeader(404) 114 w.Write([]byte(`{"message":"Not found"}`)) 115 })) 116 defer dataServer.Close() 117 118 client, err := mockClient(server, dataServer) 119 if err != nil { 120 t.Fatal(err) 121 } 122 123 var res *RichMenuResponse 124 for i, tc := range testCases { 125 currentTestIdx = i 126 t.Run(strconv.Itoa(i)+"/"+tc.Label, func(t *testing.T) { 127 if tc.UserID != "" { // test get user 128 res, err = client.GetUserRichMenu(tc.UserID).Do() 129 } else { 130 res, err = client.GetRichMenu(tc.RichMenuID).Do() 131 } 132 if tc.Want.Error != nil { 133 if !reflect.DeepEqual(err, tc.Want.Error) { 134 t.Errorf("Error %v; want %v", err, tc.Want.Error) 135 } 136 } else { 137 if err != nil { 138 t.Error(err) 139 } 140 } 141 if tc.Want.Response != nil { 142 if !reflect.DeepEqual(res, tc.Want.Response) { 143 t.Errorf("Response %v; want %v", res, tc.Want.Response) 144 } 145 } 146 }) 147 } 148 } 149 150 func TestCreateRichMenu(t *testing.T) { 151 type want struct { 152 RequestBody []byte 153 Response *RichMenuIDResponse 154 Error error 155 } 156 testCases := []struct { 157 Request RichMenu 158 Response []byte 159 ResponseCode int 160 Want want 161 }{ 162 { 163 Request: RichMenu{ 164 Size: RichMenuSize{Width: 2500, Height: 1686}, 165 Selected: false, 166 Name: "Menu1", 167 ChatBarText: "ChatText", 168 Areas: []AreaDetail{ 169 { 170 Bounds: RichMenuBounds{X: 0, Y: 0, Width: 2500, Height: 1686}, 171 Action: RichMenuAction{Type: RichMenuActionTypePostback, Data: "action=buy&itemid=123", DisplayText: "Buy", Label: "Buy"}, 172 }, 173 }, 174 }, 175 ResponseCode: 200, 176 Response: []byte(`{"richMenuId":"abcefg"}`), 177 Want: want{ 178 RequestBody: []byte(`{"size":{"width":2500,"height":1686},"selected":false,"name":"Menu1","chatBarText":"ChatText","areas":[{"bounds":{"x":0,"y":0,"width":2500,"height":1686},"action":{"type":"postback","displayText":"Buy","label":"Buy","data":"action=buy\u0026itemid=123"}}]}` + "\n"), 179 Response: &RichMenuIDResponse{RichMenuID: "abcefg"}, 180 }, 181 }, 182 } 183 184 var currentTestIdx int 185 server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 186 defer r.Body.Close() 187 tc := testCases[currentTestIdx] 188 if r.Method != http.MethodPost { 189 t.Errorf("Method %s; want %s", r.Method, http.MethodPost) 190 } 191 if r.URL.Path != APIEndpointCreateRichMenu { 192 t.Errorf("URLPath %s; want %s", r.URL.Path, APIEndpointCreateRichMenu) 193 } 194 body, err := io.ReadAll(r.Body) 195 if err != nil { 196 t.Fatal(err) 197 } 198 if !reflect.DeepEqual(body, tc.Want.RequestBody) { 199 t.Errorf("RequestBody\n %s; want\n %s", body, tc.Want.RequestBody) 200 } 201 w.WriteHeader(tc.ResponseCode) 202 w.Write(tc.Response) 203 })) 204 defer server.Close() 205 206 dataServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 207 defer r.Body.Close() 208 t.Error("Unexpected data API call") 209 w.WriteHeader(404) 210 w.Write([]byte(`{"message":"Not found"}`)) 211 })) 212 defer dataServer.Close() 213 214 client, err := mockClient(server, dataServer) 215 if err != nil { 216 t.Fatal(err) 217 } 218 for i, tc := range testCases { 219 currentTestIdx = i 220 t.Run(strconv.Itoa(i), func(t *testing.T) { 221 res, err := client.CreateRichMenu(tc.Request).Do() 222 if tc.Want.Error != nil { 223 if !reflect.DeepEqual(err, tc.Want.Error) { 224 t.Errorf("Error %v; want %v", err, tc.Want.Error) 225 } 226 } else { 227 if err != nil { 228 t.Error(err) 229 } 230 } 231 if tc.Want.Response != nil { 232 if !reflect.DeepEqual(res, tc.Want.Response) { 233 t.Errorf("Response %v; want %v", res, tc.Want.Response) 234 } 235 } 236 }) 237 } 238 } 239 240 // TestLinkRichMenu tests LinkUserRichMenu 241 func TestLinkRichMenu(t *testing.T) { 242 type want struct { 243 URLPath string 244 RequestBody []byte 245 Response *BasicResponse 246 Error error 247 } 248 testCases := []struct { 249 RichMenuID string 250 UserID string 251 ResponseCode int 252 Response []byte 253 Want want 254 }{ 255 { 256 RichMenuID: "654321", 257 UserID: "userId1", 258 ResponseCode: 200, 259 Response: []byte(`{}`), 260 Want: want{ 261 URLPath: fmt.Sprintf(APIEndpointLinkUserRichMenu, "userId1", "654321"), 262 Response: &BasicResponse{}, 263 }, 264 }, 265 } 266 267 var currentTestIdx int 268 server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 269 defer r.Body.Close() 270 tc := testCases[currentTestIdx] 271 if r.Method != http.MethodPost { 272 t.Errorf("Method %s; want %s", r.Method, http.MethodGet) 273 } 274 if r.URL.Path != tc.Want.URLPath { 275 t.Errorf("URLPath %s; want %s", r.URL.Path, tc.Want.URLPath) 276 } 277 _, err := io.ReadAll(r.Body) 278 if err != nil { 279 t.Fatal(err) 280 } 281 w.WriteHeader(tc.ResponseCode) 282 w.Write(tc.Response) 283 })) 284 defer server.Close() 285 286 dataServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 287 defer r.Body.Close() 288 t.Error("Unexpected data API call") 289 w.WriteHeader(404) 290 w.Write([]byte(`{"message":"Not found"}`)) 291 })) 292 defer dataServer.Close() 293 294 client, err := mockClient(server, dataServer) 295 if err != nil { 296 t.Fatal(err) 297 } 298 var res *BasicResponse 299 for i, tc := range testCases { 300 currentTestIdx = i 301 t.Run(strconv.Itoa(i), func(t *testing.T) { 302 res, err = client.LinkUserRichMenu(tc.UserID, tc.RichMenuID).Do() 303 if tc.Want.Error != nil { 304 if !reflect.DeepEqual(err, tc.Want.Error) { 305 t.Errorf("Error %v; want %v", err, tc.Want.Error) 306 } 307 } else { 308 if err != nil { 309 t.Error(err) 310 } 311 } 312 if tc.Want.Response != nil { 313 if !reflect.DeepEqual(res, tc.Want.Response) { 314 t.Errorf("Response %v; want %v", res, tc.Want.Response) 315 } 316 } 317 }) 318 } 319 } 320 321 // Test method for GetDefaultRichMenu 322 func (call *GetDefaultRichMenuCall) Test() { 323 } 324 325 // Test method for CancelDefaultRichMenu 326 func (call *CancelDefaultRichMenuCall) Test() { 327 } 328 329 // Test method for SetDefaultRichMenu 330 func (call *SetDefaultRichMenuCall) Test() { 331 } 332 333 // TestDefaultRichMenu tests SetDefaultRichMenu, CancelDefaultRichMenu, GetDefaultRichMenu 334 func TestDefaultRichMenu(t *testing.T) { 335 type testMethod interface { 336 Test() 337 } 338 type want struct { 339 URLPath string 340 HTTPMethod string 341 RequestBody []byte 342 Response interface{} 343 Error error 344 } 345 testCases := []struct { 346 TestMethod testMethod 347 RichMenuID string 348 ResponseCode int 349 Response []byte 350 Want want 351 }{ 352 { 353 RichMenuID: "654321", 354 TestMethod: new(SetDefaultRichMenuCall), 355 ResponseCode: 200, 356 Response: []byte(`{}`), 357 Want: want{ 358 HTTPMethod: http.MethodPost, 359 URLPath: fmt.Sprintf(APIEndpointSetDefaultRichMenu, "654321"), 360 Response: &BasicResponse{}, 361 }, 362 }, 363 { 364 RichMenuID: "N/A", 365 TestMethod: new(GetDefaultRichMenuCall), 366 ResponseCode: 200, 367 Response: []byte(`{"richMenuId": "654321"}`), 368 Want: want{ 369 HTTPMethod: http.MethodGet, 370 URLPath: APIEndpointDefaultRichMenu, 371 Response: &RichMenuIDResponse{RichMenuID: "654321"}, 372 }, 373 }, 374 { 375 RichMenuID: "N/A", 376 TestMethod: new(CancelDefaultRichMenuCall), 377 ResponseCode: 200, 378 Response: []byte(`{}`), 379 Want: want{ 380 HTTPMethod: http.MethodDelete, 381 URLPath: APIEndpointDefaultRichMenu, 382 Response: &BasicResponse{}, 383 }, 384 }, 385 } 386 387 var currentTestIdx int 388 server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 389 defer r.Body.Close() 390 tc := testCases[currentTestIdx] 391 if r.Method != tc.Want.HTTPMethod { 392 t.Errorf("Method %s; want %s", r.Method, tc.Want.HTTPMethod) 393 } 394 if r.URL.Path != tc.Want.URLPath { 395 t.Errorf("URLPath %s; want %s", r.URL.Path, tc.Want.URLPath) 396 } 397 _, err := io.ReadAll(r.Body) 398 if err != nil { 399 t.Fatal(err) 400 } 401 w.WriteHeader(tc.ResponseCode) 402 w.Write(tc.Response) 403 })) 404 defer server.Close() 405 406 dataServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 407 defer r.Body.Close() 408 t.Error("Unexpected data API call") 409 w.WriteHeader(404) 410 w.Write([]byte(`{"message":"Not found"}`)) 411 })) 412 defer dataServer.Close() 413 414 client, err := mockClient(server, dataServer) 415 if err != nil { 416 t.Fatal(err) 417 } 418 var res interface{} 419 for i, tc := range testCases { 420 currentTestIdx = i 421 t.Run(strconv.Itoa(i)+"/"+tc.RichMenuID+"."+string(tc.Response), func(t *testing.T) { 422 switch tc.TestMethod.(type) { 423 case *SetDefaultRichMenuCall: 424 res, err = client.SetDefaultRichMenu(tc.RichMenuID).Do() 425 case *CancelDefaultRichMenuCall: 426 res, err = client.CancelDefaultRichMenu().Do() 427 case *GetDefaultRichMenuCall: 428 res, err = client.GetDefaultRichMenu().Do() 429 } 430 if tc.Want.Error != nil { 431 if !reflect.DeepEqual(err, tc.Want.Error) { 432 t.Errorf("Error %v; want %v", err, tc.Want.Error) 433 } 434 } else { 435 if err != nil { 436 t.Error(err) 437 } 438 } 439 if tc.Want.Response != nil { 440 if !reflect.DeepEqual(res, tc.Want.Response) { 441 t.Errorf("Response %v; want %v", res, tc.Want.Response) 442 } 443 } 444 }) 445 } 446 } 447 448 // TestListRichMenu 449 func TestListRichMenu(t *testing.T) { 450 type want struct { 451 URLPath string 452 RequestBody []byte 453 Response []*RichMenuResponse 454 Error error 455 } 456 testCases := []struct { 457 ResponseCode int 458 Response []byte 459 Want want 460 }{ 461 { 462 ResponseCode: 200, 463 Response: []byte(`{"richmenus":[` + 464 `{"richMenuId":"123","size":{"width":2500,"height":1686},"selected":false,"areas":[{"bounds":{"x":0,"y":0,"width":2500,"height":1686},"action":{"type":"postback","data":"action=buy&itemid=123"}}]},` + 465 `{"richMenuId":"456","size":{"width":2500,"height":1686},"selected":false,"chatBarText":"hello","areas":[{"bounds":{"x":0,"y":0,"width":2500,"height":1686},"action":{"type":"message","text":"text"}}]},` + 466 `{"richMenuId":"789","size":{"width":2500,"height":1686},"selected":false,"chatBarText":"line.me","areas":[{"bounds":{"x":0,"y":0,"width":2500,"height":1686},"action":{"type":"uri","uri":"https://line.me/"}}]}` + 467 `]}`), 468 Want: want{ 469 URLPath: APIEndpointListRichMenu, 470 Response: []*RichMenuResponse{ 471 { 472 RichMenuID: "123", 473 Size: RichMenuSize{Width: 2500, Height: 1686}, 474 Selected: false, 475 ChatBarText: "", 476 Areas: []AreaDetail{ 477 { 478 Bounds: RichMenuBounds{X: 0, Y: 0, Width: 2500, Height: 1686}, 479 Action: RichMenuAction{Type: RichMenuActionTypePostback, Data: "action=buy&itemid=123"}, 480 }, 481 }, 482 }, 483 { 484 RichMenuID: "456", 485 Size: RichMenuSize{Width: 2500, Height: 1686}, 486 Selected: false, 487 ChatBarText: "hello", 488 Areas: []AreaDetail{ 489 { 490 Bounds: RichMenuBounds{X: 0, Y: 0, Width: 2500, Height: 1686}, 491 Action: RichMenuAction{Type: RichMenuActionTypeMessage, Text: "text"}, 492 }, 493 }, 494 }, 495 { 496 RichMenuID: "789", 497 Size: RichMenuSize{Width: 2500, Height: 1686}, 498 Selected: false, 499 ChatBarText: "line.me", 500 Areas: []AreaDetail{ 501 { 502 Bounds: RichMenuBounds{X: 0, Y: 0, Width: 2500, Height: 1686}, 503 Action: RichMenuAction{Type: RichMenuActionTypeURI, URI: "https://line.me/"}, 504 }, 505 }, 506 }, 507 }, 508 }, 509 }, 510 } 511 512 var currentTestIdx int 513 server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 514 defer r.Body.Close() 515 tc := testCases[currentTestIdx] 516 if r.Method != http.MethodGet { 517 t.Errorf("Method %s; want %s", r.Method, http.MethodGet) 518 } 519 if r.URL.Path != tc.Want.URLPath { 520 t.Errorf("URLPath %s; want %s", r.URL.Path, tc.Want.URLPath) 521 } 522 _, err := io.ReadAll(r.Body) 523 if err != nil { 524 t.Fatal(err) 525 } 526 w.WriteHeader(tc.ResponseCode) 527 w.Write(tc.Response) 528 })) 529 defer server.Close() 530 531 dataServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 532 defer r.Body.Close() 533 t.Error("Unexpected data API call") 534 w.WriteHeader(404) 535 w.Write([]byte(`{"message":"Not found"}`)) 536 })) 537 defer dataServer.Close() 538 539 client, err := mockClient(server, dataServer) 540 if err != nil { 541 t.Fatal(err) 542 } 543 for i, tc := range testCases { 544 currentTestIdx = i 545 t.Run(strconv.Itoa(i), func(t *testing.T) { 546 res, err := client.GetRichMenuList().Do() 547 if tc.Want.Error != nil { 548 if !reflect.DeepEqual(err, tc.Want.Error) { 549 t.Errorf("Error %v; want %v", err, tc.Want.Error) 550 } 551 } else { 552 if err != nil { 553 t.Error(err) 554 } 555 } 556 if tc.Want.Response != nil { 557 if !reflect.DeepEqual(res, tc.Want.Response) { 558 t.Errorf("Response\n %v; want\n %v", res, tc.Want.Response) 559 } 560 } 561 }) 562 } 563 } 564 565 // TestBulkRichMenu tests BulkLinkRichMenu, BulkUnlinkRichMenu 566 func TestBulkRichMenu(t *testing.T) { 567 type want struct { 568 URLPath string 569 RequestBody []byte 570 Response *BasicResponse 571 Error error 572 } 573 testCases := []struct { 574 UserIDs []string 575 RichMenuID string 576 ResponseCode int 577 Response []byte 578 Want want 579 }{ 580 { 581 ResponseCode: 202, 582 Response: []byte(`{}`), 583 UserIDs: []string{"userId1", "userId2"}, 584 RichMenuID: "richMenuId", 585 Want: want{ 586 RequestBody: []byte(`{"richMenuId":"richMenuId","userIds":["userId1","userId2"]}` + "\n"), 587 URLPath: APIEndpointBulkLinkRichMenu, 588 Response: &BasicResponse{}, 589 }, 590 }, 591 { 592 ResponseCode: 202, 593 Response: []byte(`{}`), 594 UserIDs: []string{"userId1", "userId2"}, 595 RichMenuID: "", // bulk unlink has no richmenuid 596 Want: want{ 597 RequestBody: []byte(`{"userIds":["userId1","userId2"]}` + "\n"), 598 URLPath: APIEndpointBulkUnlinkRichMenu, 599 Response: &BasicResponse{}, 600 }, 601 }, 602 } 603 604 var currentTestIdx int 605 server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 606 defer r.Body.Close() 607 tc := testCases[currentTestIdx] 608 if r.Method != http.MethodPost { 609 t.Errorf("Method %s; want %s", r.Method, http.MethodPost) 610 } 611 if r.URL.Path != tc.Want.URLPath { 612 t.Errorf("URLPath %s; want %s", r.URL.Path, tc.Want.URLPath) 613 } 614 body, err := io.ReadAll(r.Body) 615 if err != nil { 616 t.Fatal(err) 617 } 618 if !reflect.DeepEqual(body, tc.Want.RequestBody) { 619 t.Errorf("RequestBody\n %s; want\n %s", body, tc.Want.RequestBody) 620 } 621 w.WriteHeader(tc.ResponseCode) 622 w.Write(tc.Response) 623 })) 624 defer server.Close() 625 626 dataServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 627 defer r.Body.Close() 628 t.Error("Unexpected data API call") 629 w.WriteHeader(404) 630 w.Write([]byte(`{"message":"Not found"}`)) 631 })) 632 defer dataServer.Close() 633 634 client, err := mockClient(server, dataServer) 635 if err != nil { 636 t.Fatal(err) 637 } 638 639 var res interface{} 640 for i, tc := range testCases { 641 currentTestIdx = i 642 t.Run(strconv.Itoa(i), func(t *testing.T) { 643 if tc.RichMenuID == "" { // unlink 644 res, err = client.BulkUnlinkRichMenu(tc.UserIDs...).Do() 645 } else { // bulk link 646 res, err = client.BulkLinkRichMenu(tc.RichMenuID, tc.UserIDs...).Do() 647 } 648 if tc.Want.Error != nil { 649 if !reflect.DeepEqual(err, tc.Want.Error) { 650 t.Errorf("Error %v; want %v", err, tc.Want.Error) 651 } 652 } else { 653 if err != nil { 654 t.Error(err) 655 } 656 } 657 if tc.Want.Response != nil { 658 if !reflect.DeepEqual(res, tc.Want.Response) { 659 t.Errorf("Response\n %v; want\n %v", res, tc.Want.Response) 660 } 661 } 662 }) 663 } 664 } 665 666 func TestUploadRichMenuImage(t *testing.T) { 667 type want struct { 668 URLPath string 669 RequestBody []byte 670 Response *BasicResponse 671 Error error 672 } 673 testCases := []struct { 674 RichMenuID string 675 ImagePath string 676 ResponseCode int 677 Response []byte 678 Want want 679 }{ 680 { 681 RichMenuID: "123456", 682 ImagePath: filepath.Join("..", "testdata", "img", "richmenu.png"), 683 ResponseCode: 200, 684 Response: []byte(`{}`), 685 Want: want{ 686 URLPath: fmt.Sprintf(APIEndpointUploadRichMenuImage, "123456"), 687 Response: &BasicResponse{}, 688 }, 689 }, 690 } 691 692 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 693 defer r.Body.Close() 694 t.Error("Unexpected API call") 695 w.WriteHeader(404) 696 w.Write([]byte(`{"message":"Not found"}`)) 697 })) 698 defer server.Close() 699 700 var currentTestIdx int 701 dataServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 702 defer r.Body.Close() 703 tc := testCases[currentTestIdx] 704 if r.Method != http.MethodPost { 705 t.Errorf("Method %s; want %s", r.Method, http.MethodPost) 706 } 707 if r.URL.Path != tc.Want.URLPath { 708 t.Errorf("URLPath %s; want %s", r.URL.Path, tc.Want.URLPath) 709 } 710 body, err := io.ReadAll(r.Body) 711 if err != nil { 712 t.Fatal(err) 713 } 714 imgBody, err := os.ReadFile(tc.ImagePath) 715 if err != nil { 716 t.Fatal(err) 717 } 718 wantImgSize := len(imgBody) 719 if len(body) != wantImgSize { 720 t.Errorf("ContentLength %d; want %d", len(body), wantImgSize) 721 } 722 if r.ContentLength != int64(wantImgSize) { 723 t.Errorf("ContentLength %d; want %d", r.ContentLength, wantImgSize) 724 } 725 w.WriteHeader(tc.ResponseCode) 726 w.Write(tc.Response) 727 })) 728 defer dataServer.Close() 729 client, err := mockClient(server, dataServer) 730 if err != nil { 731 t.Fatal(err) 732 } 733 734 for i, tc := range testCases { 735 currentTestIdx = i 736 t.Run(strconv.Itoa(i), func(t *testing.T) { 737 res, err := client.UploadRichMenuImage(tc.RichMenuID, tc.ImagePath).Do() 738 if tc.Want.Error != nil { 739 if !reflect.DeepEqual(err, tc.Want.Error) { 740 t.Errorf("Error %v; want %v", err, tc.Want.Error) 741 } 742 } else { 743 if err != nil { 744 t.Error(err) 745 } 746 } 747 if tc.Want.Response != nil { 748 if !reflect.DeepEqual(res, tc.Want.Response) { 749 t.Errorf("Response\n %v; want\n %v", res, tc.Want.Response) 750 } 751 } 752 }) 753 } 754 } 755 756 func TestDownloadRichMenuImage(t *testing.T) { 757 filePath := filepath.Join("..", "testdata", "img", "richmenu.png") 758 file, err := os.ReadFile(filePath) 759 if err != nil { 760 t.Fatal(err) 761 } 762 763 type want struct { 764 URLPath string 765 Response *MessageContentResponse 766 Error error 767 } 768 testCases := []struct { 769 RichMenuID string 770 ImagePath string 771 Response []byte 772 ResponseCode int 773 ResponseHeader map[string]string 774 Want want 775 }{ 776 { 777 RichMenuID: "123456", 778 Response: file, 779 ResponseCode: 200, 780 ResponseHeader: map[string]string{ 781 "Content-Type": "image/png", 782 "Content-Length": strconv.Itoa(len(file)), 783 }, 784 Want: want{ 785 URLPath: fmt.Sprintf(APIEndpointUploadRichMenuImage, "123456"), 786 Response: &MessageContentResponse{ 787 ContentType: "image/png", 788 ContentLength: int64(len(file)), 789 Content: io.NopCloser(bytes.NewReader(file)), 790 }, 791 }, 792 }, 793 } 794 795 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 796 defer r.Body.Close() 797 t.Error("Unexpected API call") 798 w.WriteHeader(404) 799 w.Write([]byte(`{"message":"Not found"}`)) 800 })) 801 defer server.Close() 802 803 var currentTestIdx int 804 dataServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 805 defer r.Body.Close() 806 tc := testCases[currentTestIdx] 807 if r.Method != http.MethodGet { 808 t.Errorf("Method %s; want %s", r.Method, http.MethodGet) 809 } 810 if r.URL.Path != tc.Want.URLPath { 811 t.Errorf("URLPath %s; want %s", r.URL.Path, tc.Want.URLPath) 812 } 813 if err != nil { 814 t.Fatal(err) 815 } 816 for k, v := range tc.ResponseHeader { 817 w.Header().Add(k, v) 818 } 819 w.WriteHeader(tc.ResponseCode) 820 w.Write(tc.Response) 821 })) 822 defer dataServer.Close() 823 824 client, err := mockClient(server, dataServer) 825 if err != nil { 826 t.Fatal(err) 827 } 828 829 for i, tc := range testCases { 830 currentTestIdx = i 831 t.Run(strconv.Itoa(i), func(t *testing.T) { 832 res, err := client.DownloadRichMenuImage(tc.RichMenuID).Do() 833 if tc.Want.Error != nil { 834 if !reflect.DeepEqual(err, tc.Want.Error) { 835 t.Errorf("Error %v; want %v", err, tc.Want.Error) 836 } 837 } else { 838 if err != nil { 839 t.Error(err) 840 } 841 } 842 if tc.Want.Response != nil { 843 body := res.Content 844 defer body.Close() 845 resImage, err := io.ReadAll(body) 846 if err != nil { 847 t.Fatal(err) 848 } 849 if !bytes.Equal(resImage, tc.Response) { 850 t.Error("Expected image content is not returned") 851 } 852 res.Content = nil 853 tc.Want.Response.Content = nil 854 if !reflect.DeepEqual(res, tc.Want.Response) { 855 t.Errorf("Response\n %+v; want\n %+v", res, tc.Want.Response) 856 } 857 } 858 }) 859 } 860 } 861 862 // Test method for CreateRichMenuAlias 863 func (call *CreateRichMenuAliasCall) Test() { 864 } 865 866 // Test method for GetRichMenuAlias 867 func (call *GetRichMenuAliasCall) Test() { 868 } 869 870 // Test method for UpdateRichMenuAlias 871 func (call *UpdateRichMenuAliasCall) Test() { 872 } 873 874 // Test method for DeleteRichMenuAlias 875 func (call *DeleteRichMenuAliasCall) Test() { 876 } 877 878 // TestCRUDRichMenuAlias tests CreateRichMenuAlias, GetRichMenuAlias, UpdateRichMenuAlias, DeleteRichMenuAlias 879 func TestCRUDRichMenuAlias(t *testing.T) { 880 type testMethod interface { 881 Test() 882 } 883 type want struct { 884 URLPath string 885 HTTPMethod string 886 Response interface{} 887 Error error 888 } 889 testCases := []struct { 890 TestMethod testMethod 891 RichMenuID string 892 RichMenuAliasID string 893 ResponseCode int 894 Response []byte 895 Want want 896 }{ 897 { 898 RichMenuID: "654321", 899 RichMenuAliasID: "richmenu-alias-create", 900 TestMethod: new(CreateRichMenuAliasCall), 901 ResponseCode: 200, 902 Response: []byte(`{}`), 903 Want: want{ 904 HTTPMethod: http.MethodPost, 905 URLPath: APIEndpointCreateRichMenuAlias, 906 Response: &BasicResponse{}, 907 }, 908 }, 909 { 910 RichMenuID: "N/A", 911 RichMenuAliasID: "richmenu-alias-get", 912 TestMethod: new(GetRichMenuAliasCall), 913 ResponseCode: 200, 914 Response: []byte(`{"richMenuAliasId":"richmenu-alias-get","richMenuId":"richmenu-88c05ef6921ae53f8b58a25f3a65faf7"}`), 915 Want: want{ 916 HTTPMethod: http.MethodGet, 917 URLPath: fmt.Sprintf(APIEndpointGetRichMenuAlias, "richmenu-alias-get"), 918 Response: &RichMenuAliasResponse{RichMenuAliasID: "richmenu-alias-get", RichMenuID: "richmenu-88c05ef6921ae53f8b58a25f3a65faf7"}, 919 }, 920 }, 921 { 922 RichMenuID: "123456", 923 RichMenuAliasID: "richmenu-alias-update", 924 TestMethod: new(UpdateRichMenuAliasCall), 925 ResponseCode: 200, 926 Response: []byte(`{}`), 927 Want: want{ 928 HTTPMethod: http.MethodPost, 929 URLPath: fmt.Sprintf(APIEndpointGetRichMenuAlias, "richmenu-alias-update"), 930 Response: &BasicResponse{}, 931 }, 932 }, 933 { 934 RichMenuID: "N/A", 935 RichMenuAliasID: "richmenu-alias-delete", 936 TestMethod: new(DeleteRichMenuAliasCall), 937 ResponseCode: 200, 938 Response: []byte(`{}`), 939 Want: want{ 940 HTTPMethod: http.MethodDelete, 941 URLPath: fmt.Sprintf(APIEndpointDeleteRichMenuAlias, "richmenu-alias-delete"), 942 Response: &BasicResponse{}, 943 }, 944 }, 945 } 946 947 var currentTestIdx int 948 server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 949 defer r.Body.Close() 950 tc := testCases[currentTestIdx] 951 if r.Method != tc.Want.HTTPMethod { 952 t.Errorf("Method %s; want %s", r.Method, tc.Want.HTTPMethod) 953 } 954 if r.URL.Path != tc.Want.URLPath { 955 t.Errorf("URLPath %s; want %s", r.URL.Path, tc.Want.URLPath) 956 } 957 _, err := io.ReadAll(r.Body) 958 if err != nil { 959 t.Fatal(err) 960 } 961 w.WriteHeader(tc.ResponseCode) 962 w.Write(tc.Response) 963 })) 964 defer server.Close() 965 966 dataServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 967 defer r.Body.Close() 968 t.Error("Unexpected data API call") 969 w.WriteHeader(404) 970 w.Write([]byte(`{"message":"Not found"}`)) 971 })) 972 defer dataServer.Close() 973 974 client, err := mockClient(server, dataServer) 975 if err != nil { 976 t.Fatal(err) 977 } 978 var res interface{} 979 for i, tc := range testCases { 980 currentTestIdx = i 981 t.Run(strconv.Itoa(i)+"/"+tc.RichMenuAliasID+"."+string(tc.Response), func(t *testing.T) { 982 switch tc.TestMethod.(type) { 983 case *CreateRichMenuAliasCall: 984 res, err = client.CreateRichMenuAlias(tc.RichMenuAliasID, tc.RichMenuID).Do() 985 case *GetRichMenuAliasCall: 986 res, err = client.GetRichMenuAlias(tc.RichMenuAliasID).Do() 987 case *UpdateRichMenuAliasCall: 988 res, err = client.UpdateRichMenuAlias(tc.RichMenuAliasID, tc.RichMenuID).Do() 989 case *DeleteRichMenuAliasCall: 990 res, err = client.DeleteRichMenuAlias(tc.RichMenuAliasID).Do() 991 } 992 if tc.Want.Error != nil { 993 if !reflect.DeepEqual(err, tc.Want.Error) { 994 t.Errorf("Error %v; want %v", err, tc.Want.Error) 995 } 996 } else { 997 if err != nil { 998 t.Error(err) 999 } 1000 } 1001 if tc.Want.Response != nil { 1002 if !reflect.DeepEqual(res, tc.Want.Response) { 1003 t.Errorf("Response %v; want %v", res, tc.Want.Response) 1004 } 1005 } 1006 }) 1007 } 1008 } 1009 1010 // TestListRichMenuAlias 1011 func TestListRichMenuAlias(t *testing.T) { 1012 type want struct { 1013 URLPath string 1014 Response []*RichMenuAliasResponse 1015 Error error 1016 } 1017 testCases := []struct { 1018 ResponseCode int 1019 Response []byte 1020 Want want 1021 }{ 1022 { 1023 ResponseCode: 200, 1024 Response: []byte(`{"aliases":[` + 1025 `{"richMenuAliasId":"richmenu-alias-a","richMenuId": "richmenu-862e6ad6c267d2ddf3f42bc78554f6a4"},` + 1026 `{"richMenuAliasId": "richmenu-alias-b","richMenuId": "richmenu-88c05ef6921ae53f8b58a25f3a65faf7"}` + 1027 `]}`), 1028 Want: want{ 1029 URLPath: APIEndpointListRichMenuAlias, 1030 Response: []*RichMenuAliasResponse{ 1031 { 1032 RichMenuAliasID: "richmenu-alias-a", 1033 RichMenuID: "richmenu-862e6ad6c267d2ddf3f42bc78554f6a4", 1034 }, 1035 { 1036 RichMenuAliasID: "richmenu-alias-b", 1037 RichMenuID: "richmenu-88c05ef6921ae53f8b58a25f3a65faf7", 1038 }, 1039 }, 1040 }, 1041 }, 1042 { 1043 ResponseCode: 200, 1044 Response: []byte(`{"aliases":[` + 1045 `]}`), 1046 Want: want{ 1047 URLPath: APIEndpointListRichMenuAlias, 1048 Response: []*RichMenuAliasResponse{}, 1049 }, 1050 }, 1051 } 1052 1053 var currentTestIdx int 1054 server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 1055 defer r.Body.Close() 1056 tc := testCases[currentTestIdx] 1057 if r.Method != http.MethodGet { 1058 t.Errorf("Method %s; want %s", r.Method, http.MethodGet) 1059 } 1060 if r.URL.Path != tc.Want.URLPath { 1061 t.Errorf("URLPath %s; want %s", r.URL.Path, tc.Want.URLPath) 1062 } 1063 _, err := io.ReadAll(r.Body) 1064 if err != nil { 1065 t.Fatal(err) 1066 } 1067 w.WriteHeader(tc.ResponseCode) 1068 w.Write(tc.Response) 1069 })) 1070 defer server.Close() 1071 1072 dataServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 1073 defer r.Body.Close() 1074 t.Error("Unexpected data API call") 1075 w.WriteHeader(404) 1076 w.Write([]byte(`{"message":"Not found"}`)) 1077 })) 1078 defer dataServer.Close() 1079 1080 client, err := mockClient(server, dataServer) 1081 if err != nil { 1082 t.Fatal(err) 1083 } 1084 for i, tc := range testCases { 1085 currentTestIdx = i 1086 t.Run(strconv.Itoa(i), func(t *testing.T) { 1087 res, err := client.GetRichMenuAliasList().Do() 1088 if tc.Want.Error != nil { 1089 if !reflect.DeepEqual(err, tc.Want.Error) { 1090 t.Errorf("Error %v; want %v", err, tc.Want.Error) 1091 } 1092 } else { 1093 if err != nil { 1094 t.Error(err) 1095 } 1096 } 1097 if tc.Want.Response != nil { 1098 if !reflect.DeepEqual(res, tc.Want.Response) { 1099 t.Errorf("Response\n %v; want\n %v", res, tc.Want.Response) 1100 } 1101 } 1102 }) 1103 } 1104 } 1105 1106 func TestValidateRichMenuObject(t *testing.T) { 1107 type want struct { 1108 RequestBody []byte 1109 Response *BasicResponse 1110 Error error 1111 } 1112 testCases := []struct { 1113 Request RichMenu 1114 Response []byte 1115 ResponseCode int 1116 Want want 1117 }{ 1118 { 1119 Request: RichMenu{ 1120 Size: RichMenuSize{Width: 2500, Height: 1686}, 1121 Selected: false, 1122 Name: "Menu1", 1123 ChatBarText: "ChatText", 1124 Areas: []AreaDetail{ 1125 { 1126 Bounds: RichMenuBounds{X: 0, Y: 0, Width: 2500, Height: 1686}, 1127 Action: RichMenuAction{Type: RichMenuActionTypePostback, Data: "action=buy&itemid=123", DisplayText: "Buy", Label: "Buy"}, 1128 }, 1129 }, 1130 }, 1131 ResponseCode: 200, 1132 Response: []byte(`{}`), 1133 Want: want{ 1134 RequestBody: []byte(`{"size":{"width":2500,"height":1686},"selected":false,"name":"Menu1","chatBarText":"ChatText","areas":[{"bounds":{"x":0,"y":0,"width":2500,"height":1686},"action":{"type":"postback","displayText":"Buy","label":"Buy","data":"action=buy\u0026itemid=123"}}]}` + "\n"), 1135 Response: &BasicResponse{}, 1136 }, 1137 }, 1138 } 1139 1140 var currentTestIdx int 1141 server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 1142 defer r.Body.Close() 1143 tc := testCases[currentTestIdx] 1144 if r.Method != http.MethodPost { 1145 t.Errorf("Method %s; want %s", r.Method, http.MethodPost) 1146 } 1147 if r.URL.Path != APIEndpointValidateRichMenuObject { 1148 t.Errorf("URLPath %s; want %s", r.URL.Path, APIEndpointValidateRichMenuObject) 1149 } 1150 body, err := io.ReadAll(r.Body) 1151 if err != nil { 1152 t.Fatal(err) 1153 } 1154 if !reflect.DeepEqual(body, tc.Want.RequestBody) { 1155 t.Errorf("RequestBody\n %s; want\n %s", body, tc.Want.RequestBody) 1156 } 1157 w.WriteHeader(tc.ResponseCode) 1158 w.Write(tc.Response) 1159 })) 1160 defer server.Close() 1161 1162 dataServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 1163 defer r.Body.Close() 1164 t.Error("Unexpected data API call") 1165 w.WriteHeader(404) 1166 w.Write([]byte(`{"message":"Not found"}`)) 1167 })) 1168 defer dataServer.Close() 1169 1170 client, err := mockClient(server, dataServer) 1171 if err != nil { 1172 t.Fatal(err) 1173 } 1174 for i, tc := range testCases { 1175 currentTestIdx = i 1176 t.Run(strconv.Itoa(i), func(t *testing.T) { 1177 res, err := client.ValidateRichMenuObject(tc.Request).Do() 1178 if tc.Want.Error != nil { 1179 if !reflect.DeepEqual(err, tc.Want.Error) { 1180 t.Errorf("Error %v; want %v", err, tc.Want.Error) 1181 } 1182 } else { 1183 if err != nil { 1184 t.Error(err) 1185 } 1186 } 1187 if tc.Want.Response != nil { 1188 if !reflect.DeepEqual(res, tc.Want.Response) { 1189 t.Errorf("Response %v; want %v", res, tc.Want.Response) 1190 } 1191 } 1192 }) 1193 } 1194 }