~mna/zerojson

62540f7a18ba3ea3af4df86b4b334abf4fb4cbb9 — Martin Angers 2 months ago 824f0ac master
notes for improvements
2 files changed, 80 insertions(+), 61 deletions(-)

M zerojson.go
M zerojson_test.go
M zerojson.go => zerojson.go +2 -0
@@ 195,6 195,8 @@ loop:
			fmt.Printf("%d: stack=%c [%d : %b] ; allow=%c ; atEOF=%t ; char=%c\n", start, peek, p.stack.depth, p.stack.static[0], p.allow, atEOF, typ)
		}

		// TODO: probably need to emit ':' and ',' to keep track of where we are (key vs value),
		// or add a "role" arg that indicates key, value or array value?
		switch p.allow {
		case ':':
			if typ == ':' {

M zerojson_test.go => zerojson_test.go +78 -61
@@ 2,6 2,7 @@ package zerojson

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"


@@ 15,34 16,6 @@ import (
	"github.com/stretchr/testify/require"
)

func TestParser_Testdata(t *testing.T) {
	// parse each JSON document in testdata/ directory, make sure it parses
	// without error.
	files, err := ioutil.ReadDir("testdata")
	require.NoError(t, err)
	for _, file := range files {
		if ext := filepath.Ext(file.Name()); ext != ".json" {
			continue
		}
		t.Run(file.Name(), func(t *testing.T) {
			b, err := ioutil.ReadFile(filepath.Join("testdata", file.Name()))
			require.NoError(t, err)

			p := parser{
				input: b,
				emit: func(offset int, typ byte, v []byte, err error) error {
					if err != nil && err != io.EOF {
						return fmt.Errorf("%d: %c: %s: %v", offset, typ, string(v), err)
					}
					return nil
				},
			}
			err = p.parse()
			require.NoError(t, err)
		})
	}
}

func TestParser(t *testing.T) {
	cases := []struct {
		in, out string


@@ 245,6 218,83 @@ func TestParser(t *testing.T) {
	}
}

func TestParser_Testdata(t *testing.T) {
	// parse each JSON document in testdata/ directory, make sure it parses
	// without error.
	files, err := ioutil.ReadDir("testdata")
	require.NoError(t, err)
	for _, file := range files {
		if ext := filepath.Ext(file.Name()); ext != ".json" {
			continue
		}

		t.Run(file.Name(), func(t *testing.T) {
			b, err := ioutil.ReadFile(filepath.Join("testdata", file.Name()))
			require.NoError(t, err)

			var buf bytes.Buffer
			p := parser{
				input: b,
				emit: func(offset int, typ byte, v []byte, err error) error {
					if err == io.EOF {
						return nil
					}

					if err != nil {
						return fmt.Errorf("%d: %c: %s: %v", offset, typ, string(v), err)
					}
					buf.Write(v)
					return nil
				},
			}

			// assert that zerojson parses without error
			err = p.parse()
			require.NoError(t, err)

			// assert correctness by parsing with encoding/json and then parsing the zerojson-emitted
			// document, and comparing the result.
			var m1, m2 map[string]interface{}
			require.NoError(t, json.Unmarshal(b, &m1))
			require.NoError(t, json.Unmarshal(buf.Bytes(), &m2))
			require.Equal(t, m1, m2)
		})
	}
}

func TestParser_Depth(t *testing.T) {
	depths := []int{1, 10, 100, 1_000, 10_000, 100_000, 1_000_000, 10_000_000}
	for _, depth := range depths {
		t.Run(strconv.Itoa(depth), func(t *testing.T) {
			var open, clos int

			p := parser{
				input: append(bytes.Repeat([]byte{'['}, depth), bytes.Repeat([]byte{']'}, depth)...),
				emit: func(offset int, typ byte, v []byte, err error) error {
					if err == io.EOF {
						return nil
					}

					switch typ {
					case '[':
						open++
					case ']':
						clos++
					default:
						t.Fatalf("unexpected JSON token type: %c", typ)
					}
					return err
				},
			}

			err := p.parse()
			require.NoError(t, err)
			require.Equal(t, depth, open)
			require.Equal(t, depth, clos)
		})
	}
}

func TestStack(t *testing.T) {
	seed := time.Now().UnixNano()
	rnd := rand.New(rand.NewSource(seed))


@@ 299,36 349,3 @@ func TestStack(t *testing.T) {
		}
	}
}

func TestParser_Depth(t *testing.T) {
	depths := []int{1, 10, 100, 1_000, 10_000, 100_000, 1_000_000, 10_000_000}
	for _, depth := range depths {
		t.Run(strconv.Itoa(depth), func(t *testing.T) {
			var open, clos int

			p := parser{
				input: append(bytes.Repeat([]byte{'['}, depth), bytes.Repeat([]byte{']'}, depth)...),
				emit: func(offset int, typ byte, v []byte, err error) error {
					if err == io.EOF {
						return nil
					}

					switch typ {
					case '[':
						open++
					case ']':
						clos++
					default:
						t.Fatalf("unexpected JSON token type: %c", typ)
					}
					return err
				},
			}

			err := p.parse()
			require.NoError(t, err)
			require.Equal(t, depth, open)
			require.Equal(t, depth, clos)
		})
	}
}