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  }