Skip to content

Commit

Permalink
Marshal arrays and slices
Browse files Browse the repository at this point in the history
  • Loading branch information
blgm committed May 5, 2020
1 parent 2403b09 commit 002201e
Show file tree
Hide file tree
Showing 7 changed files with 276 additions and 72 deletions.
30 changes: 0 additions & 30 deletions context.go

This file was deleted.

8 changes: 5 additions & 3 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@ package jsonry
import (
"fmt"
"reflect"

"code.cloudfoundry.org/jsonry/internal/context"
)

type UnsupportedType struct {
TypeName string
Context context
Context context.Context
}

func NewUnsupportedTypeError(ctx context, t reflect.Type) *UnsupportedType {
func NewUnsupportedTypeError(ctx context.Context, t reflect.Type) *UnsupportedType {
return &UnsupportedType{
Context: ctx,
TypeName: t.String(),
}
}

func (u *UnsupportedType) Error() string {
return fmt.Sprintf("unsupported type '%s' at %s", u.TypeName, u.Context)
return fmt.Sprintf(`unsupported type "%s" %s`, u.TypeName, u.Context)
}
80 changes: 80 additions & 0 deletions internal/context/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package context

import (
"fmt"
"reflect"
)

type sort uint

const (
field sort = iota
index
key
)

type segment struct {
sort sort
name string
index int
typ reflect.Type
}

func (s segment) String() string {
switch s.sort {
case field:
return fmt.Sprintf(`field "%s" (type "%s")`, s.name, s.typ)
case index:
return fmt.Sprintf(`index %d (type "%s")`, s.index, s.typ)
default:
return fmt.Sprintf(`key "%s" (type "%s")`, s.name, s.typ)
}
}

type Context []segment

func (ctx Context) String() string {
switch len(ctx) {
case 0:
return "at the root"
case 1:
return fmt.Sprintf("at %s", ctx.leaf())
default:
return fmt.Sprintf("at %s path %s", ctx.leaf(), ctx.path())
}
}

func (ctx Context) leaf() segment {
return ctx[len(ctx)-1]
}

func (ctx Context) path() string {
var path string
for _, s := range ctx {
switch s.sort {
case index:
path = fmt.Sprintf("%s[%d]", path, s.index)
case field:
if len(path) > 0 {
path = path + "."
}
path = path + s.name
case key:
path = fmt.Sprintf(`%s["%s"]`, path, s.name)
}
}

return path
}

func (ctx Context) WithField(f reflect.StructField) Context {
return append(ctx, segment{sort: field, name: f.Name, typ: f.Type})
}

func (ctx Context) WithIndex(i int, t reflect.Type) Context {
return append(ctx, segment{sort: index, index: i, typ: t})
}

func (ctx Context) WithKey(k string, t reflect.Type) Context {
return append(ctx, segment{sort: key, name: k, typ: t})
}
13 changes: 13 additions & 0 deletions internal/context/context_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package context_test

import (
"testing"

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

func TestContext(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Context Suite")
}
100 changes: 100 additions & 0 deletions internal/context/context_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package context_test

import (
"reflect"

"code.cloudfoundry.org/jsonry/internal/context"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Context", func() {
When("it is the zero value", func() {
It("reports being at the root", func() {
ctx := context.Context{}
Expect(ctx.String()).To(Equal("at the root"))
})
})

When("it has a field", func() {
It("reports the field detail", func() {
ctx := context.Context{}.WithField(reflect.StructField{Name: "Foo", Type: reflect.TypeOf("")})
Expect(ctx.String()).To(Equal(`at field "Foo" (type "string")`))
})
})

When("it has an index", func() {
It("reports the index detail", func() {
ctx := context.Context{}.WithIndex(4, reflect.TypeOf(true))
Expect(ctx.String()).To(Equal(`at index 4 (type "bool")`))

})
})

When("it has an key", func() {
It("reports the key detail", func() {
ctx := context.Context{}.WithKey("foo", reflect.TypeOf(true))
Expect(ctx.String()).To(Equal(`at key "foo" (type "bool")`))

})
})

When("it has multiple fields", func() {
It("reports the path details", func() {
ctx := context.Context{}.
WithField(reflect.StructField{Name: "Foo", Type: reflect.TypeOf("")}).
WithField(reflect.StructField{Name: "Bar", Type: reflect.TypeOf(true)}).
WithField(reflect.StructField{Name: "Baz", Type: reflect.TypeOf(42)})

Expect(ctx.String()).To(Equal(`at field "Baz" (type "int") path Foo.Bar.Baz`))
})
})

When("it has multiple indices", func() {
It("reports the path details", func() {
ctx := context.Context{}.
WithIndex(3, reflect.TypeOf("")).
WithIndex(5, reflect.TypeOf(true)).
WithIndex(4, reflect.TypeOf(42))
Expect(ctx.String()).To(Equal(`at index 4 (type "int") path [3][5][4]`))
})
})

When("it has multiple key", func() {
It("reports the path details", func() {
ctx := context.Context{}.
WithKey("foo", reflect.TypeOf(true)).
WithKey("bar", reflect.TypeOf(42)).
WithKey("baz", reflect.TypeOf(""))
Expect(ctx.String()).To(Equal(`at key "baz" (type "string") path ["foo"]["bar"]["baz"]`))

})
})

When("it there is a mixture of fields, indices, and keys", func() {
It("reports the details", func() {
ctx := context.Context{}.
WithIndex(3, reflect.TypeOf("")).
WithField(reflect.StructField{Name: "Foo", Type: reflect.TypeOf("")}).
WithKey("foo", reflect.TypeOf(true)).
WithIndex(5, reflect.TypeOf(true)).
WithField(reflect.StructField{Name: "Bar", Type: reflect.TypeOf(true)}).
WithField(reflect.StructField{Name: "Baz", Type: reflect.TypeOf(42)}).
WithKey("bar", reflect.TypeOf(42)).
WithIndex(4, reflect.TypeOf(42))
Expect(ctx.String()).To(Equal(`at index 4 (type "int") path [3].Foo["foo"][5].Bar.Baz["bar"][4]`))

ctx = context.Context{}.
WithField(reflect.StructField{Name: "Foo", Type: reflect.TypeOf("")}).
WithIndex(5, reflect.TypeOf(true)).
WithIndex(3, reflect.TypeOf("")).
WithKey("foo", reflect.TypeOf(true)).
WithField(reflect.StructField{Name: "Bar", Type: reflect.TypeOf(true)}).
WithKey("bar", reflect.TypeOf(42)).
WithIndex(4, reflect.TypeOf(42)).
WithField(reflect.StructField{Name: "Baz", Type: reflect.TypeOf(42)})
Expect(ctx.String()).To(Equal(`at field "Baz" (type "int") path Foo[5][3]["foo"].Bar["bar"][4].Baz`))
})
})

})

0 comments on commit 002201e

Please sign in to comment.