~mna/zerojson

ref: 2f03901dbdea79fbe34e68cad9974871fd0f26a0 zerojson/zerojson_test.go -rw-r--r-- 2.3 KiB View raw
2f03901dMartin Angers scan and test literal tokens 1 year, 1 month ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package zerojson

import (
	"bytes"
	"fmt"
	"io"
	"math/rand"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
)

func TestParser(t *testing.T) {
	cases := []struct {
		in, out string
		err     error
	}{
		{"", "", nil},
		{" \t\n ", "", nil},
		{"null", "0: n: null", nil},
		{"true", "0: t: true", nil},
		{"false", "0: f: false", nil},
		{" null", "1: n: null", nil},
		{"\ttrue", "1: t: true", nil},
		{"\n false", "2: f: false", nil},
		{" null ", "1: n: null", nil},
		{"\ttrue\t", "1: t: true", nil},
		{"\n false\n ", "2: f: false", nil},
		{"nulltruefalse", "0: n: null\n4: t: true\n8: f: false", nil},
	}

	for _, c := range cases {
		t.Run(c.in, func(t *testing.T) {
			var buf bytes.Buffer

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

			require.Equal(t, strings.TrimSpace(c.out), strings.TrimSpace(buf.String()))
		})
	}
}

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

	// make sure to bleed into dynamic allocation
	max := staticStackSize*64 + rnd.Intn(1000) + 1

	// generate the slice of values to push and pop
	vals := make([]byte, max)
	for i := range vals {
		if rnd.Intn(2) == 1 {
			vals[i] = '{'
		} else {
			vals[i] = '['
		}
	}
	t.Logf("seed=%d\nmax=%d\nvalues=%s", seed, max, string(vals))

	var s stack

	// repeat a couple times, so we push after pop
	for count := 0; count < 2; count++ {
		for _, v := range vals {
			s.push(v)
			b := s.peek()
			if b != v {
				t.Fatalf("peek: want %#U, got %#U", v, b)
			}
		}

		for i := len(vals) - 1; i >= 0; i-- {
			v := s.pop()
			if v != vals[i] {
				t.Fatalf("pop at %d: want %#U, got %#U", i, vals[i], v)
			}

			if i > 0 {
				want := vals[i-1]
				for j := 0; j < 2; j++ {
					got := s.peek()
					if want != got {
						t.Fatalf("peek at %d: want %#U, got %#U", i, want, got)
					}
				}
			}
		}
		if s.depth != 0 {
			t.Fatalf("depth should be 0, is %d", s.depth)
		}
		if got := s.peek(); got != 0 {
			t.Fatalf("peek when empty should be 0, got %#U", got)
		}
	}
}