summaryrefslogtreecommitdiff
path: root/decode_scan_test.go
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@datawire.io>2022-08-15 00:37:32 -0600
committerLuke Shumaker <lukeshu@datawire.io>2022-08-15 00:37:32 -0600
commit801fdb54ba1bb14433fad810c832a5df530f0a25 (patch)
treeda37231548e1f7c0048e91d4efacfe5d1526a4a7 /decode_scan_test.go
parent58b7df5e9f1c0d4858528f326440599620a8c1fb (diff)
rename parse_scan decode_scan parse_scan*
Diffstat (limited to 'decode_scan_test.go')
-rw-r--r--decode_scan_test.go269
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)
+ }
+}