Skip to content

Commit

Permalink
Add end to end test scenario
Browse files Browse the repository at this point in the history
  • Loading branch information
blgm committed May 9, 2020
1 parent 85f9370 commit b5db5ce
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 108 deletions.
82 changes: 82 additions & 0 deletions e2e_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package jsonry_test

import (
"code.cloudfoundry.org/jsonry"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("end to end", func() {
It("marshals", func() {
o := struct {
Num float32 `json:"number"`
Spaces []space `jsonry:"relationships.space.data"`
Orgs []string `jsonry:"relationships.orgs.data.guids"`
OtherSpace []space `jsonry:"other_space[].data"`
Type string `jsonry:"authentication.type"`
Username string `jsonry:"authentication.credentials.username"`
Password string `jsonry:"authentication.credentials.password"`
Labels map[string]nullString `jsonry:"metadata.labels"`
Annotations map[string]space `jsonry:"metadata.annotations"`
}{
Num: 12,
Spaces: []space{{GUID: "foo"}, {Name: "Bar", GUID: "bar"}},
Orgs: []string{"baz", "quz"},
OtherSpace: []space{{GUID: "alpha"}, {Name: "Beta", GUID: "beta"}},
Type: "basic",
Username: "fake-user",
Password: "fake secret",
Labels: map[string]nullString{"first": {value: "one"}, "second": {null: true}},
Annotations: map[string]space{"alpha": {GUID: "foo"}, "beta": {Name: "Bar", GUID: "bar"}},
}
r, err := jsonry.Marshal(o)
Expect(err).NotTo(HaveOccurred())
Expect(r).To(MatchJSON(`
{
"number": 12,
"relationships": {
"orgs": {
"data": {
"guids": ["baz","quz"]
}
},
"space": {
"data": [
{"guid": "foo"},
{"guid": "bar","name": "Bar"}
]
}
},
"authentication": {
"type": "basic",
"credentials": {
"username": "fake-user",
"password": "fake secret"
}
},
"metadata": {
"annotations": {
"alpha": {
"guid": "foo"
},
"beta": {
"guid": "bar",
"name": "Bar"
}
},
"labels": {
"first": "one",
"second": null
}
},
"other_space": [
{
"data": {"guid": "alpha"}
},
{
"data": {"guid": "beta","name": "Beta"}
}
]
}`))
})
})
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ go 1.13
require (
github.com/onsi/ginkgo v1.12.0
github.com/onsi/gomega v1.9.0
honnef.co/go/tools v0.0.1-2020.1.3
)
2 changes: 1 addition & 1 deletion internal/context/context_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ import (

func TestContext(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Context Suite")
RunSpecs(t, "JSONry Internal Context Suite")
}
2 changes: 1 addition & 1 deletion internal/path/path_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ import (

func TestPath(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Path Suite")
RunSpecs(t, "JSONry Internal Path Suite")
}
2 changes: 1 addition & 1 deletion internal/tree/tree_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ import (

func TestTree(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Tree Suite")
RunSpecs(t, "JSONry Internal Tree Suite")
}
42 changes: 42 additions & 0 deletions jsonry_suite_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,54 @@
package jsonry_test

import (
"encoding/json"
"errors"
"testing"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

type pri struct {
private bool
Public bool
}

type jsm struct{ value bool }

func (j jsm) MarshalJSON() ([]byte, error) {
if j.value {
return nil, errors.New("ouch")
}
return json.Marshal("hello")
}

type jrm struct{ value bool }

type space struct {
Name string `jsonry:"name,omitempty"`
GUID string `jsonry:"guid"`
}

type nullString struct {
value string
null bool
}

func (n nullString) MarshalJSON() ([]byte, error) {
if n.null {
return []byte("null"), nil
}
return json.Marshal(n.value)
}

func (j jrm) MarshalJSONry() (interface{}, error) {
if j.value {
return nil, errors.New("ouch")
}
return &pri{private: true, Public: true}, nil
}

func TestJSONry(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "JSONry Suite")
Expand Down
194 changes: 89 additions & 105 deletions marshal_test.go
Original file line number Diff line number Diff line change
@@ -1,119 +1,19 @@
package jsonry_test

import (
"encoding/json"
"errors"

"code.cloudfoundry.org/jsonry"
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"
)

type pri struct {
private bool
Public bool
}

type jsm struct{ value bool }

func (j jsm) MarshalJSON() ([]byte, error) {
if j.value {
return nil, errors.New("ouch")
}
return json.Marshal("hello")
}

type jrm struct{ value bool }

func (j jrm) MarshalJSONry() (interface{}, error) {
if j.value {
return nil, errors.New("ouch")
}
return &pri{private: true, Public: true}, nil
}

var _ = Describe("Marshal", func() {
type c struct{ V interface{} }

var i int

DescribeTable(
"supported types",
func(input c, expected string) {
out, err := jsonry.Marshal(input)
Expect(err).NotTo(HaveOccurred())
Expect(out).To(MatchJSON(expected))
},
Entry("string", c{V: "hello"}, `{"V":"hello"}`),
Entry("boolean", c{V: true}, `{"V":true}`),
Entry("int", c{V: 42}, `{"V":42}`),
Entry("int8", c{V: int8(42)}, `{"V":42}`),
Entry("int16", c{V: int16(42)}, `{"V":42}`),
Entry("int32", c{V: int32(42)}, `{"V":42}`),
Entry("int64", c{V: int64(42)}, `{"V":42}`),
Entry("uint", c{V: uint(42)}, `{"V":42}`),
Entry("uint8", c{V: uint8(42)}, `{"V":42}`),
Entry("uint16", c{V: uint16(42)}, `{"V":42}`),
Entry("uint32", c{V: uint32(42)}, `{"V":42}`),
Entry("uint64", c{V: uint64(42)}, `{"V":42}`),
Entry("float32", c{V: float32(4.2)}, `{"V":4.2}`),
Entry("float64", c{V: 4.2}, `{"V":4.2}`),
Entry("struct", c{V: c{V: "hierarchical"}}, `{"V":{"V":"hierarchical"}}`),
Entry("struct with private field", c{V: pri{private: true, Public: true}}, `{"V":{"Public":true}}`),
Entry("pointer", c{V: &i}, `{"V":0}`),
Entry("nil pointer", c{V: (*int)(nil)}, `{"V":null}`),
Entry("slice", c{V: []interface{}{"hello", true, 42}}, `{"V":["hello",true,42]}`),
Entry("array", c{V: [3]interface{}{"hello", true, 42}}, `{"V":["hello",true,42]}`),
Entry("map of interfaces", c{V: map[string]interface{}{"foo": "hello", "bar": true, "baz": 42}}, `{"V":{"foo":"hello","bar":true,"baz":42}}`),
Entry("map of strings", c{V: map[string]string{"foo": "hello", "bar": "true", "baz": "42"}}, `{"V":{"foo":"hello","bar":"true","baz":"42"}}`),
Entry("json.Marshaler", c{V: jsm{}}, `{"V":"hello"}`),
Entry("jsonry.Marshaler", c{V: jrm{}}, `{"V":{"Public":true}}`),
)

DescribeTable(
"type failure cases",
func(input c, message string) {
_, err := jsonry.Marshal(input)
Expect(err).To(MatchError(message), func() string {
if err != nil {
return err.Error()
}
return "there was no error"
})
},
Entry("complex", c{V: complex(1, 2)}, `unsupported type "complex128" at field "V" (type "interface {}")`),
Entry("channel", c{V: make(chan bool)}, `unsupported type "chan bool" at field "V" (type "interface {}")`),
Entry("func", c{V: func() {}}, `unsupported type "func()" at field "V" (type "interface {}")`),
Entry("map with non-string keys", c{V: map[int]interface{}{4: 3}}, `maps must only have strings keys for "map[int]interface {}" at field "V" (type "interface {}")`),
Entry("json.Marshaler with failure", c{V: jsm{value: true}}, `error from MarshaJSON() call at field "V" (type "interface {}"): ouch`),
Entry("jsonry.Marshaler with failure", c{V: jrm{value: true}}, `error from MarshaJSONry() call at field "V" (type "interface {}"): ouch`),
)

Describe("inputs", func() {
It("accept a struct", func() {
var s struct{}
_, err := jsonry.Marshal(s)
Expect(err).NotTo(HaveOccurred())
})
It("marshals a basic string field", func() {
s := struct{ Foo string }{Foo: "works"}

It("accept a struct pointer", func() {
var s struct{}
_, err := jsonry.Marshal(&s)
Expect(err).NotTo(HaveOccurred())
})

It("rejects a non-struct value", func() {
_, err := jsonry.Marshal(42)
Expect(err).To(MatchError(`the input must be a struct, not "int"`))
})

It("rejects a nil pointer", func() {
type s struct{}
var sp *s
_, err := jsonry.Marshal(sp)
Expect(err).To(MatchError(`the input must be a struct, not "invalid"`))
})
json, err := jsonry.Marshal(s)
Expect(err).NotTo(HaveOccurred())
Expect(json).To(MatchJSON(`{"Foo": "works"}`))
})

Describe("paths", func() {
Expand Down Expand Up @@ -143,6 +43,64 @@ var _ = Describe("Marshal", func() {
})
})

Describe("types", func() {
type c struct{ V interface{} }

var i int

DescribeTable(
"supported types",
func(input c, expected string) {
out, err := jsonry.Marshal(input)
Expect(err).NotTo(HaveOccurred())
Expect(out).To(MatchJSON(expected))
},
Entry("string", c{V: "hello"}, `{"V":"hello"}`),
Entry("boolean", c{V: true}, `{"V":true}`),
Entry("int", c{V: 42}, `{"V":42}`),
Entry("int8", c{V: int8(42)}, `{"V":42}`),
Entry("int16", c{V: int16(42)}, `{"V":42}`),
Entry("int32", c{V: int32(42)}, `{"V":42}`),
Entry("int64", c{V: int64(42)}, `{"V":42}`),
Entry("uint", c{V: uint(42)}, `{"V":42}`),
Entry("uint8", c{V: uint8(42)}, `{"V":42}`),
Entry("uint16", c{V: uint16(42)}, `{"V":42}`),
Entry("uint32", c{V: uint32(42)}, `{"V":42}`),
Entry("uint64", c{V: uint64(42)}, `{"V":42}`),
Entry("float32", c{V: float32(4.2)}, `{"V":4.2}`),
Entry("float64", c{V: 4.2}, `{"V":4.2}`),
Entry("struct", c{V: c{V: "hierarchical"}}, `{"V":{"V":"hierarchical"}}`),
Entry("struct with private field", c{V: pri{private: true, Public: true}}, `{"V":{"Public":true}}`),
Entry("pointer", c{V: &i}, `{"V":0}`),
Entry("nil pointer", c{V: (*int)(nil)}, `{"V":null}`),
Entry("slice", c{V: []interface{}{"hello", true, 42}}, `{"V":["hello",true,42]}`),
Entry("array", c{V: [3]interface{}{"hello", true, 42}}, `{"V":["hello",true,42]}`),
Entry("map of interfaces", c{V: map[string]interface{}{"foo": "hello", "bar": true, "baz": 42}}, `{"V":{"foo":"hello","bar":true,"baz":42}}`),
Entry("map of strings", c{V: map[string]string{"foo": "hello", "bar": "true", "baz": "42"}}, `{"V":{"foo":"hello","bar":"true","baz":"42"}}`),
Entry("json.Marshaler", c{V: jsm{}}, `{"V":"hello"}`),
Entry("jsonry.Marshaler", c{V: jrm{}}, `{"V":{"Public":true}}`),
)

DescribeTable(
"type failure cases",
func(input c, message string) {
_, err := jsonry.Marshal(input)
Expect(err).To(MatchError(message), func() string {
if err != nil {
return err.Error()
}
return "there was no error"
})
},
Entry("complex", c{V: complex(1, 2)}, `unsupported type "complex128" at field "V" (type "interface {}")`),
Entry("channel", c{V: make(chan bool)}, `unsupported type "chan bool" at field "V" (type "interface {}")`),
Entry("func", c{V: func() {}}, `unsupported type "func()" at field "V" (type "interface {}")`),
Entry("map with non-string keys", c{V: map[int]interface{}{4: 3}}, `maps must only have strings keys for "map[int]interface {}" at field "V" (type "interface {}")`),
Entry("json.Marshaler with failure", c{V: jsm{value: true}}, `error from MarshaJSON() call at field "V" (type "interface {}"): ouch`),
Entry("jsonry.Marshaler with failure", c{V: jrm{value: true}}, `error from MarshaJSONry() call at field "V" (type "interface {}"): ouch`),
)
})

Describe("omitempty", func() {
It("omits zero values", func() {
s := struct {
Expand Down Expand Up @@ -170,4 +128,30 @@ var _ = Describe("Marshal", func() {
Expect(r).To(MatchJSON(`{"E":null}`))
})
})

Describe("inputs", func() {
It("accept a struct", func() {
var s struct{}
_, err := jsonry.Marshal(s)
Expect(err).NotTo(HaveOccurred())
})

It("accept a struct pointer", func() {
var s struct{}
_, err := jsonry.Marshal(&s)
Expect(err).NotTo(HaveOccurred())
})

It("rejects a non-struct value", func() {
_, err := jsonry.Marshal(42)
Expect(err).To(MatchError(`the input must be a struct, not "int"`))
})

It("rejects a nil pointer", func() {
type s struct{}
var sp *s
_, err := jsonry.Marshal(sp)
Expect(err).To(MatchError(`the input must be a struct, not "invalid"`))
})
})
})
4 changes: 4 additions & 0 deletions test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env sh

go run honnef.co/go/tools/cmd/staticcheck ./...
go run github.com/onsi/ginkgo/ginkgo -r

0 comments on commit b5db5ce

Please sign in to comment.