github.com/seeker-insurance/kit@v0.0.13/jsonapi/response_test.go (about) 1 package jsonapi 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "reflect" 7 "sort" 8 "testing" 9 "time" 10 ) 11 12 func TestMarshalPayload(t *testing.T) { 13 book := &Book{ID: 1} 14 books := []*Book{book, {ID: 2}} 15 var jsonData map[string]interface{} 16 17 // One 18 out1 := bytes.NewBuffer(nil) 19 MarshalPayload(out1, book) 20 21 if err := json.Unmarshal(out1.Bytes(), &jsonData); err != nil { 22 t.Fatal(err) 23 } 24 if _, ok := jsonData["data"].(map[string]interface{}); !ok { 25 t.Fatalf("data key did not contain an Hash/Dict/Map") 26 } 27 28 // Many 29 out2 := bytes.NewBuffer(nil) 30 MarshalPayload(out2, books) 31 32 if err := json.Unmarshal(out2.Bytes(), &jsonData); err != nil { 33 t.Fatal(err) 34 } 35 if _, ok := jsonData["data"].([]interface{}); !ok { 36 t.Fatalf("data key did not contain an Array") 37 } 38 } 39 40 func TestMarshalPayloadWithNulls(t *testing.T) { 41 42 books := []*Book{nil, {ID:101}, nil} 43 var jsonData map[string]interface{} 44 45 46 out := bytes.NewBuffer(nil) 47 if err := MarshalPayload(out, books); err != nil { 48 t.Fatal(err) 49 } 50 51 if err := json.Unmarshal(out.Bytes(), &jsonData); err != nil { 52 t.Fatal(err) 53 } 54 raw, ok := jsonData["data"] 55 if !ok { 56 t.Fatalf("data key does not exist") 57 } 58 arr, ok := raw.([]interface{}) 59 if !ok { 60 t.Fatalf("data is not an Array") 61 } 62 for i := 0; i < len(arr); i++ { 63 if books[i] == nil && arr[i] != nil || 64 books[i] != nil && arr[i] == nil { 65 t.Fatalf("restored data is not equal to source") 66 } 67 } 68 } 69 70 func TestMarshal_attrStringSlice(t *testing.T) { 71 tags := []string{"fiction", "sale"} 72 b := &Book{ID: 1, Tags: tags} 73 74 out := bytes.NewBuffer(nil) 75 if err := MarshalPayload(out, b); err != nil { 76 t.Fatal(err) 77 } 78 79 var jsonData map[string]interface{} 80 if err := json.Unmarshal(out.Bytes(), &jsonData); err != nil { 81 t.Fatal(err) 82 } 83 84 jsonTags := jsonData["data"].(map[string]interface{})["attributes"].(map[string]interface{})["tags"].([]interface{}) 85 if e, a := len(tags), len(jsonTags); e != a { 86 t.Fatalf("Was expecting tags of length %d got %d", e, a) 87 } 88 89 // Convert from []interface{} to []string 90 jsonTagsStrings := []string{} 91 for _, tag := range jsonTags { 92 jsonTagsStrings = append(jsonTagsStrings, tag.(string)) 93 } 94 95 // Sort both 96 sort.Strings(jsonTagsStrings) 97 sort.Strings(tags) 98 99 for i, tag := range tags { 100 if e, a := tag, jsonTagsStrings[i]; e != a { 101 t.Fatalf("At index %d, was expecting %s got %s", i, e, a) 102 } 103 } 104 } 105 106 func TestWithoutOmitsEmptyAnnotationOnRelation(t *testing.T) { 107 blog := &Blog{} 108 109 out := bytes.NewBuffer(nil) 110 if err := MarshalPayload(out, blog); err != nil { 111 t.Fatal(err) 112 } 113 114 var jsonData map[string]interface{} 115 if err := json.Unmarshal(out.Bytes(), &jsonData); err != nil { 116 t.Fatal(err) 117 } 118 relationships := jsonData["data"].(map[string]interface{})["relationships"].(map[string]interface{}) 119 120 // Verifiy the "posts" relation was an empty array 121 posts, ok := relationships["posts"] 122 if !ok { 123 t.Fatal("Was expecting the data.relationships.posts key/value to have been present") 124 } 125 postsMap, ok := posts.(map[string]interface{}) 126 if !ok { 127 t.Fatal("data.relationships.posts was not a map") 128 } 129 postsData, ok := postsMap["data"] 130 if !ok { 131 t.Fatal("Was expecting the data.relationships.posts.data key/value to have been present") 132 } 133 postsDataSlice, ok := postsData.([]interface{}) 134 if !ok { 135 t.Fatal("data.relationships.posts.data was not a slice []") 136 } 137 if len(postsDataSlice) != 0 { 138 t.Fatal("Was expecting the data.relationships.posts.data value to have been an empty array []") 139 } 140 141 // Verifiy the "current_post" was a null 142 currentPost, postExists := relationships["current_post"] 143 if !postExists { 144 t.Fatal("Was expecting the data.relationships.current_post key/value to have NOT been omitted") 145 } 146 currentPostMap, ok := currentPost.(map[string]interface{}) 147 if !ok { 148 t.Fatal("data.relationships.current_post was not a map") 149 } 150 currentPostData, ok := currentPostMap["data"] 151 if !ok { 152 t.Fatal("Was expecting the data.relationships.current_post.data key/value to have been present") 153 } 154 if currentPostData != nil { 155 t.Fatal("Was expecting the data.relationships.current_post.data value to have been nil/null") 156 } 157 } 158 159 func TestWithOmitsEmptyAnnotationOnRelation(t *testing.T) { 160 type BlogOptionalPosts struct { 161 ID int `jsonapi:"primary,blogs"` 162 Title string `jsonapi:"attr,title"` 163 Posts []*Post `jsonapi:"relation,posts,omitempty"` 164 CurrentPost *Post `jsonapi:"relation,current_post,omitempty"` 165 } 166 167 blog := &BlogOptionalPosts{ID: 999} 168 169 out := bytes.NewBuffer(nil) 170 if err := MarshalPayload(out, blog); err != nil { 171 t.Fatal(err) 172 } 173 174 var jsonData map[string]interface{} 175 if err := json.Unmarshal(out.Bytes(), &jsonData); err != nil { 176 t.Fatal(err) 177 } 178 payload := jsonData["data"].(map[string]interface{}) 179 180 // Verify relationship was NOT set 181 if val, exists := payload["relationships"]; exists { 182 t.Fatalf("Was expecting the data.relationships key/value to have been empty - it was not and had a value of %v", val) 183 } 184 } 185 186 func TestWithOmitsEmptyAnnotationOnRelation_MixedData(t *testing.T) { 187 type BlogOptionalPosts struct { 188 ID int `jsonapi:"primary,blogs"` 189 Title string `jsonapi:"attr,title"` 190 Posts []*Post `jsonapi:"relation,posts,omitempty"` 191 CurrentPost *Post `jsonapi:"relation,current_post,omitempty"` 192 } 193 194 blog := &BlogOptionalPosts{ 195 ID: 999, 196 CurrentPost: &Post{ 197 ID: 123, 198 }, 199 } 200 201 out := bytes.NewBuffer(nil) 202 if err := MarshalPayload(out, blog); err != nil { 203 t.Fatal(err) 204 } 205 206 var jsonData map[string]interface{} 207 if err := json.Unmarshal(out.Bytes(), &jsonData); err != nil { 208 t.Fatal(err) 209 } 210 payload := jsonData["data"].(map[string]interface{}) 211 212 // Verify relationship was set 213 if _, exists := payload["relationships"]; !exists { 214 t.Fatal("Was expecting the data.relationships key/value to have NOT been empty") 215 } 216 217 relationships := payload["relationships"].(map[string]interface{}) 218 219 // Verify the relationship was not omitted, and is not null 220 if val, exists := relationships["current_post"]; !exists { 221 t.Fatal("Was expecting the data.relationships.current_post key/value to have NOT been omitted") 222 } else if val.(map[string]interface{})["data"] == nil { 223 t.Fatal("Was expecting the data.relationships.current_post value to have NOT been nil/null") 224 } 225 } 226 227 func TestWithOmitsEmptyAnnotationOnAttribute(t *testing.T) { 228 type Phone struct { 229 Number string `json:"number"` 230 } 231 232 type Address struct { 233 City string `json:"city"` 234 Street string `json:"street"` 235 } 236 237 type Tags map[string]int 238 239 type Author struct { 240 ID int `jsonapi:"primary,authors"` 241 Name string `jsonapi:"attr,title"` 242 Phones []*Phone `jsonapi:"attr,phones,omitempty"` 243 Address *Address `jsonapi:"attr,address,omitempty"` 244 Tags Tags `jsonapi:"attr,tags,omitempty"` 245 } 246 247 author := &Author{ 248 ID: 999, 249 Name: "Igor", 250 Phones: nil, // should be omitted 251 Address: nil, // should be omitted 252 Tags: Tags{"dogs": 1, "cats": 2}, // should not be omitted 253 } 254 255 out := bytes.NewBuffer(nil) 256 if err := MarshalPayload(out, author); err != nil { 257 t.Fatal(err) 258 } 259 260 var jsonData map[string]interface{} 261 if err := json.Unmarshal(out.Bytes(), &jsonData); err != nil { 262 t.Fatal(err) 263 } 264 265 // Verify that there is no field "phones" in attributes 266 payload := jsonData["data"].(map[string]interface{}) 267 attributes := payload["attributes"].(map[string]interface{}) 268 if _, ok := attributes["title"]; !ok { 269 t.Fatal("Was expecting the data.attributes.title to have NOT been omitted") 270 } 271 if _, ok := attributes["phones"]; ok { 272 t.Fatal("Was expecting the data.attributes.phones to have been omitted") 273 } 274 if _, ok := attributes["address"]; ok { 275 t.Fatal("Was expecting the data.attributes.phones to have been omitted") 276 } 277 if _, ok := attributes["tags"]; !ok { 278 t.Fatal("Was expecting the data.attributes.tags to have NOT been omitted") 279 } 280 } 281 282 func TestMarshalIDPtr(t *testing.T) { 283 id, make, model := "123e4567-e89b-12d3-a456-426655440000", "Ford", "Mustang" 284 car := &Car{ 285 ID: &id, 286 Make: &make, 287 Model: &model, 288 } 289 290 out := bytes.NewBuffer(nil) 291 if err := MarshalPayload(out, car); err != nil { 292 t.Fatal(err) 293 } 294 295 var jsonData map[string]interface{} 296 if err := json.Unmarshal(out.Bytes(), &jsonData); err != nil { 297 t.Fatal(err) 298 } 299 data := jsonData["data"].(map[string]interface{}) 300 // attributes := data["attributes"].(map[string]interface{}) 301 302 // Verify that the ID was sent 303 val, exists := data["id"] 304 if !exists { 305 t.Fatal("Was expecting the data.id member to exist") 306 } 307 if val != id { 308 t.Fatalf("Was expecting the data.id member to be `%s`, got `%s`", id, val) 309 } 310 } 311 312 func TestMarshalOnePayload_omitIDString(t *testing.T) { 313 type Foo struct { 314 ID string `jsonapi:"primary,foo"` 315 Title string `jsonapi:"attr,title"` 316 } 317 318 foo := &Foo{Title: "Foo"} 319 out := bytes.NewBuffer(nil) 320 if err := MarshalPayload(out, foo); err != nil { 321 t.Fatal(err) 322 } 323 324 var jsonData map[string]interface{} 325 if err := json.Unmarshal(out.Bytes(), &jsonData); err != nil { 326 t.Fatal(err) 327 } 328 payload := jsonData["data"].(map[string]interface{}) 329 330 // Verify that empty ID of type string gets omitted. See: 331 // https://github.com/google/jsonapi/issues/83#issuecomment-285611425 332 _, ok := payload["id"] 333 if ok { 334 t.Fatal("Was expecting the data.id member to be omitted") 335 } 336 } 337 338 func TestMarshall_invalidIDType(t *testing.T) { 339 type badIDStruct struct { 340 ID *bool `jsonapi:"primary,cars"` 341 } 342 id := true 343 o := &badIDStruct{ID: &id} 344 345 out := bytes.NewBuffer(nil) 346 if err := MarshalPayload(out, o); err != ErrBadJSONAPIID { 347 t.Fatalf( 348 "Was expecting a `%s` error, got `%s`", ErrBadJSONAPIID, err, 349 ) 350 } 351 } 352 353 func TestOmitsEmptyAnnotation(t *testing.T) { 354 book := &Book{ 355 Author: "aren55555", 356 PublishedAt: time.Now().AddDate(0, -1, 0), 357 } 358 359 out := bytes.NewBuffer(nil) 360 if err := MarshalPayload(out, book); err != nil { 361 t.Fatal(err) 362 } 363 364 var jsonData map[string]interface{} 365 if err := json.Unmarshal(out.Bytes(), &jsonData); err != nil { 366 t.Fatal(err) 367 } 368 attributes := jsonData["data"].(map[string]interface{})["attributes"].(map[string]interface{}) 369 370 // Verify that the specifically omitted field were omitted 371 if val, exists := attributes["title"]; exists { 372 t.Fatalf("Was expecting the data.attributes.title key/value to have been omitted - it was not and had a value of %v", val) 373 } 374 if val, exists := attributes["pages"]; exists { 375 t.Fatalf("Was expecting the data.attributes.pages key/value to have been omitted - it was not and had a value of %v", val) 376 } 377 378 // Verify the implicitly omitted fields were omitted 379 if val, exists := attributes["PublishedAt"]; exists { 380 t.Fatalf("Was expecting the data.attributes.PublishedAt key/value to have been implicitly omitted - it was not and had a value of %v", val) 381 } 382 383 // Verify the unset fields were not omitted 384 if _, exists := attributes["isbn"]; !exists { 385 t.Fatal("Was expecting the data.attributes.isbn key/value to have NOT been omitted") 386 } 387 } 388 389 func TestHasPrimaryAnnotation(t *testing.T) { 390 testModel := &Blog{ 391 ID: 5, 392 Title: "Title 1", 393 CreatedAt: time.Now(), 394 } 395 396 out := bytes.NewBuffer(nil) 397 if err := MarshalPayload(out, testModel); err != nil { 398 t.Fatal(err) 399 } 400 401 resp := new(OnePayload) 402 403 if err := json.NewDecoder(out).Decode(resp); err != nil { 404 t.Fatal(err) 405 } 406 407 data := resp.Data 408 409 if data.Type != "blogs" { 410 t.Fatalf("type should have been blogs, got %s", data.Type) 411 } 412 413 if data.ID != "5" { 414 t.Fatalf("ID not transferred") 415 } 416 } 417 418 func TestSupportsAttributes(t *testing.T) { 419 testModel := &Blog{ 420 ID: 5, 421 Title: "Title 1", 422 CreatedAt: time.Now(), 423 } 424 425 out := bytes.NewBuffer(nil) 426 if err := MarshalPayload(out, testModel); err != nil { 427 t.Fatal(err) 428 } 429 430 resp := new(OnePayload) 431 if err := json.NewDecoder(out).Decode(resp); err != nil { 432 t.Fatal(err) 433 } 434 435 data := resp.Data 436 437 if data.Attributes == nil { 438 t.Fatalf("Expected attributes") 439 } 440 441 if data.Attributes["title"] != "Title 1" { 442 t.Fatalf("Attributes hash not populated using tags correctly") 443 } 444 } 445 446 func TestOmitsZeroTimes(t *testing.T) { 447 testModel := &Blog{ 448 ID: 5, 449 Title: "Title 1", 450 CreatedAt: time.Time{}, 451 } 452 453 out := bytes.NewBuffer(nil) 454 if err := MarshalPayload(out, testModel); err != nil { 455 t.Fatal(err) 456 } 457 458 resp := new(OnePayload) 459 if err := json.NewDecoder(out).Decode(resp); err != nil { 460 t.Fatal(err) 461 } 462 463 data := resp.Data 464 465 if data.Attributes == nil { 466 t.Fatalf("Expected attributes") 467 } 468 469 if data.Attributes["created_at"] != nil { 470 t.Fatalf("Created at was serialized even though it was a zero Time") 471 } 472 } 473 474 func TestMarshalISO8601Time(t *testing.T) { 475 testModel := &Timestamp{ 476 ID: 5, 477 Time: time.Date(2016, 8, 17, 8, 27, 12, 23849, time.UTC), 478 } 479 480 out := bytes.NewBuffer(nil) 481 if err := MarshalPayload(out, testModel); err != nil { 482 t.Fatal(err) 483 } 484 485 resp := new(OnePayload) 486 if err := json.NewDecoder(out).Decode(resp); err != nil { 487 t.Fatal(err) 488 } 489 490 data := resp.Data 491 492 if data.Attributes == nil { 493 t.Fatalf("Expected attributes") 494 } 495 496 if data.Attributes["timestamp"] != "2016-08-17T08:27:12Z" { 497 t.Fatal("Timestamp was not serialised into ISO8601 correctly") 498 } 499 } 500 501 func TestMarshalISO8601TimePointer(t *testing.T) { 502 tm := time.Date(2016, 8, 17, 8, 27, 12, 23849, time.UTC) 503 testModel := &Timestamp{ 504 ID: 5, 505 Next: &tm, 506 } 507 508 out := bytes.NewBuffer(nil) 509 if err := MarshalPayload(out, testModel); err != nil { 510 t.Fatal(err) 511 } 512 513 resp := new(OnePayload) 514 if err := json.NewDecoder(out).Decode(resp); err != nil { 515 t.Fatal(err) 516 } 517 518 data := resp.Data 519 520 if data.Attributes == nil { 521 t.Fatalf("Expected attributes") 522 } 523 524 if data.Attributes["next"] != "2016-08-17T08:27:12Z" { 525 t.Fatal("Next was not serialised into ISO8601 correctly") 526 } 527 } 528 529 func TestSupportsLinkable(t *testing.T) { 530 testModel := &Blog{ 531 ID: 5, 532 Title: "Title 1", 533 CreatedAt: time.Now(), 534 } 535 536 out := bytes.NewBuffer(nil) 537 if err := MarshalPayload(out, testModel); err != nil { 538 t.Fatal(err) 539 } 540 541 resp := new(OnePayload) 542 if err := json.NewDecoder(out).Decode(resp); err != nil { 543 t.Fatal(err) 544 } 545 546 data := resp.Data 547 548 if data.Links == nil { 549 t.Fatal("Expected data.links") 550 } 551 links := *data.Links 552 553 self, hasSelf := links["self"] 554 if !hasSelf { 555 t.Fatal("Expected 'self' link to be present") 556 } 557 if _, isString := self.(string); !isString { 558 t.Fatal("Expected 'self' to contain a string") 559 } 560 561 comments, hasComments := links["comments"] 562 if !hasComments { 563 t.Fatal("expect 'comments' to be present") 564 } 565 commentsMap, isMap := comments.(map[string]interface{}) 566 if !isMap { 567 t.Fatal("Expected 'comments' to contain a map") 568 } 569 570 commentsHref, hasHref := commentsMap["href"] 571 if !hasHref { 572 t.Fatal("Expect 'comments' to contain an 'href' key/value") 573 } 574 if _, isString := commentsHref.(string); !isString { 575 t.Fatal("Expected 'href' to contain a string") 576 } 577 578 commentsMeta, hasMeta := commentsMap["meta"] 579 if !hasMeta { 580 t.Fatal("Expect 'comments' to contain a 'meta' key/value") 581 } 582 commentsMetaMap, isMap := commentsMeta.(map[string]interface{}) 583 if !isMap { 584 t.Fatal("Expected 'comments' to contain a map") 585 } 586 587 commentsMetaObject := Meta(commentsMetaMap) 588 countsMap, isMap := commentsMetaObject["counts"].(map[string]interface{}) 589 if !isMap { 590 t.Fatal("Expected 'counts' to contain a map") 591 } 592 for k, v := range countsMap { 593 if _, isNum := v.(float64); !isNum { 594 t.Fatalf("Exepected value at '%s' to be a numeric (float64)", k) 595 } 596 } 597 } 598 599 func TestInvalidLinkable(t *testing.T) { 600 testModel := &BadComment{ 601 ID: 5, 602 Body: "Hello World", 603 } 604 605 out := bytes.NewBuffer(nil) 606 if err := MarshalPayload(out, testModel); err == nil { 607 t.Fatal("Was expecting an error") 608 } 609 } 610 611 func TestSupportsMetable(t *testing.T) { 612 testModel := &Blog{ 613 ID: 5, 614 Title: "Title 1", 615 CreatedAt: time.Now(), 616 } 617 618 out := bytes.NewBuffer(nil) 619 if err := MarshalPayload(out, testModel); err != nil { 620 t.Fatal(err) 621 } 622 623 resp := new(OnePayload) 624 if err := json.NewDecoder(out).Decode(resp); err != nil { 625 t.Fatal(err) 626 } 627 628 data := resp.Data 629 if data.Meta == nil { 630 t.Fatalf("Expected data.meta") 631 } 632 633 meta := Meta(*data.Meta) 634 if e, a := "extra details regarding the blog", meta["detail"]; e != a { 635 t.Fatalf("Was expecting meta.detail to be %q, got %q", e, a) 636 } 637 } 638 639 func TestRelations(t *testing.T) { 640 testModel := testBlog() 641 642 out := bytes.NewBuffer(nil) 643 if err := MarshalPayload(out, testModel); err != nil { 644 t.Fatal(err) 645 } 646 647 resp := new(OnePayload) 648 if err := json.NewDecoder(out).Decode(resp); err != nil { 649 t.Fatal(err) 650 } 651 652 relations := resp.Data.Relationships 653 654 if relations == nil { 655 t.Fatalf("Relationships were not materialized") 656 } 657 658 if relations["posts"] == nil { 659 t.Fatalf("Posts relationship was not materialized") 660 } else { 661 if relations["posts"].(map[string]interface{})["links"] == nil { 662 t.Fatalf("Posts relationship links were not materialized") 663 } 664 if relations["posts"].(map[string]interface{})["meta"] == nil { 665 t.Fatalf("Posts relationship meta were not materialized") 666 } 667 } 668 669 if relations["current_post"] == nil { 670 t.Fatalf("Current post relationship was not materialized") 671 } else { 672 if relations["current_post"].(map[string]interface{})["links"] == nil { 673 t.Fatalf("Current post relationship links were not materialized") 674 } 675 if relations["current_post"].(map[string]interface{})["meta"] == nil { 676 t.Fatalf("Current post relationship meta were not materialized") 677 } 678 } 679 680 if len(relations["posts"].(map[string]interface{})["data"].([]interface{})) != 2 { 681 t.Fatalf("Did not materialize two posts") 682 } 683 } 684 685 func TestForcedEmbed(t *testing.T) { 686 testModel := &Blog{ 687 ID: 5, 688 Title: "Title 1", 689 CreatedAt: time.Now(), 690 R: &blogR{ 691 Comment: &Comment{ 692 ID: 99, 693 Body: "eyecue", 694 }, 695 }, 696 } 697 698 out := bytes.NewBuffer(nil) 699 if err := MarshalPayload(out, testModel); err != nil { 700 t.Fatal(err) 701 } 702 703 resp := new(OnePayload) 704 705 if err := json.NewDecoder(out).Decode(resp); err != nil { 706 t.Fatal(err) 707 } 708 709 data := resp.Data 710 711 if rel, ok := data.Relationships["comment"]; ok { 712 relMap := rel.(map[string]interface{}) 713 if relMap["data"].(map[string]interface{})["id"] != "99" { 714 t.Fatalf("expected comment relation to have id 99, got %v", relMap["id"]) 715 } 716 } else { 717 t.Fatalf("expected comment relation") 718 } 719 720 if resp.Included[0].Attributes["body"] != "eyecue" { 721 t.Fatalf("included arr should be eyecue, got %s", resp.Included[0].Attributes["body"]) 722 } 723 } 724 725 func TestNoRelations(t *testing.T) { 726 testModel := &Blog{ID: 1, Title: "Title 1", CreatedAt: time.Now()} 727 728 out := bytes.NewBuffer(nil) 729 if err := MarshalPayload(out, testModel); err != nil { 730 t.Fatal(err) 731 } 732 733 resp := new(OnePayload) 734 if err := json.NewDecoder(out).Decode(resp); err != nil { 735 t.Fatal(err) 736 } 737 738 if resp.Included != nil { 739 t.Fatalf("Encoding json response did not omit included") 740 } 741 } 742 743 func TestMarshalPayloadWithoutIncluded(t *testing.T) { 744 data := &Post{ 745 ID: 1, 746 BlogID: 2, 747 ClientID: "123e4567-e89b-12d3-a456-426655440000", 748 Title: "Foo", 749 Body: "Bar", 750 Comments: []*Comment{ 751 { 752 ID: 20, 753 Body: "First", 754 }, 755 { 756 ID: 21, 757 Body: "Hello World", 758 }, 759 }, 760 LatestComment: &Comment{ 761 ID: 22, 762 Body: "Cool!", 763 }, 764 } 765 766 out := bytes.NewBuffer(nil) 767 if err := MarshalPayloadWithoutIncluded(out, data); err != nil { 768 t.Fatal(err) 769 } 770 771 resp := new(OnePayload) 772 if err := json.NewDecoder(out).Decode(resp); err != nil { 773 t.Fatal(err) 774 } 775 776 if resp.Included != nil { 777 t.Fatalf("Encoding json response did not omit included") 778 } 779 } 780 781 func TestMarshalPayload_many(t *testing.T) { 782 data := []interface{}{ 783 &Blog{ 784 ID: 5, 785 Title: "Title 1", 786 CreatedAt: time.Now(), 787 Posts: []*Post{ 788 { 789 ID: 1, 790 Title: "Foo", 791 Body: "Bar", 792 }, 793 { 794 ID: 2, 795 Title: "Fuubar", 796 Body: "Bas", 797 }, 798 }, 799 CurrentPost: &Post{ 800 ID: 1, 801 Title: "Foo", 802 Body: "Bar", 803 }, 804 }, 805 &Blog{ 806 ID: 6, 807 Title: "Title 2", 808 CreatedAt: time.Now(), 809 Posts: []*Post{ 810 { 811 ID: 3, 812 Title: "Foo", 813 Body: "Bar", 814 }, 815 { 816 ID: 4, 817 Title: "Fuubar", 818 Body: "Bas", 819 }, 820 }, 821 CurrentPost: &Post{ 822 ID: 4, 823 Title: "Foo", 824 Body: "Bar", 825 }, 826 }, 827 } 828 829 out := bytes.NewBuffer(nil) 830 if err := MarshalPayload(out, data); err != nil { 831 t.Fatal(err) 832 } 833 834 resp := new(ManyPayload) 835 if err := json.NewDecoder(out).Decode(resp); err != nil { 836 t.Fatal(err) 837 } 838 839 d := resp.Data 840 841 if len(d) != 2 { 842 t.Fatalf("data should have two elements") 843 } 844 } 845 846 func TestMarshalMany_WithSliceOfStructPointers(t *testing.T) { 847 var data []*Blog 848 for len(data) < 2 { 849 data = append(data, testBlog()) 850 } 851 852 out := bytes.NewBuffer(nil) 853 if err := MarshalPayload(out, data); err != nil { 854 t.Fatal(err) 855 } 856 857 resp := new(ManyPayload) 858 if err := json.NewDecoder(out).Decode(resp); err != nil { 859 t.Fatal(err) 860 } 861 862 d := resp.Data 863 864 if len(d) != 2 { 865 t.Fatalf("data should have two elements") 866 } 867 } 868 869 func TestMarshalManyWithoutIncluded(t *testing.T) { 870 var data []*Blog 871 for len(data) < 2 { 872 data = append(data, testBlog()) 873 } 874 875 out := bytes.NewBuffer(nil) 876 if err := MarshalPayloadWithoutIncluded(out, data); err != nil { 877 t.Fatal(err) 878 } 879 880 resp := new(ManyPayload) 881 if err := json.NewDecoder(out).Decode(resp); err != nil { 882 t.Fatal(err) 883 } 884 885 d := resp.Data 886 887 if len(d) != 2 { 888 t.Fatalf("data should have two elements") 889 } 890 891 if resp.Included != nil { 892 t.Fatalf("Encoding json response did not omit included") 893 } 894 } 895 896 func TestMarshalMany_SliceOfInterfaceAndSliceOfStructsSameJSON(t *testing.T) { 897 structs := []*Book{ 898 {ID: 1, Author: "aren55555", ISBN: "abc"}, 899 {ID: 2, Author: "shwoodard", ISBN: "xyz"}, 900 } 901 interfaces := []interface{}{} 902 for _, s := range structs { 903 interfaces = append(interfaces, s) 904 } 905 906 // Perform Marshals 907 structsOut := new(bytes.Buffer) 908 if err := MarshalPayload(structsOut, structs); err != nil { 909 t.Fatal(err) 910 } 911 interfacesOut := new(bytes.Buffer) 912 if err := MarshalPayload(interfacesOut, interfaces); err != nil { 913 t.Fatal(err) 914 } 915 916 // Generic JSON Unmarshal 917 structsData, interfacesData := 918 make(map[string]interface{}), make(map[string]interface{}) 919 if err := json.Unmarshal(structsOut.Bytes(), &structsData); err != nil { 920 t.Fatal(err) 921 } 922 if err := json.Unmarshal(interfacesOut.Bytes(), &interfacesData); err != nil { 923 t.Fatal(err) 924 } 925 926 // Compare Result 927 if !reflect.DeepEqual(structsData, interfacesData) { 928 t.Fatal("Was expecting the JSON API generated to be the same") 929 } 930 } 931 932 func TestMarshal_InvalidIntefaceArgument(t *testing.T) { 933 out := new(bytes.Buffer) 934 if err := MarshalPayload(out, true); err != ErrUnexpectedType { 935 t.Fatal("Was expecting an error") 936 } 937 if err := MarshalPayload(out, 25); err != ErrUnexpectedType { 938 t.Fatal("Was expecting an error") 939 } 940 if err := MarshalPayload(out, Book{}); err != ErrUnexpectedType { 941 t.Fatal("Was expecting an error") 942 } 943 }