diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2023-01-30 21:54:38 -0700 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2023-01-30 21:54:38 -0700 |
commit | 8467bdaa181257d031a258a05012dc85adbcb233 (patch) | |
tree | bc9bf437a34905f0b7249352043aff9e9d80ebe8 /methods_test.go | |
parent | 0b57145421e7e4f165f64e73ee7c5d8102945569 (diff) | |
parent | 2e48a42fb9b9e946958810cfbb90ae85bee997e4 (diff) |
Merge branch 'lukeshu/quality2'
Diffstat (limited to 'methods_test.go')
-rw-r--r-- | methods_test.go | 198 |
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) + } + }) + } +} |