1package buffer
2
3import (
4	"bytes"
5	"io"
6	"testing"
7
8	"github.com/tdewolff/test"
9)
10
11func TestLexer(t *testing.T) {
12	s := `Lorem ipsum dolor sit amet, consectetur adipiscing elit.`
13	z := NewLexer(bytes.NewBufferString(s))
14
15	test.Bytes(t, z.Bytes(), []byte(s), "bytes match original buffer")
16
17	test.T(t, z.err, nil, "buffer has no error")
18	test.T(t, z.Err(), nil, "buffer is at EOF but must not return EOF until we reach that")
19	test.That(t, z.Pos() == 0, "buffer must start at position 0")
20	test.That(t, z.Peek(0) == 'L', "first character must be 'L'")
21	test.That(t, z.Peek(1) == 'o', "second character must be 'o'")
22
23	z.Move(1)
24	test.That(t, z.Peek(0) == 'o', "must be 'o' at position 1")
25	test.That(t, z.Peek(1) == 'r', "must be 'r' at position 1")
26	z.Rewind(6)
27	test.That(t, z.Peek(0) == 'i', "must be 'i' at position 6")
28	test.That(t, z.Peek(1) == 'p', "must be 'p' at position 7")
29
30	test.T(t, z.Offset(), 6, "offset")
31
32	test.Bytes(t, z.Lexeme(), []byte("Lorem "), "buffered string must now read 'Lorem ' when at position 6")
33	test.Bytes(t, z.Shift(), []byte("Lorem "), "shift must return the buffered string")
34	test.That(t, z.Pos() == 0, "after shifting position must be 0")
35	test.That(t, z.Peek(0) == 'i', "must be 'i' at position 0 after shifting")
36	test.That(t, z.Peek(1) == 'p', "must be 'p' at position 1 after shifting")
37	test.T(t, z.Err(), nil, "error must be nil at this point")
38
39	z.Move(len(s) - len("Lorem ") - 1)
40	test.T(t, z.Err(), nil, "error must be nil just before the end of the buffer")
41	z.Skip()
42	test.That(t, z.Pos() == 0, "after skipping position must be 0")
43	z.Move(1)
44	test.T(t, z.Err(), io.EOF, "error must be EOF when past the buffer")
45	z.Move(-1)
46	test.T(t, z.Err(), nil, "error must be nil just before the end of the buffer, even when it has been past the buffer")
47
48	z.Reset()
49	test.That(t, z.Peek(0) == 'L', "must be 'L' at position 0")
50	test.That(t, z.Peek(1) == 'o', "must be 'o' at position 1")
51}
52
53func TestLexerRunes(t *testing.T) {
54	z := NewLexer(bytes.NewBufferString("aæ†\U00100000"))
55	r, n := z.PeekRune(0)
56	test.That(t, n == 1, "first character must be length 1")
57	test.That(t, r == 'a', "first character must be rune 'a'")
58	r, n = z.PeekRune(1)
59	test.That(t, n == 2, "second character must be length 2")
60	test.That(t, r == 'æ', "second character must be rune 'æ'")
61	r, n = z.PeekRune(3)
62	test.That(t, n == 3, "fourth character must be length 3")
63	test.That(t, r == '†', "fourth character must be rune '†'")
64	r, n = z.PeekRune(6)
65	test.That(t, n == 4, "seventh character must be length 4")
66	test.That(t, r == '\U00100000', "seventh character must be rune '\U00100000'")
67}
68
69func TestLexerBadRune(t *testing.T) {
70	z := NewLexer(bytes.NewBufferString("\xF0")) // expect four byte rune
71	r, n := z.PeekRune(0)
72	test.T(t, n, 1, "length")
73	test.T(t, r, rune(0xF0), "rune")
74}
75
76func TestLexerZeroLen(t *testing.T) {
77	z := NewLexer(test.NewPlainReader(bytes.NewBufferString("")))
78	test.That(t, z.Peek(0) == 0, "first character must yield error")
79	test.Bytes(t, z.Bytes(), []byte{}, "bytes match original buffer")
80}
81
82func TestLexerEmptyReader(t *testing.T) {
83	z := NewLexer(test.NewEmptyReader())
84	test.That(t, z.Peek(0) == 0, "first character must yield error")
85	test.T(t, z.Err(), io.EOF, "error must be EOF")
86	test.That(t, z.Peek(0) == 0, "second peek must also yield error")
87}
88
89func TestLexerErrorReader(t *testing.T) {
90	z := NewLexer(test.NewErrorReader(0))
91	test.That(t, z.Peek(0) == 0, "first character must yield error")
92	test.T(t, z.Err(), test.ErrPlain, "error must be ErrPlain")
93	test.That(t, z.Peek(0) == 0, "second peek must also yield error")
94}
95
96func TestLexerBytes(t *testing.T) {
97	b := []byte{'t', 'e', 's', 't'}
98	z := NewLexerBytes(b)
99	test.That(t, z.Peek(4) == 0, "fifth character must yield NULL")
100}
101
102func TestLexerRestore(t *testing.T) {
103	b := []byte{'a', 'b', 'c', 'd'}
104	z := NewLexerBytes(b[:2])
105
106	test.T(t, len(z.buf), 3, "must have terminating NULL")
107	test.T(t, z.buf[2], byte(0), "must have terminating NULL")
108	test.Bytes(t, b, []byte{'a', 'b', 0, 'd'}, "terminating NULL overwrites underlying buffer")
109
110	z.Restore()
111	test.Bytes(t, b, []byte{'a', 'b', 'c', 'd'}, "terminating NULL has been restored")
112}
113