Skip to content

Commit ed8377a

Browse files
committed
increase test coverage
1 parent 909aa8d commit ed8377a

16 files changed

+435
-169
lines changed

api.go

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@ func (res *resource) handleReplaceRelation(c APIContexter, w http.ResponseWriter
702702
editObj = response.Result()
703703
}
704704

705-
err = jsonapi.UnmarshalRelationshipsData(editObj, relation.Name, data)
705+
err = processRelationshipsData(data, relation.Name, editObj)
706706
if err != nil {
707707
return err
708708
}
@@ -1101,3 +1101,57 @@ func handleError(err error, w http.ResponseWriter, r *http.Request, marshalers m
11011101

11021102
writeResult(w, []byte(marshaler.MarshalError(err)), http.StatusInternalServerError, contentType)
11031103
}
1104+
1105+
func processRelationshipsData(data interface{}, linkName string, target interface{}) error {
1106+
hasOne, ok := data.(map[string]interface{})
1107+
if ok {
1108+
hasOneID, ok := hasOne["id"].(string)
1109+
if !ok {
1110+
return fmt.Errorf("data object must have a field id for %s", linkName)
1111+
}
1112+
1113+
target, ok := target.(jsonapi.UnmarshalToOneRelations)
1114+
if !ok {
1115+
return errors.New("target struct must implement interface UnmarshalToOneRelations")
1116+
}
1117+
1118+
target.SetToOneReferenceID(linkName, hasOneID)
1119+
} else if data == nil {
1120+
// this means that a to-one relationship must be deleted
1121+
target, ok := target.(jsonapi.UnmarshalToOneRelations)
1122+
if !ok {
1123+
return errors.New("target struct must implement interface UnmarshalToOneRelations")
1124+
}
1125+
1126+
target.SetToOneReferenceID(linkName, "")
1127+
} else {
1128+
hasMany, ok := data.([]interface{})
1129+
if !ok {
1130+
return fmt.Errorf("invalid data object or array, must be an object with \"id\" and \"type\" field for %s", linkName)
1131+
}
1132+
1133+
target, ok := target.(jsonapi.UnmarshalToManyRelations)
1134+
if !ok {
1135+
return errors.New("target struct must implement interface UnmarshalToManyRelations")
1136+
}
1137+
1138+
hasManyIDs := []string{}
1139+
1140+
for _, entry := range hasMany {
1141+
data, ok := entry.(map[string]interface{})
1142+
if !ok {
1143+
return fmt.Errorf("entry in data array must be an object for %s", linkName)
1144+
}
1145+
dataID, ok := data["id"].(string)
1146+
if !ok {
1147+
return fmt.Errorf("all data objects must have a field id for %s", linkName)
1148+
}
1149+
1150+
hasManyIDs = append(hasManyIDs, dataID)
1151+
}
1152+
1153+
target.SetToManyReferenceIDs(linkName, hasManyIDs)
1154+
}
1155+
1156+
return nil
1157+
}

api_public.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -59,23 +59,6 @@ func (api *API) UseMiddleware(middleware ...HandlerFunc) {
5959
api.middlewares = append(api.middlewares, middleware...)
6060
}
6161

62-
// SetRedirectTrailingSlash enables 307 redirects on urls ending with /
63-
// when disabled, an URL ending with / will 404
64-
// this will and should work only if using the default router
65-
// DEPRECATED
66-
func (api *API) SetRedirectTrailingSlash(enabled bool) {
67-
if api.router == nil {
68-
panic("router must not be nil")
69-
}
70-
71-
httpRouter, ok := api.router.(*routing.HTTPRouter)
72-
if !ok {
73-
panic("can not set redirectTrailingSlashes if not using the internal httpRouter")
74-
}
75-
76-
httpRouter.SetRedirectTrailingSlash(enabled)
77-
}
78-
7962
// NewAPIWithMarshalling does the same as NewAPIWithBaseURL with the addition
8063
// of a set of marshalers that provide a way to interact with clients that
8164
// use a serialization format other than JSON. The marshalers map is indexed

api_test.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"strings"
1212

1313
"github.com/manyminds/api2go/jsonapi"
14+
"github.com/manyminds/api2go/routing"
1415
. "github.com/onsi/ginkgo"
1516
. "github.com/onsi/gomega"
1617
"gopkg.in/guregu/null.v2"
@@ -620,6 +621,10 @@ var _ = Describe("RestHandler", func() {
620621
rec = httptest.NewRecorder()
621622
})
622623

