diff options
author | Luke Shumaker <lukeshu@datawire.io> | 2022-08-15 00:37:32 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@datawire.io> | 2022-08-15 00:37:32 -0600 |
commit | 801fdb54ba1bb14433fad810c832a5df530f0a25 (patch) | |
tree | da37231548e1f7c0048e91d4efacfe5d1526a4a7 /decode_scan_test.go | |
parent | 58b7df5e9f1c0d4858528f326440599620a8c1fb (diff) |
rename parse_scan decode_scan parse_scan*
Diffstat (limited to 'decode_scan_test.go')
-rw-r--r-- | decode_scan_test.go | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/decode_scan_test.go b/decode_scan_test.go new file mode 100644 index 0000000..5ad454f --- /dev/null +++ b/decode_scan_test.go @@ -0,0 +1,269 @@ +// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com> +// +// SPDX-License-Identifier: GPL-2.0-or-later + +package lowmemjson + +import ( + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type ReadRuneTypeResult struct { + r rune + s int + t RuneType + e error +} + +func (r ReadRuneTypeResult) String() string { + return fmt.Sprintf("{%q, %d, %#v, %v}", r.r, r.s, r.t, r.e) +} + +func TestRuneTypeScanner(t *testing.T) { + type testcase struct { + Input string + Exp []ReadRuneTypeResult + } + testcases := map[string]testcase{ + "basic": {`{"foo": 12.0}`, []ReadRuneTypeResult{ + {'{', 1, RuneTypeObjectBeg, nil}, + {'"', 1, RuneTypeStringBeg, nil}, + {'f', 1, RuneTypeStringChar, nil}, + {'o', 1, RuneTypeStringChar, nil}, + {'o', 1, RuneTypeStringChar, nil}, + {'"', 1, RuneTypeStringEnd, nil}, + {':', 1, RuneTypeObjectColon, nil}, + {' ', 1, RuneTypeSpace, nil}, + {'1', 1, RuneTypeNumberIntDig, nil}, + {'2', 1, RuneTypeNumberIntDig, nil}, + {'.', 1, RuneTypeNumberFracDot, nil}, + {'0', 1, RuneTypeNumberFracDig, nil}, + {'}', 1, RuneTypeObjectEnd, nil}, + {0, 0, RuneTypeEOF, nil}, + {0, 0, RuneTypeEOF, nil}, + }}, + "unread": {`{"foo": 12.0}`, []ReadRuneTypeResult{ + {'{', 1, RuneTypeObjectBeg, nil}, + {'"', 1, RuneTypeStringBeg, nil}, + {'f', 1, RuneTypeStringChar, nil}, + {'o', 1, RuneTypeStringChar, nil}, + {'o', 1, RuneTypeStringChar, nil}, + {'"', 1, RuneTypeStringEnd, nil}, + {':', 1, RuneTypeObjectColon, nil}, + {' ', 1, RuneTypeSpace, nil}, + {'1', 1, RuneTypeNumberIntDig, nil}, + {0, -1, 0, nil}, + {'1', 1, RuneTypeNumberIntDig, nil}, + {'2', 1, RuneTypeNumberIntDig, nil}, + {'.', 1, RuneTypeNumberFracDot, nil}, + {'0', 1, RuneTypeNumberFracDig, nil}, + {'}', 1, RuneTypeObjectEnd, nil}, + {0, 0, RuneTypeEOF, nil}, + {0, 0, RuneTypeEOF, nil}, + }}, + "unread2": {`{"foo": 12.0}`, []ReadRuneTypeResult{ + {'{', 1, RuneTypeObjectBeg, nil}, + {'"', 1, RuneTypeStringBeg, nil}, + {'f', 1, RuneTypeStringChar, nil}, + {'o', 1, RuneTypeStringChar, nil}, + {'o', 1, RuneTypeStringChar, nil}, + {'"', 1, RuneTypeStringEnd, nil}, + {':', 1, RuneTypeObjectColon, nil}, + {' ', 1, RuneTypeSpace, nil}, + {'1', 1, RuneTypeNumberIntDig, nil}, + {0, -1, 0, nil}, + {0, -1, 0, ErrInvalidUnreadRune}, + {'1', 1, RuneTypeNumberIntDig, nil}, + {'2', 1, RuneTypeNumberIntDig, nil}, + {'.', 1, RuneTypeNumberFracDot, nil}, + {'0', 1, RuneTypeNumberFracDig, nil}, + {'}', 1, RuneTypeObjectEnd, nil}, + {0, 0, RuneTypeEOF, nil}, + {0, 0, RuneTypeEOF, nil}, + }}, + "unread-eof": {`{"foo": 12.0}`, []ReadRuneTypeResult{ + {'{', 1, RuneTypeObjectBeg, nil}, + {'"', 1, RuneTypeStringBeg, nil}, + {'f', 1, RuneTypeStringChar, nil}, + {'o', 1, RuneTypeStringChar, nil}, + {'o', 1, RuneTypeStringChar, nil}, + {'"', 1, RuneTypeStringEnd, nil}, + {':', 1, RuneTypeObjectColon, nil}, + {' ', 1, RuneTypeSpace, nil}, + {'1', 1, RuneTypeNumberIntDig, nil}, + {'2', 1, RuneTypeNumberIntDig, nil}, + {'.', 1, RuneTypeNumberFracDot, nil}, + {'0', 1, RuneTypeNumberFracDig, nil}, + {'}', 1, RuneTypeObjectEnd, nil}, + {0, 0, RuneTypeEOF, nil}, + {0, -1, 0, ErrInvalidUnreadRune}, + {0, 0, RuneTypeEOF, nil}, + {0, 0, RuneTypeEOF, nil}, + }}, + } + for tcName, tc := range testcases { + t.Run(tcName, func(t *testing.T) { + sc := &runeTypeScannerImpl{ + inner: strings.NewReader(tc.Input), + } + var exp, act []string + for _, iExp := range tc.Exp { + var iAct ReadRuneTypeResult + if iExp.s < 0 { + iAct.s = iExp.s + iAct.e = sc.UnreadRune() + } else { + iAct.r, iAct.s, iAct.t, iAct.e = sc.ReadRuneType() + } + exp = append(exp, iExp.String()) + act = append(act, iAct.String()) + } + assert.Equal(t, exp, act) + }) + } +} + +func TestNoWSRuneTypeScanner(t *testing.T) { + type testcase struct { + Input string + Exp []ReadRuneTypeResult + } + testcases := map[string]testcase{ + "basic": {`{"foo": 12.0}`, []ReadRuneTypeResult{ + {'{', 1, RuneTypeObjectBeg, nil}, + {'"', 1, RuneTypeStringBeg, nil}, + {'f', 1, RuneTypeStringChar, nil}, + {'o', 1, RuneTypeStringChar, nil}, + {'o', 1, RuneTypeStringChar, nil}, + {'"', 1, RuneTypeStringEnd, nil}, + {':', 1, RuneTypeObjectColon, nil}, + {'1', 1, RuneTypeNumberIntDig, nil}, + {'2', 1, RuneTypeNumberIntDig, nil}, + {'.', 1, RuneTypeNumberFracDot, nil}, + {'0', 1, RuneTypeNumberFracDig, nil}, + {'}', 1, RuneTypeObjectEnd, nil}, + {0, 0, RuneTypeEOF, nil}, + {0, 0, RuneTypeEOF, nil}, + }}, + "unread": {`{"foo": 12.0}`, []ReadRuneTypeResult{ + {'{', 1, RuneTypeObjectBeg, nil}, + {'"', 1, RuneTypeStringBeg, nil}, + {'f', 1, RuneTypeStringChar, nil}, + {'o', 1, RuneTypeStringChar, nil}, + {'o', 1, RuneTypeStringChar, nil}, + {'"', 1, RuneTypeStringEnd, nil}, + {':', 1, RuneTypeObjectColon, nil}, + {'1', 1, RuneTypeNumberIntDig, nil}, + {0, -1, 0, nil}, + {'1', 1, RuneTypeNumberIntDig, nil}, + {'2', 1, RuneTypeNumberIntDig, nil}, + {'.', 1, RuneTypeNumberFracDot, nil}, + {'0', 1, RuneTypeNumberFracDig, nil}, + {'}', 1, RuneTypeObjectEnd, nil}, + {0, 0, RuneTypeEOF, nil}, + {0, 0, RuneTypeEOF, nil}, + }}, + "tail": {`{"foo": 12.0} `, []ReadRuneTypeResult{ + {'{', 1, RuneTypeObjectBeg, nil}, + {'"', 1, RuneTypeStringBeg, nil}, + {'f', 1, RuneTypeStringChar, nil}, + {'o', 1, RuneTypeStringChar, nil}, + {'o', 1, RuneTypeStringChar, nil}, + {'"', 1, RuneTypeStringEnd, nil}, + {':', 1, RuneTypeObjectColon, nil}, + {'1', 1, RuneTypeNumberIntDig, nil}, + {'2', 1, RuneTypeNumberIntDig, nil}, + {'.', 1, RuneTypeNumberFracDot, nil}, + {'0', 1, RuneTypeNumberFracDig, nil}, + {'}', 1, RuneTypeObjectEnd, nil}, + {0, 0, RuneTypeEOF, nil}, + {0, 0, RuneTypeEOF, nil}, + }}, + } + for tcName, tc := range testcases { + t.Run(tcName, func(t *testing.T) { + sc := &noWSRuneTypeScanner{ + inner: &runeTypeScannerImpl{ + inner: strings.NewReader(tc.Input), + }, + } + var exp, act []string + for _, iExp := range tc.Exp { + var iAct ReadRuneTypeResult + if iExp.s < 0 { + iAct.s = iExp.s + iAct.e = sc.UnreadRune() + } else { + iAct.r, iAct.s, iAct.t, iAct.e = sc.ReadRuneType() + } + exp = append(exp, iExp.String()) + act = append(act, iAct.String()) + } + assert.Equal(t, exp, act) + }) + } +} + +func TestElemRuneTypeScanner(t *testing.T) { + parent := &noWSRuneTypeScanner{ + inner: &runeTypeScannerImpl{ + inner: strings.NewReader(` { "foo" : 12.0 } `), + }, + } + exp := []ReadRuneTypeResult{ + {'{', 1, RuneTypeObjectBeg, nil}, + {'"', 1, RuneTypeStringBeg, nil}, + {'f', 1, RuneTypeStringChar, nil}, + {'o', 1, RuneTypeStringChar, nil}, + {'o', 1, RuneTypeStringChar, nil}, + {'"', 1, RuneTypeStringEnd, nil}, + {':', 1, RuneTypeObjectColon, nil}, + } + var expStr, actStr []string + for _, iExp := range exp { + var iAct ReadRuneTypeResult + iAct.r, iAct.s, iAct.t, iAct.e = parent.ReadRuneType() + expStr = append(expStr, iExp.String()) + actStr = append(actStr, iAct.String()) + require.Equal(t, expStr, actStr) + } + + child := &elemRuneTypeScanner{ + inner: parent, + } + exp = []ReadRuneTypeResult{ + {'1', 1, RuneTypeNumberIntDig, nil}, + {'2', 1, RuneTypeNumberIntDig, nil}, + {'.', 1, RuneTypeNumberFracDot, nil}, + {'0', 1, RuneTypeNumberFracDig, nil}, + {0, 0, RuneTypeEOF, nil}, + {0, 0, RuneTypeEOF, nil}, + } + expStr, actStr = nil, nil + for _, iExp := range exp { + var iAct ReadRuneTypeResult + iAct.r, iAct.s, iAct.t, iAct.e = child.ReadRuneType() + expStr = append(expStr, iExp.String()) + actStr = append(actStr, iAct.String()) + require.Equal(t, expStr, actStr) + } + + exp = []ReadRuneTypeResult{ + {'}', 1, RuneTypeObjectEnd, nil}, + {0, 0, RuneTypeEOF, nil}, + {0, 0, RuneTypeEOF, nil}, + } + expStr, actStr = nil, nil + for _, iExp := range exp { + var iAct ReadRuneTypeResult + iAct.r, iAct.s, iAct.t, iAct.e = parent.ReadRuneType() + expStr = append(expStr, iExp.String()) + actStr = append(actStr, iAct.String()) + require.Equal(t, expStr, actStr) + } +} |