-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtoken_test.go
More file actions
200 lines (191 loc) · 6.41 KB
/
token_test.go
File metadata and controls
200 lines (191 loc) · 6.41 KB
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
package template
import (
"strconv"
"testing"
)
func TestTokenTypeString(t *testing.T) {
tests := []struct {
name string
typ TokenType
want string
}{
{name: "TokenError", typ: TokenError, want: "ERROR"},
{name: "TokenEOF", typ: TokenEOF, want: "EOF"},
{name: "TokenText", typ: TokenText, want: "TEXT"},
{name: "TokenVarBegin", typ: TokenVarBegin, want: "VAR_BEGIN"},
{name: "TokenVarEnd", typ: TokenVarEnd, want: "VAR_END"},
{name: "TokenTagBegin", typ: TokenTagBegin, want: "TAG_BEGIN"},
{name: "TokenTagEnd", typ: TokenTagEnd, want: "TAG_END"},
{name: "TokenIdentifier", typ: TokenIdentifier, want: "IDENTIFIER"},
{name: "TokenString", typ: TokenString, want: "STRING"},
{name: "TokenNumber", typ: TokenNumber, want: "NUMBER"},
{name: "TokenSymbol", typ: TokenSymbol, want: "SYMBOL"},
{name: "unknown type 999", typ: TokenType(999), want: "UNKNOWN(" + strconv.Itoa(999) + ")"},
{name: "unknown type -1", typ: TokenType(-1), want: "UNKNOWN(" + strconv.Itoa(-1) + ")"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.typ.String()
if got != tt.want {
t.Errorf("TokenType(%d).String() = %q, want %q", tt.typ, got, tt.want)
}
})
}
}
func TestTokenString(t *testing.T) {
tests := []struct {
name string
token Token
want string
}{
{
name: "EOF token",
token: Token{Type: TokenEOF, Line: 1, Col: 1},
want: "EOF at line 1, col 1",
},
{
name: "EOF at different position",
token: Token{Type: TokenEOF, Line: 10, Col: 25},
want: "EOF at line 10, col 25",
},
{
name: "short identifier",
token: Token{Type: TokenIdentifier, Value: "name", Line: 1, Col: 5},
want: `IDENTIFIER("name") at line 1, col 5`,
},
{
name: "empty value",
token: Token{Type: TokenText, Value: "", Line: 1, Col: 1},
want: `TEXT("") at line 1, col 1`,
},
{
name: "exactly 20 characters not truncated",
token: Token{Type: TokenText, Value: "12345678901234567890", Line: 2, Col: 1},
want: `TEXT("12345678901234567890") at line 2, col 1`,
},
{
name: "21 characters truncated",
token: Token{Type: TokenText, Value: "123456789012345678901", Line: 3, Col: 1},
want: `TEXT("12345678901234567890"...) at line 3, col 1`,
},
{
name: "long text truncated",
token: Token{Type: TokenText, Value: "This is a very long text that exceeds twenty characters", Line: 1, Col: 1},
want: `TEXT("This is a very long "...) at line 1, col 1`,
},
{
name: "string literal token",
token: Token{Type: TokenString, Value: "hello", Line: 1, Col: 10},
want: `STRING("hello") at line 1, col 10`,
},
{
name: "number token",
token: Token{Type: TokenNumber, Value: "42", Line: 5, Col: 3},
want: `NUMBER("42") at line 5, col 3`,
},
{
name: "symbol token",
token: Token{Type: TokenSymbol, Value: "==", Line: 1, Col: 8},
want: `SYMBOL("==") at line 1, col 8`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.token.String()
if got != tt.want {
t.Errorf("Token.String() = %q, want %q", got, tt.want)
}
})
}
}
func TestIsKeyword(t *testing.T) {
tests := []struct {
name string
ident string
want bool
}{
// All valid keywords
{name: "in", ident: "in", want: true},
{name: "and", ident: "and", want: true},
{name: "or", ident: "or", want: true},
{name: "not", ident: "not", want: true},
{name: "true", ident: "true", want: true},
{name: "false", ident: "false", want: true},
{name: "if", ident: "if", want: true},
{name: "elif", ident: "elif", want: true},
{name: "else", ident: "else", want: true},
{name: "endif", ident: "endif", want: true},
{name: "for", ident: "for", want: true},
{name: "endfor", ident: "endfor", want: true},
{name: "break", ident: "break", want: true},
{name: "continue", ident: "continue", want: true},
// Non-keywords
{name: "regular identifier name", ident: "name", want: false},
{name: "regular identifier render", ident: "render", want: false},
{name: "empty string", ident: "", want: false},
{name: "uppercase IF is not keyword", ident: "IF", want: false},
{name: "uppercase TRUE is not keyword", ident: "TRUE", want: false},
{name: "mixed case Not is not keyword", ident: "Not", want: false},
{name: "partial keyword end", ident: "end", want: false},
{name: "partial keyword el", ident: "el", want: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := IsKeyword(tt.ident)
if got != tt.want {
t.Errorf("IsKeyword(%q) = %v, want %v", tt.ident, got, tt.want)
}
})
}
}
func TestIsSymbol(t *testing.T) {
tests := []struct {
name string
input string
want bool
}{
// Comparison operators
{name: "equal", input: "==", want: true},
{name: "not equal", input: "!=", want: true},
{name: "less than", input: "<", want: true},
{name: "greater than", input: ">", want: true},
{name: "less or equal", input: "<=", want: true},
{name: "greater or equal", input: ">=", want: true},
// Arithmetic operators
{name: "plus", input: "+", want: true},
{name: "minus", input: "-", want: true},
{name: "multiply", input: "*", want: true},
{name: "divide", input: "/", want: true},
{name: "modulo", input: "%", want: true},
// Logical operators
{name: "logical and", input: "&&", want: true},
{name: "logical or", input: "||", want: true},
{name: "logical not", input: "!", want: true},
// Other symbols
{name: "pipe", input: "|", want: true},
{name: "colon", input: ":", want: true},
{name: "comma", input: ",", want: true},
{name: "dot", input: ".", want: true},
{name: "left paren", input: "(", want: true},
{name: "right paren", input: ")", want: true},
{name: "left bracket", input: "[", want: true},
{name: "right bracket", input: "]", want: true},
{name: "assignment", input: "=", want: true},
// Non-symbols
{name: "word is not symbol", input: "abc", want: false},
{name: "empty string is not symbol", input: "", want: false},
{name: "triple equals is not symbol", input: "===", want: false},
{name: "power operator is not symbol", input: "**", want: false},
{name: "arrow is not symbol", input: "->", want: false},
{name: "left brace is not symbol", input: "{", want: false},
{name: "right brace is not symbol", input: "}", want: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := IsSymbol(tt.input)
if got != tt.want {
t.Errorf("IsSymbol(%q) = %v, want %v", tt.input, got, tt.want)
}
})
}
}