summaryrefslogtreecommitdiff
path: root/methods_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'methods_test.go')
-rw-r--r--methods_test.go198
1 files changed, 198 insertions, 0 deletions
diff --git a/methods_test.go b/methods_test.go
index 5e2209a..f5d5a9a 100644
--- a/methods_test.go
+++ b/methods_test.go
@@ -6,8 +6,10 @@ package lowmemjson_test
import (
"bytes"
+ "errors"
"fmt"
"io"
+ "strings"
"testing"
"github.com/stretchr/testify/assert"
@@ -121,3 +123,199 @@ func TestMethods(t *testing.T) {
assert.NoError(t, lowmemjson.NewDecoder(&buf).Decode(&out))
assert.Equal(t, in, out)
}
+
+type strEncoder string
+
+func (s strEncoder) EncodeJSON(w io.Writer) error {
+ _, err := io.WriteString(w, string(s))
+ return err
+}
+
+type strMarshaler string
+
+func (s strMarshaler) MarshalJSON() ([]byte, error) {
+ return []byte(s), nil
+}
+
+type strTextMarshaler struct {
+ str string
+ err string
+}
+
+func (m strTextMarshaler) MarshalText() (txt []byte, err error) {
+ if len(m.str) > 0 {
+ txt = []byte(m.str)
+ }
+ if len(m.err) > 0 {
+ err = errors.New(m.err)
+ }
+ return
+}
+
+func TestMethodsEncode(t *testing.T) {
+ t.Parallel()
+ type testcase struct {
+ In string
+ ExpectedErr string
+ }
+ testcases := map[string]testcase{
+ "basic": {In: `{}`},
+ "empty": {In: ``, ExpectedErr: `syntax error at input byte 0: EOF`},
+ "short": {In: `{`, ExpectedErr: `syntax error at input byte 1: unexpected EOF`},
+ "long": {In: `{}{}`, ExpectedErr: `syntax error at input byte 2: invalid character '{' after top-level value`},
+ }
+ t.Run("encodable", func(t *testing.T) {
+ t.Parallel()
+ for tcName, tc := range testcases {
+ tc := tc
+ t.Run(tcName, func(t *testing.T) {
+ t.Parallel()
+ var buf strings.Builder
+ err := lowmemjson.NewEncoder(&buf).Encode([]any{strEncoder(tc.In)})
+ if tc.ExpectedErr == "" {
+ assert.NoError(t, err)
+ assert.Equal(t, "["+tc.In+"]", buf.String())
+ } else {
+ assert.EqualError(t, err,
+ `json: error calling EncodeJSON for type lowmemjson_test.strEncoder: `+
+ tc.ExpectedErr)
+ }
+ })
+ }
+ })
+ t.Run("marshaler", func(t *testing.T) {
+ t.Parallel()
+ for tcName, tc := range testcases {
+ tc := tc
+ t.Run(tcName, func(t *testing.T) {
+ t.Parallel()
+ var buf strings.Builder
+ err := lowmemjson.NewEncoder(&buf).Encode([]any{strMarshaler(tc.In)})
+ if tc.ExpectedErr == "" {
+ assert.NoError(t, err)
+ assert.Equal(t, "["+tc.In+"]", buf.String())
+ } else {
+ assert.EqualError(t, err,
+ `json: error calling MarshalJSON for type lowmemjson_test.strMarshaler: `+
+ tc.ExpectedErr)
+ }
+ })
+ }
+ })
+ t.Run("text", func(t *testing.T) {
+ t.Parallel()
+ type testcase struct {
+ Str string
+ Err string
+ }
+ testcases := map[string]testcase{
+ "basic": {Str: `a`},
+ "err": {Err: `xxx`},
+ "both": {Str: `a`, Err: `xxx`},
+ }
+ for tcName, tc := range testcases {
+ tc := tc
+ t.Run(tcName, func(t *testing.T) {
+ t.Parallel()
+ var buf strings.Builder
+ err := lowmemjson.NewEncoder(&buf).Encode([]any{strTextMarshaler{str: tc.Str, err: tc.Err}})
+ if tc.Err == "" {
+ assert.NoError(t, err)
+ assert.Equal(t, `["`+tc.Str+`"]`, buf.String())
+ } else {
+ assert.EqualError(t, err,
+ `json: error calling MarshalText for type lowmemjson_test.strTextMarshaler: `+
+ tc.Err)
+ assert.Equal(t, "[", buf.String())
+ }
+ })
+ }
+ })
+}
+
+type tstDecoder struct {
+ n int
+ err string
+}
+
+func (d *tstDecoder) DecodeJSON(r io.RuneScanner) error {
+ for i := 0; i < d.n; i++ {
+ if _, _, err := r.ReadRune(); err != nil {
+ if err == io.EOF {
+ break
+ }
+ return err
+ }
+ }
+ if len(d.err) > 0 {
+ return errors.New(d.err)
+ }
+ return nil
+}
+
+type strUnmarshaler struct {
+ err string
+}
+
+func (u *strUnmarshaler) UnmarshalJSON([]byte) error {
+ if u.err == "" {
+ return nil
+ }
+ return errors.New(u.err)
+}
+
+type textUnmarshaler struct {
+ err string
+}
+
+func (u *textUnmarshaler) UnmarshalText([]byte) error {
+ if u.err == "" {
+ return nil
+ }
+ return errors.New(u.err)
+}
+
+type errTextUnmarshaler struct {
+ S string
+}
+
+func (u *errTextUnmarshaler) UnmarshalText(dat []byte) error {
+ u.S = string(dat)
+ return errors.New("eee")
+}
+
+func TestMethodsDecode(t *testing.T) {
+ t.Parallel()
+ type testcase struct {
+ In string
+ Obj any
+ ExpectedErr string
+ }
+ testcases := map[string]testcase{
+ "decode-basic": {In: `{}`, Obj: &tstDecoder{n: 2}},
+ "decode-basic-eof": {In: `{}`, Obj: &tstDecoder{n: 5}},
+ "decode-syntax-error": {In: `{x}`, Obj: &tstDecoder{n: 5}, ExpectedErr: `json: v: syntax error at input byte 1: object: unexpected character: 'x'`},
+ "unmarshal-syntax-error": {In: `{x}`, Obj: &strUnmarshaler{}, ExpectedErr: `json: v: syntax error at input byte 1: object: unexpected character: 'x'`},
+ "decode-short": {In: `{}`, Obj: &tstDecoder{n: 1}, ExpectedErr: `json: v: cannot decode JSON object at input byte 0 into Go *lowmemjson_test.tstDecoder: did not consume entire object`},
+ "decode-err": {In: `{}`, Obj: &tstDecoder{err: "xxx"}, ExpectedErr: `json: v: cannot decode JSON object at input byte 0 into Go *lowmemjson_test.tstDecoder: xxx`},
+ "decode-err2": {In: `{}`, Obj: &tstDecoder{n: 1, err: "yyy"}, ExpectedErr: `json: v: cannot decode JSON object at input byte 0 into Go *lowmemjson_test.tstDecoder: yyy`},
+ "unmarshal-err": {In: `{}`, Obj: &strUnmarshaler{err: "zzz"}, ExpectedErr: `json: v: cannot decode JSON object at input byte 0 into Go *lowmemjson_test.strUnmarshaler: zzz`},
+ "unmarshaltext": {In: `""`, Obj: &textUnmarshaler{}},
+ "unmarshaltext-nonstr": {In: `{}`, Obj: &textUnmarshaler{}, ExpectedErr: `json: v: cannot decode JSON object at input byte 0 into Go *lowmemjson_test.textUnmarshaler`},
+ "unmarshaltext-err": {In: `""`, Obj: &textUnmarshaler{err: "zzz"}, ExpectedErr: `json: v: cannot decode JSON string at input byte 0 into Go *lowmemjson_test.textUnmarshaler: zzz`},
+ "unmarshaltext-mapkey": {In: `{"a":1}`, Obj: new(map[errTextUnmarshaler]int), ExpectedErr: `json: v: cannot decode JSON string at input byte 1 into Go *lowmemjson_test.errTextUnmarshaler: eee`},
+ }
+ for tcName, tc := range testcases {
+ tc := tc
+ t.Run(tcName, func(t *testing.T) {
+ t.Parallel()
+ obj := tc.Obj
+ err := lowmemjson.NewDecoder(strings.NewReader(tc.In)).Decode(&obj)
+ if tc.ExpectedErr == "" {
+ assert.NoError(t, err)
+ } else {
+ assert.EqualError(t, err, tc.ExpectedErr)
+ }
+ })
+ }
+}