Skip to content

Commit 345597e

Browse files
committed
chore: add tests
1 parent 49482ae commit 345597e

3 files changed

Lines changed: 241 additions & 1 deletion

File tree

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { expect, it } from 'vitest'
2+
import { compile } from '../../test/__helper'
3+
4+
it('basic', async () => {
5+
expect(await compile('hello world')).toMatchInlineSnapshot(
6+
`""use strict";return(async()=>{let s="";s+="hello world";return s;})();"`,
7+
)
8+
expect(await compile(' hello world ')).toMatchInlineSnapshot(
9+
`""use strict";return(async()=>{let s="";s+=" hello world ";return s;})();"`,
10+
)
11+
expect(await compile(' hello\nworld ')).toMatchInlineSnapshot(
12+
`""use strict";return(async()=>{let s="";s+=" hello\\nworld ";return s;})();"`,
13+
)
14+
})
15+
16+
it('whitespace control', async () => {
17+
expect(await compile(' {{ t -}} hello world {{- t }} ')).toMatchInlineSnapshot(
18+
`""use strict";return(async()=>{let s="";s+=" ";s+="hello world";s+=" ";return s;})();"`,
19+
)
20+
expect(await compile(' {{- t }} hello world {{ t -}} ')).toMatchInlineSnapshot(
21+
`""use strict";return(async()=>{let s="";s+=" hello world ";return s;})();"`,
22+
)
23+
expect(await compile(' {{- t -}} hello world {{- t -}} ')).toMatchInlineSnapshot(
24+
`""use strict";return(async()=>{let s="";s+="hello world";return s;})();"`,
25+
)
26+
})
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
import type { EngineOptions } from './types'
2+
import { describe, expect, it } from 'vitest'
3+
import { Validator } from './validator'
4+
5+
describe('validator', () => {
6+
const defaultOptions: Required<EngineOptions> = {
7+
debug: false,
8+
globals: {},
9+
filters: {},
10+
tags: {},
11+
strictMode: false,
12+
autoEscape: true,
13+
stripComments: false,
14+
trimWhitespace: false,
15+
loader: async () => '',
16+
cache: true,
17+
}
18+
19+
it('should initialize with empty expected array', () => {
20+
const validator = new Validator(defaultOptions)
21+
expect(validator.expected).toEqual([])
22+
expect(validator.options).toBe(defaultOptions)
23+
})
24+
25+
describe('expect', () => {
26+
it('should add expected token names', () => {
27+
const validator = new Validator(defaultOptions)
28+
validator.expect(['foo', 'bar'])
29+
expect(validator.expected).toEqual([['foo', 'bar']])
30+
})
31+
32+
it('should support multiple expectations', () => {
33+
const validator = new Validator(defaultOptions)
34+
validator.expect(['foo', 'bar'])
35+
validator.expect(['baz'])
36+
expect(validator.expected).toEqual([['foo', 'bar'], ['baz']])
37+
})
38+
})
39+
40+
describe('matchAny', () => {
41+
it('should return true if any expected token matches any provided name', () => {
42+
const validator = new Validator(defaultOptions)
43+
validator.expect(['foo', 'bar'])
44+
validator.expect(['baz'])
45+
46+
expect(validator.matchAny(['foo'])).toBe(true)
47+
expect(validator.matchAny(['bar'])).toBe(true)
48+
expect(validator.matchAny(['baz'])).toBe(true)
49+
expect(validator.matchAny(['foo', 'unknown'])).toBe(true)
50+
})
51+
52+
it('should return false if no expected tokens match any provided name', () => {
53+
const validator = new Validator(defaultOptions)
54+
validator.expect(['foo', 'bar'])
55+
validator.expect(['baz'])
56+
57+
expect(validator.matchAny(['unknown'])).toBe(false)
58+
expect(validator.matchAny(['other', 'unknown'])).toBe(false)
59+
})
60+
61+
it('should return false when no expectations exist', () => {
62+
const validator = new Validator(defaultOptions)
63+
expect(validator.matchAny(['foo'])).toBe(false)
64+
})
65+
66+
it('should return false when provided names are empty', () => {
67+
const validator = new Validator(defaultOptions)
68+
validator.expect(['foo'])
69+
expect(validator.matchAny([])).toBe(false)
70+
})
71+
})
72+
73+
describe('match', () => {
74+
it('should return true if the last expected token matches any provided name', () => {
75+
const validator = new Validator(defaultOptions)
76+
validator.expect(['foo', 'bar'])
77+
validator.expect(['baz'])
78+
79+
expect(validator.match(['baz'])).toBe(true)
80+
expect(validator.match(['baz', 'unknown'])).toBe(true)
81+
})
82+
83+
it('should return false if the last expected token does not match any provided name', () => {
84+
const validator = new Validator(defaultOptions)
85+
validator.expect(['foo', 'bar'])
86+
validator.expect(['baz'])
87+
88+
expect(validator.match(['foo'])).toBe(false)
89+
expect(validator.match(['bar'])).toBe(false)
90+
expect(validator.match(['unknown'])).toBe(false)
91+
})
92+
93+
it('should return undefined when no expectations exist', () => {
94+
const validator = new Validator(defaultOptions)
95+
expect(validator.match(['foo'])).toBeUndefined()
96+
})
97+
98+
it('should return false when provided names are empty', () => {
99+
const validator = new Validator(defaultOptions)
100+
validator.expect(['foo'])
101+
expect(validator.match([])).toBe(false)
102+
})
103+
})
104+
105+
describe('consume', () => {
106+
it('should consume and return true when last expected token matches', () => {
107+
const validator = new Validator(defaultOptions)
108+
validator.expect(['foo', 'bar'])
109+
validator.expect(['baz'])
110+
111+
expect(validator.consume(['baz'])).toBe(true)
112+
expect(validator.expected).toEqual([['foo', 'bar']])
113+
})
114+
115+
it('should not consume and return false when last expected token does not match', () => {
116+
const validator = new Validator(defaultOptions)
117+
validator.expect(['foo', 'bar'])
118+
validator.expect(['baz'])
119+
120+
expect(validator.consume(['foo'])).toBe(false)
121+
expect(validator.expected).toEqual([['foo', 'bar'], ['baz']])
122+
})
123+
124+
it('should return false when no expectations exist', () => {
125+
const validator = new Validator(defaultOptions)
126+
expect(validator.consume(['foo'])).toBe(false)
127+
})
128+
129+
it('should consume multiple expectations in LIFO order', () => {
130+
const validator = new Validator(defaultOptions)
131+
validator.expect(['foo'])
132+
validator.expect(['bar'])
133+
validator.expect(['baz'])
134+
135+
expect(validator.consume(['baz'])).toBe(true)
136+
expect(validator.expected).toEqual([['foo'], ['bar']])
137+
138+
expect(validator.consume(['bar'])).toBe(true)
139+
expect(validator.expected).toEqual([['foo']])
140+
141+
expect(validator.consume(['foo'])).toBe(true)
142+
expect(validator.expected).toEqual([])
143+
})
144+
})
145+
146+
describe('validate', () => {
147+
it('should not throw when all expectations are consumed', () => {
148+
const validator = new Validator(defaultOptions)
149+
validator.expect(['foo'])
150+
validator.consume(['foo'])
151+
152+
expect(() => validator.validate()).not.toThrow()
153+
})
154+
155+
it('should throw when expectations remain unconsumed', () => {
156+
const validator = new Validator(defaultOptions)
157+
validator.expect(['foo'])
158+
159+
expect(() => validator.validate()).toThrow('expected tokens foo, but got nothing')
160+
})
161+
162+
it('should throw with multiple unconsumed expectations', () => {
163+
const validator = new Validator(defaultOptions)
164+
validator.expect(['foo', 'bar'])
165+
validator.expect(['baz'])
166+
167+
expect(() => validator.validate()).toThrow('expected tokens foo, bar, baz, but got nothing')
168+
})
169+
170+
it('should not throw when no expectations were set', () => {
171+
const validator = new Validator(defaultOptions)
172+
expect(() => validator.validate()).not.toThrow()
173+
})
174+
})
175+
176+
describe('integration scenarios', () => {
177+
it('should handle complex validation workflow', () => {
178+
const validator = new Validator(defaultOptions)
179+
180+
// Set up nested expectations
181+
validator.expect(['if', 'for'])
182+
validator.expect(['endif', 'endfor'])
183+
184+
// Check if any tokens match
185+
expect(validator.matchAny(['if', 'other'])).toBe(true)
186+
expect(validator.matchAny(['other', 'unknown'])).toBe(false)
187+
188+
// Match specific last expectation
189+
expect(validator.match(['endif'])).toBe(true)
190+
expect(validator.match(['if'])).toBe(false)
191+
192+
// Consume the last expectation
193+
expect(validator.consume(['endif'])).toBe(true)
194+
expect(validator.expected).toEqual([['if', 'for']])
195+
196+
// Now the first expectation becomes the last
197+
expect(validator.match(['if'])).toBe(true)
198+
expect(validator.consume(['for'])).toBe(true)
199+
expect(validator.expected).toEqual([])
200+
201+
// Validation should pass
202+
expect(() => validator.validate()).not.toThrow()
203+
})
204+
205+
it('should handle empty token arrays', () => {
206+
const validator = new Validator(defaultOptions)
207+
validator.expect([])
208+
209+
expect(validator.matchAny(['foo'])).toBe(false)
210+
expect(validator.match(['foo'])).toBe(false)
211+
expect(validator.consume(['foo'])).toBe(false)
212+
})
213+
})
214+
})

packages/template/src/validator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export class Validator {
2929

3030
validate() {
3131
if (this.expected.length) {
32-
throw new Error(`expected tokens ${this.expected.join(', ')}, but got nothing`)
32+
throw new Error(`expected tokens ${this.expected.flatMap(e => e).join(', ')}, but got nothing`)
3333
}
3434
}
3535
}

0 commit comments

Comments
 (0)