Skip to content

Commit 83fad07

Browse files
Rework evaluation attribute schema validation (#441)
1 parent 38a568d commit 83fad07

File tree

3 files changed

+226
-47
lines changed

3 files changed

+226
-47
lines changed

src/schema/evaluatorSchemas.ts

+43-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,52 @@
1-
import {ObjectType, NumberType, JsonObjectType} from '../validation';
1+
import {
2+
ObjectType,
3+
NumberType,
4+
JsonObjectType,
5+
UnionType,
6+
StringType,
7+
NullType,
8+
BooleanType,
9+
TypeSchema,
10+
ArrayType,
11+
} from '../validation';
12+
13+
function createJsonSchema(maximumDepth: number): TypeSchema {
14+
return new UnionType(
15+
new NullType(),
16+
new NumberType(),
17+
new BooleanType(),
18+
new StringType({maxLength: 255}),
19+
...(maximumDepth > 1
20+
? [
21+
new JsonObjectType({
22+
propertyNames: new UnionType(
23+
new NumberType(),
24+
new StringType({
25+
minLength: 1,
26+
maxLength: 50,
27+
}),
28+
),
29+
properties: createJsonSchema(maximumDepth - 1),
30+
}),
31+
new ArrayType({items: createJsonSchema(maximumDepth - 1)}),
32+
]
33+
: []
34+
),
35+
);
36+
}
237

338
export const evaluationOptionsSchema = new ObjectType({
439
properties: {
540
timeout: new NumberType({
641
integer: true,
742
minimum: 0,
843
}),
9-
attributes: new JsonObjectType(),
44+
attributes: new JsonObjectType({
45+
propertyNames: new StringType({
46+
minLength: 1,
47+
maxLength: 50,
48+
}),
49+
properties: createJsonSchema(5),
50+
}),
1051
},
1152
});

test/schemas/evaluationSchemas.test.ts

-45
This file was deleted.

test/schemas/evaluatorSchemas.test.ts

+183
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import {evaluationOptionsSchema} from '../../src/schema';
2+
import {EvaluationOptions} from '../../src/facade/evaluatorFacade';
3+
4+
describe('The evaluator options schema', () => {
5+
it.each<EvaluationOptions[]>([
6+
[{}],
7+
[{
8+
timeout: 1,
9+
}],
10+
[{
11+
attributes: {foo: 'bar'},
12+
}],
13+
[{
14+
timeout: 1,
15+
attributes: {foo: 'bar'},
16+
}],
17+
[{
18+
timeout: 1,
19+
attributes: {},
20+
}],
21+
[{
22+
timeout: 1,
23+
attributes: {
24+
['x'.repeat(50)]: 'x'.repeat(255),
25+
'multi-byte character': '♥'.repeat(255),
26+
arr: [
27+
null,
28+
123,
29+
'x'.repeat(255),
30+
true,
31+
false,
32+
],
33+
first: {
34+
second: {
35+
third: {
36+
'nested array': [
37+
null,
38+
123,
39+
'x'.repeat(255),
40+
true,
41+
false,
42+
],
43+
fourth: {
44+
fifth: '',
45+
},
46+
},
47+
},
48+
},
49+
},
50+
}],
51+
])('should allow %s', value => {
52+
function validate(): void {
53+
evaluationOptionsSchema.validate(value);
54+
}
55+
56+
expect(validate).not.toThrow();
57+
});
58+
59+
it.each([
60+
[
61+
{timeout: -1},
62+
'Expected a value greater than or equal to 0 at path \'/timeout\', actual -1.',
63+
],
64+
[
65+
{timeout: 1.2},
66+
'Expected value of type integer at path \'/timeout\', actual number.',
67+
],
68+
[
69+
{attributes: 0},
70+
'Expected a JSON object at path \'/attributes\', actual integer.',
71+
],
72+
[
73+
{
74+
attributes: {
75+
first: {
76+
second: {
77+
third: {
78+
fourth: {
79+
fifth: {},
80+
},
81+
},
82+
},
83+
},
84+
},
85+
},
86+
'Expected value of type null, number, boolean or string'
87+
+ ' at path \'/attributes/first/second/third/fourth/fifth\', actual Object.',
88+
],
89+
[
90+
{
91+
attributes: {
92+
first: [
93+
[
94+
[
95+
[
96+
['fifth level'],
97+
],
98+
],
99+
],
100+
],
101+
},
102+
},
103+
'Expected value of type null, number, boolean or string'
104+
+ ' at path \'/attributes/first/0/0/0/0\', actual array.',
105+
],
106+
[
107+
{
108+
attributes: {
109+
foo: undefined,
110+
},
111+
},
112+
'Expected a JSON object at path \'/attributes\', actual Object.',
113+
],
114+
[
115+
{
116+
attributes: {
117+
'': 'foo',
118+
},
119+
},
120+
'Expected at least 1 character at path \'/attributes/\', actual 0.',
121+
],
122+
[
123+
{
124+
attributes: {
125+
['x'.repeat(51)]: 'foo',
126+
},
127+
},
128+
`Expected at most 50 characters at path '/attributes/${'x'.repeat(51)}', actual 51.`,
129+
],
130+
[
131+
{
132+
attributes: 'foo',
133+
},
134+
'Expected a JSON object at path \'/attributes\', actual string.',
135+
],
136+
[
137+
{
138+
attributes: {
139+
string: 'x'.repeat(256),
140+
},
141+
},
142+
'Expected at most 255 characters at path \'/attributes/string\', actual 256.',
143+
],
144+
[
145+
{
146+
attributes: {
147+
first: {
148+
second: {
149+
third: {
150+
fourth: {
151+
fifth: 'x'.repeat(256),
152+
},
153+
},
154+
},
155+
},
156+
},
157+
},
158+
'Expected at most 255 characters at path \'/attributes/first/second/third/fourth/fifth\', actual 256.',
159+
],
160+
[
161+
{
162+
attributes: {
163+
first: [
164+
[
165+
[
166+
[
167+
'x'.repeat(256),
168+
],
169+
],
170+
],
171+
],
172+
},
173+
},
174+
'Expected at most 255 characters at path \'/attributes/first/0/0/0/0\', actual 256.',
175+
],
176+
])('should not allow %s', (value: Record<string, unknown>, message: string) => {
177+
function validate(): void {
178+
evaluationOptionsSchema.validate(value);
179+
}
180+
181+
expect(validate).toThrowWithMessage(Error, message);
182+
});
183+
});

0 commit comments

Comments
 (0)