624+
It("Router() returns a HTTPRouter instance", func() {
625+
Expect(api.Router()).To(BeAssignableToTypeOf(&routing.HTTPRouter{}))
626+
})
627+
623628
It("GETs collections", func() {
624629
req, err := http.NewRequest("GET", "/v1/posts", nil)
625630
Expect(err).To(BeNil())
@@ -758,7 +763,8 @@ var _ = Describe("RestHandler", func() {
758763
reqBody := strings.NewReader(`{"data": [{"title": "New Post", "type": "posts"}]}`)
759764
req, err := http.NewRequest("POST", "/v1/posts/", reqBody)
760765
Expect(err).To(BeNil())
761-
api.SetRedirectTrailingSlash(true)
766+
router := api.Router().(*routing.HTTPRouter)
767+
router.SetRedirectTrailingSlash(true)
762768
api.Handler().ServeHTTP(rec, req)
763769
Expect(rec.Code).To(Equal(http.StatusTemporaryRedirect))
764770
})
@@ -775,7 +781,8 @@ var _ = Describe("RestHandler", func() {
775781
reqBody := strings.NewReader(`{"data": [{"title": "New Post", "type": "posts"}]}`)
776782
req, err := http.NewRequest("POST", "/v1/posts/", reqBody)
777783
Expect(err).To(BeNil())
778-
api.SetRedirectTrailingSlash(false)
784+
router := api.Router().(*routing.HTTPRouter)
785+
router.SetRedirectTrailingSlash(false)
779786
api.Handler().ServeHTTP(rec, req)
780787
Expect(rec.Code).To(Equal(http.StatusNotFound))
781788
})

context.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package api2go
22

33
import (
4-
"golang.org/x/net/context"
54
"time"
5+
6+
"golang.org/x/net/context"
67
)
78

89
// APIContextAllocatorFunc to allow custom context implementations
@@ -72,7 +73,7 @@ var _ APIContexter = &APIContext{}
7273
// ContextQueryParams fetches the QueryParams if Set
7374
func ContextQueryParams(c *APIContext) map[string][]string {
7475
qp, ok := c.Get("QueryParams")
75-
if ok == true {
76+
if ok == false {
7677
qp = make(map[string][]string)
7778
c.Set("QueryParams", qp)
7879
}

context_test.go

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
package api2go
22

33
import (
4+
"time"
5+
46
. "github.com/onsi/ginkgo"
57
. "github.com/onsi/gomega"
68
)
79

810
var _ = Describe("Context", func() {
9-
Context("Set", func() {
10-
c := &APIContext{}
11+
var c *APIContext
12+
13+
BeforeEach(func() {
14+
c = &APIContext{}
15+
})
1116

17+
Context("Set", func() {
1218
It("sets key", func() {
1319
c.Set("test", 1)
1420
_, ok := c.keys["test"]
@@ -17,28 +23,76 @@ var _ = Describe("Context", func() {
1723
})
1824

1925
Context("Get", func() {
20-
c := &APIContext{}
21-
c.Set("test", 2)
26+
BeforeEach(func() {
27+
c.Set("test", 2)
28+
})
2229

2330
It("gets key", func() {
2431
key, ok := c.Get("test")
2532
Expect(ok).To(BeTrue())
2633
Expect(key.(int)).To(Equal(2))
2734
})
35+
2836
It("not okay if key does not exist", func() {
2937
key, ok := c.Get("nope")
3038
Expect(ok).To(BeFalse())
3139
Expect(key).To(BeNil())
3240
})
3341
})
42+
3443
Context("Reset", func() {
35-
c := &APIContext{}
36-
c.Set("test", 3)
44+
BeforeEach(func() {
45+
c.Set("test", 3)
46+
})
3747

3848
It("reset removes keys", func() {
3949
c.Reset()
4050
_, ok := c.Get("test")
4151
Expect(ok).To(BeFalse())
4252
})
4353
})
54+
55+
Context("Not yet implemented", func() {
56+
It("Deadline", func() {
57+
deadline, ok := c.Deadline()
58+
Expect(deadline).To(Equal(time.Time{}))
59+
Expect(ok).To(Equal(false))
60+
})
61+
62+
It("Done", func() {
63+
var chanel <-chan struct{}
64+
Expect(c.Done()).To(Equal(chanel))
65+
})
66+
67+
It("Err", func() {
68+
Expect(c.Err()).To(BeNil())
69+
})
70+
})
71+
72+
Context("Value", func() {
73+
It("Value returns a set value", func() {
74+
c.Set("foo", "bar")
75+
Expect(c.Value("foo")).To(Equal("bar"))
76+
})
77+
78+
It("Returns nil if key was not a string", func() {
79+
Expect(c.Value(1337)).To(BeNil())
80+
})
81+
82+
})
83+
84+
Context("ContextQueryParams", func() {
85+
It("returns them if set", func() {
86+
queryParams := map[string][]string{
87+
"foo": {"bar"},
88+
}
89+
90+
c.Set("QueryParams", queryParams)
91+
Expect(ContextQueryParams(c)).To(Equal(queryParams))
92+
})
93+
94+
It("sets empty ones if not set", func() {
95+
Expect(ContextQueryParams(c)).To(Equal(map[string][]string{}))
96+
})
97+
})
4498
})

error.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,6 @@ type Error struct {
2929
Meta interface{} `json:"meta,omitempty"`
3030
}
3131

32-
// GetID returns the ID
33-
func (e Error) GetID() string {
34-
return e.ID
35-
}
36-
3732
// ErrorLinks is used to provide an About URL that leads to
3833
// further details about the particular occurrence of the problem.
3934
//

error_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,25 @@ package api2go
22

33
import (
44
"errors"
5+
"net/http"
56

67
. "github.com/onsi/ginkgo"
78
. "github.com/onsi/gomega"
89
)
910

11+
type ErrorMarshaler struct{}
12+
13+
func (e ErrorMarshaler) Marshal(i interface{}) ([]byte, error) {
14+
return []byte{}, errors.New("this will always fail")
15+
}
16+
func (e ErrorMarshaler) Unmarshal(data []byte, i interface{}) error {
17+
return nil
18+
}
19+
20+
func (e ErrorMarshaler) MarshalError(error) string {
21+
return ""
22+
}
23+
1024
var _ = Describe("Errors test", func() {
1125
Context("validate error logic", func() {
1226
It("can create array tree", func() {
@@ -85,5 +99,13 @@ var _ = Describe("Errors test", func() {
8599
expected := `{"errors":[{"id":"001","status":"500","code":"001","title":"Title must not be empty","detail":"Never occures in real life","meta":{"creator":"api2go"}}]}`
86100
Expect(result).To(Equal(expected))
87101
})
102+
103+
It("logs a Marshal error and returns an empty json array", func() {
104+
Expect(
105+
marshalHTTPError(
106+
NewHTTPError(nil, "test", http.StatusInternalServerError),
107+
ErrorMarshaler{}),
108+
).To(Equal("{}"))
109+
})
88110
})
89111
})

jsonapi/data_structs_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,31 @@ var _ = Describe("JSONAPI Struct tests", func() {
9898
})
9999
})
100100

101+
It("return an error for invalid relationship data format", func() {
102+
sampleJSON := `
103+
{
104+
"data": [
105+
{
106+
"type": "test",
107+
"id": "1",
108+
"attributes": {"foo": "bar"},
109+
"relationships": {
110+
"comments": {
111+
"data": "foo"
112+
}
113+
}
114+
}
115+
]
116+
}
117+
`
118+
119+
target := Document{}
120+
121+
err := json.Unmarshal([]byte(sampleJSON), &target)
122+
Expect(err).To(HaveOccurred())
123+
Expect(err.Error()).To(Equal("Invalid json for relationship data array/object"))
124+
})
125+
101126
It("creates an empty slice for empty to-many relationships and nil for empty toOne", func() {
102127
sampleJSON := `
103128
{

jsonapi/fixtures_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,3 +421,39 @@ func (i PrefixServerInformation) GetBaseURL() string {
421421
func (i PrefixServerInformation) GetPrefix() string {
422422
return prefix
423423
}
424+
425+
type NoRelationshipPosts struct{}
426+
427+
func (n NoRelationshipPosts) GetID() string {
428+
return "someID"
429+
}
430+
431+
func (n *NoRelationshipPosts) SetID(ID string) error {
432+
return nil
433+
}
434+
435+
func (n NoRelationshipPosts) GetName() string {
436+
return "posts"
437+
}
438+
439+
type ErrorRelationshipPosts struct{}
440+
441+
func (e ErrorRelationshipPosts) GetID() string {
442+
return "errorID"
443+
}
444+
445+
func (e *ErrorRelationshipPosts) SetID(ID string) error {
446+
return nil
447+
}
448+
449+
func (e ErrorRelationshipPosts) GetName() string {
450+
return "posts"
451+
}
452+
453+
func (e ErrorRelationshipPosts) SetToOneReferenceID(name, ID string) error {
454+
return errors.New("this never works")
455+
}
456+
457+
func (e ErrorRelationshipPosts) SetToManyReferenceIDs(name string, IDs []string) error {
458+
return errors.New("this also never works")
459+
}

jsonapi/helpers_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,15 @@ var _ = Describe("StringHelpers", func() {
1212
Expect(Pluralize("posts")).To(Equal("posts"))
1313
Expect(Pluralize("category")).To(Equal("categories"))
1414
})
15+
16+
Context("Jsonify", func() {
17+
It("handles empty strings", func() {
18+
Expect(Jsonify("")).To(Equal(""))
19+
})
20+
21+
It("uses common initialisms", func() {
22+
Expect(Jsonify("RAM")).To(Equal("ram"))
23+
})
24+
})
1525
})
1626
})

0 commit comments

Comments
 (0)