Skip to content

Commit 70de81f

Browse files
committed
chore: convert all stringify unit tests into a stringify test-suite
1 parent 250d4b8 commit 70de81f

File tree

10 files changed

+388
-216
lines changed

10 files changed

+388
-216
lines changed

src/compile.test.ts

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import Ajv from 'ajv'
22
import { describe, expect, test } from 'vitest'
3-
import type { CompileTestSuite } from '../test-suite/compile'
4-
import schema from '../test-suite/compile.schema.json'
3+
import type { CompileTestSuite } from '../test-suite/compile.test'
54
import suite from '../test-suite/compile.test.json'
5+
import schema from '../test-suite/compile.test.schema.json'
66
import { compile } from './compile'
77
import { buildFunction } from './functions'
88
import type { JSONQuery, JSONQueryCompileOptions } from './types'
@@ -25,32 +25,22 @@ function go(data: unknown, query: JSONQuery, options?: JSONQueryCompileOptions)
2525
return exec(data)
2626
}
2727

28-
describe('test-suite', () => {
29-
const groupByCategory = compile(['groupBy', ['get', 'category']])
30-
const testsByCategory = groupByCategory(suite.tests) as Record<string, CompileTestSuite['tests']>
28+
const groupByCategory = compile(['groupBy', ['get', 'category']])
29+
const testsByCategory = groupByCategory(suite.tests) as Record<string, CompileTestSuite['tests']>
3130

32-
for (const [category, tests] of Object.entries(testsByCategory)) {
33-
describe(category, () => {
34-
for (const currentTest of tests) {
35-
const { description, data, query, output } = currentTest
31+
for (const [category, tests] of Object.entries(testsByCategory)) {
32+
describe(category, () => {
33+
for (const currentTest of tests) {
34+
const { description, data, query, output } = currentTest
3635

37-
test(description, () => {
38-
const actualOutput = compile(query)(data)
36+
test(description, () => {
37+
const actualOutput = compile(query)(data)
3938

40-
expect({ data, query, output: actualOutput }).toEqual({ data, query, output })
41-
})
42-
}
43-
})
44-
}
45-
46-
test('should validate the test-suite itself against its JSON schema', () => {
47-
const ajv = new Ajv({ allErrors: false })
48-
const valid = ajv.validate(schema, suite)
49-
50-
expect(ajv.errors).toEqual(null)
51-
expect(valid).toEqual(true)
39+
expect({ data, query, output: actualOutput }).toEqual({ data, query, output })
40+
})
41+
}
5242
})
53-
})
43+
}
5444

5545
describe('error handling', () => {
5646
test('should throw a helpful error when a pipe contains a compile time error', () => {
@@ -196,3 +186,11 @@ describe('customization', () => {
196186
expect(go({ a: 2 }, ['aboutEq', ['get', 'a'], '2'], options)).toEqual(true)
197187
})
198188
})
189+
190+
test('should validate the compile test-suite against its JSON schema', () => {
191+
const ajv = new Ajv({ allErrors: false })
192+
const valid = ajv.validate(schema, suite)
193+
194+
expect(ajv.errors).toEqual(null)
195+
expect(valid).toEqual(true)
196+
})

src/parse.test.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import Ajv from 'ajv'
22
import { describe, expect, test } from 'vitest'
3-
import type { ParseTestException, ParseTestSuite } from '../test-suite/parse'
4-
import schema from '../test-suite/parse.schema.json'
3+
import type { ParseTestException, ParseTestSuite } from '../test-suite/parse.test'
54
import suite from '../test-suite/parse.test.json'
5+
import schema from '../test-suite/parse.test.schema.json'
66
import { compile } from './compile'
77
import { parse } from './parse'
88
import type { JSONQueryParseOptions } from './types'
@@ -40,16 +40,6 @@ for (const [category, testGroups] of Object.entries(testsByCategory)) {
4040
})
4141
}
4242

43-
describe('test-suite', () => {
44-
test('should validate the test-suite itself against its JSON schema', () => {
45-
const ajv = new Ajv({ allErrors: false })
46-
const valid = ajv.validate(schema, suite)
47-
48-
expect(ajv.errors).toEqual(null)
49-
expect(valid).toEqual(true)
50-
})
51-
})
52-
5343
describe('customization', () => {
5444
test('should parse a custom function', () => {
5545
const options: JSONQueryParseOptions = {
@@ -67,3 +57,13 @@ describe('customization', () => {
6757
expect(parse('.score ~= 8', options)).toEqual(['aboutEq', ['get', 'score'], 8])
6858
})
6959
})
60+
61+
describe('test-suite', () => {
62+
test('should validate the parse test-suite against its JSON schema', () => {
63+
const ajv = new Ajv({ allErrors: false })
64+
const valid = ajv.validate(schema, suite)
65+
66+
expect(ajv.errors).toEqual(null)
67+
expect(valid).toEqual(true)
68+
})
69+
})

src/stringify.test.ts

Lines changed: 28 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -1,193 +1,41 @@
1+
import Ajv from 'ajv'
12
import { describe, expect, test } from 'vitest'
3+
import type { StringifyTestSuite } from '../test-suite/stringify.test'
4+
import suite from '../test-suite/stringify.test.json'
5+
import schema from '../test-suite/stringify.test.schema.json'
6+
import { compile } from './compile'
27
import { stringify } from './stringify'
3-
import type { JSONQueryStringifyOptions } from './types'
48

5-
describe('stringify', () => {
6-
test('should stringify a function', () => {
7-
expect(stringify(['sort', ['get', 'age'], 'desc'])).toEqual('sort(.age, "desc")')
8-
expect(stringify(['filter', ['gt', ['get', 'age'], 18]])).toEqual('filter(.age > 18)')
9-
})
9+
const groupByCategory = compile(['groupBy', ['get', 'category']])
10+
const testsByCategory = groupByCategory(suite.groups) as Record<
11+
string,
12+
StringifyTestSuite['groups']
13+
>
1014

11-
test('should stringify a function with indentation', () => {
12-
expect(stringify(['sort', ['get', 'age'], 'desc'], { maxLineLength: 4 })).toEqual(
13-
'sort(\n .age,\n "desc"\n)'
14-
)
15-
})
15+
for (const [category, testGroups] of Object.entries(testsByCategory)) {
16+
describe(category, () => {
17+
for (const group of testGroups) {
18+
describe(group.description, () => {
19+
for (const currentTest of group.tests) {
20+
const description = `input = ${JSON.stringify(currentTest.input)}`
1621

17-
test('should stringify a nested function with indentation', () => {
18-
expect(
19-
stringify(['object', { sorted: ['sort', ['get', 'age'], 'desc'] }], { maxLineLength: 4 })
20-
).toEqual('{\n sorted: sort(\n .age,\n "desc"\n )\n}')
21-
})
22+
test(description, () => {
23+
const { input, output } = currentTest
2224

23-
test('should stringify a nested function having one argument with indentation', () => {
24-
expect(
25-
stringify(['map', ['object', { name: ['get', 'name'], city: ['get', 'address', 'city'] }]], {
26-
maxLineLength: 4
25+
expect(stringify(input, group.options)).toEqual(output)
26+
})
27+
}
2728
})
28-
).toEqual('map({\n name: .name,\n city: .address.city\n})')
29-
})
30-
31-
test('should stringify a property', () => {
32-
expect(stringify(['get'])).toEqual('get()')
33-
expect(stringify(['get', 'age'])).toEqual('.age')
34-
expect(stringify(['get', 'address', 'city'])).toEqual('.address.city')
35-
expect(stringify(['get', 'with space'])).toEqual('."with space"')
36-
expect(stringify(['get', 'with special !'])).toEqual('."with special !"')
37-
})
38-
39-
test('should stringify an operator', () => {
40-
expect(stringify(['add', 2, 3])).toEqual('(2 + 3)')
41-
})
42-
43-
test('should stringify an custom operator', () => {
44-
const options: JSONQueryStringifyOptions = {
45-
operators: { aboutEq: '~=' }
4629
}
47-
48-
expect(stringify(['aboutEq', 2, 3], options)).toEqual('(2 ~= 3)')
49-
expect(stringify(['filter', ['aboutEq', 2, 3]], options)).toEqual('filter(2 ~= 3)')
50-
expect(stringify(['object', { result: ['aboutEq', 2, 3] }], options)).toEqual(
51-
'{ result: (2 ~= 3) }'
52-
)
53-
expect(stringify(['eq', 2, 3], options)).toEqual('(2 == 3)')
54-
})
55-
56-
test('should stringify a pipe', () => {
57-
expect(stringify(['pipe', ['get', 'age'], ['average']])).toEqual('.age | average()')
58-
})
59-
60-
test('should stringify a pipe with indentation', () => {
61-
expect(stringify(['pipe', ['get', 'age'], ['average']], { maxLineLength: 10 })).toEqual(
62-
'.age\n | average()'
63-
)
64-
})
65-
66-
test('should stringify a nested pipe with indentation', () => {
67-
const query = ['object', { nested: ['pipe', ['get', 'age'], ['average']] }]
68-
expect(stringify(query, { maxLineLength: 10 })).toEqual('{\n nested: .age\n | average()\n}')
69-
})
70-
71-
test('should stringify an object', () => {
72-
expect(
73-
stringify(['object', { name: ['get', 'name'], city: ['get', 'address', 'city'] }])
74-
).toEqual('{ name: .name, city: .address.city }')
75-
})
76-
77-
test('should stringify an object with indentation', () => {
78-
const query = ['object', { name: ['get', 'name'], city: ['get', 'address', 'city'] }]
79-
80-
expect(stringify(query, { maxLineLength: 20 })).toEqual(
81-
'{\n name: .name,\n city: .address.city\n}'
82-
)
8330
})
31+
}
8432

85-
test('should stringify a nested object with indentation', () => {
86-
const query = [
87-
'object',
88-
{
89-
name: ['get', 'name'],
90-
address: [
91-
'object',
92-
{
93-
city: ['get', 'city'],
94-
street: ['get', 'street']
95-
}
96-
]
97-
}
98-
]
33+
describe('test-suite', () => {
34+
test('should validate the stringify test-suite against its JSON schema', () => {
35+
const ajv = new Ajv({ allErrors: false })
36+
const valid = ajv.validate(schema, suite)
9937

100-
expect(stringify(query, { maxLineLength: 4 })).toEqual(
101-
'{\n name: .name,\n address: {\n city: .city,\n street: .street\n }\n}'
102-
)
103-
})
104-
105-
test('should stringify an object with custom indentation', () => {
106-
const query = ['object', { name: ['get', 'name'], city: ['get', 'address', 'city'] }]
107-
108-
expect(stringify(query, { maxLineLength: 20, indentation: ' ' })).toEqual(
109-
'{\n name: .name,\n city: .address.city\n}'
110-
)
111-
112-
expect(stringify(query, { maxLineLength: 20, indentation: '\t' })).toEqual(
113-
'{\n\tname: .name,\n\tcity: .address.city\n}'
114-
)
115-
})
116-
117-
test('should stringify an array', () => {
118-
expect(stringify(['array', 1, 2, 3])).toEqual('[1, 2, 3]')
119-
expect(stringify(['array', ['add', 1, 2], 4, 5])).toEqual('[(1 + 2), 4, 5]')
120-
expect(stringify(['filter', ['in', ['get', 'age'], ['array', 19, 23]]])).toEqual(
121-
'filter(.age in [19, 23])'
122-
)
123-
})
124-
125-
test('should stringify an array with indentation', () => {
126-
expect(stringify(['array', 1, 2, 3], { maxLineLength: 4 })).toEqual('[\n 1,\n 2,\n 3\n]')
127-
})
128-
129-
test('should stringify a nested array with indentation', () => {
130-
expect(stringify(['object', { array: ['array', 1, 2, 3] }], { maxLineLength: 4 })).toEqual(
131-
'{\n array: [\n 1,\n 2,\n 3\n ]\n}'
132-
)
133-
})
134-
135-
test('should stringify a composed query (1)', () => {
136-
expect(
137-
stringify(['pipe', ['map', ['multiply', ['get', 'price'], ['get', 'quantity']]], ['sum']])
138-
).toEqual('map(.price * .quantity) | sum()')
139-
})
140-
141-
test('should stringify a composed query (2)', () => {
142-
expect(
143-
stringify([
144-
'pipe',
145-
['get', 'friends'],
146-
['filter', ['eq', ['get', 'city'], 'New York']],
147-
['sort', ['get', 'age']],
148-
['pick', ['get', 'name'], ['get', 'age']]
149-
])
150-
).toEqual(`.friends
151-
| filter(.city == "New York")
152-
| sort(.age)
153-
| pick(.name, .age)`)
154-
})
155-
156-
test('should stringify a composed query (3)', () => {
157-
expect(
158-
stringify(['filter', ['and', ['gte', ['get', 'age'], 23], ['lte', ['get', 'age'], 27]]])
159-
).toEqual('filter((.age >= 23) and (.age <= 27))')
160-
})
161-
162-
test('should stringify a composed query (4)', () => {
163-
expect(
164-
stringify([
165-
'pipe',
166-
['get', 'friends'],
167-
[
168-
'object',
169-
{
170-
names: ['map', ['get', 'name']],
171-
count: ['size'],
172-
averageAge: ['pipe', ['map', ['get', 'age']], ['average']]
173-
}
174-
]
175-
])
176-
).toEqual(
177-
'.friends\n | {\n names: map(.name),\n count: size(),\n averageAge: map(.age) | average()\n }'
178-
)
179-
})
180-
181-
test('should stringify a composed query (5)', () => {
182-
expect(
183-
stringify([
184-
'object',
185-
{
186-
name: ['get', 'name'],
187-
city: ['get', 'address', 'city'],
188-
averageAge: ['pipe', ['map', ['get', 'age']], ['average']]
189-
}
190-
])
191-
).toEqual('{\n name: .name,\n city: .address.city,\n averageAge: map(.age) | average()\n}')
38+
expect(ajv.errors).toEqual(null)
39+
expect(valid).toEqual(true)
19240
})
19341
})
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

test-suite/stringify.test.d.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { JSONQuery, JSONQueryStringifyOptions } from '../src/types'
2+
3+
export interface StringifyTest {
4+
input: JSONQuery
5+
output: string
6+
}
7+
8+
export interface StringifyTestGroup {
9+
category: string
10+
description: string
11+
options?: JSONQueryStringifyOptions
12+
tests: StringifyTest[]
13+
}
14+
15+
export interface StringifyTestSuite {
16+
updated: string
17+
groups: StringifyTestGroup[]
18+
}

0 commit comments

Comments
 (0)