Pop-up dictionary browser extension for language learning. Successor to Yomichan. (PERSONAL FORK)
1/*
2 * Copyright (C) 2023-2025 Yomitan Authors
3 * Copyright (C) 2020-2022 Yomichan Authors
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19import {describe, expect, test} from 'vitest';
20import {JsonSchema} from '../ext/js/data/json-schema.js';
21
22/**
23 * @param {import('ext/json-schema').Schema} schema
24 * @param {unknown} value
25 * @returns {boolean}
26 */
27function schemaValidate(schema, value) {
28 return new JsonSchema(schema).isValid(value);
29}
30
31/**
32 * @param {import('ext/json-schema').Schema} schema
33 * @param {unknown} value
34 * @returns {import('ext/json-schema').Value}
35 */
36function getValidValueOrDefault(schema, value) {
37 return new JsonSchema(schema).getValidValueOrDefault(value);
38}
39
40/**
41 * @param {import('ext/json-schema').Schema} schema
42 * @param {import('ext/json-schema').Value} value
43 * @returns {import('ext/json-schema').Value}
44 */
45function createProxy(schema, value) {
46 return new JsonSchema(schema).createProxy(value);
47}
48
49
50describe('JsonSchema', () => {
51 describe('Validate1', () => {
52 /** @type {import('ext/json-schema').Schema} */
53 const schema = {
54 allOf: [
55 {
56 type: 'number',
57 },
58 {
59 anyOf: [
60 {minimum: 10, maximum: 100},
61 {minimum: -100, maximum: -10},
62 ],
63 },
64 {
65 oneOf: [
66 {multipleOf: 3},
67 {multipleOf: 5},
68 ],
69 },
70 {
71 not: {
72 anyOf: [
73 {multipleOf: 20},
74 ],
75 },
76 },
77 ],
78 };
79
80 /**
81 * @param {number} value
82 * @returns {boolean}
83 */
84 const jsValidate = (value) => {
85 return (
86 typeof value === 'number' &&
87 (
88 (value >= 10 && value <= 100) ||
89 (value >= -100 && value <= -10)
90 ) &&
91 (
92 (
93 (value % 3) === 0 ||
94 (value % 5) === 0
95 ) &&
96 (value % 15) !== 0
97 ) &&
98 (value % 20) !== 0
99 );
100 };
101
102 test('works as expected', () => {
103 for (let i = -111; i <= 111; i++) {
104 const actual = schemaValidate(schema, i);
105 const expected = jsValidate(i);
106 expect(actual).toStrictEqual(expected);
107 }
108 });
109 });
110
111 describe('Validate2', () => {
112 /* eslint-disable @stylistic/no-multi-spaces */
113 /** @type {{schema: import('ext/json-schema').Schema, inputs: {expected: boolean, value: unknown}[]}[]} */
114 const data = [
115 // String tests
116 {
117 schema: {
118 type: 'string',
119 },
120 inputs: [
121 {expected: false, value: null},
122 {expected: false, value: void 0},
123 {expected: false, value: 0},
124 {expected: false, value: {}},
125 {expected: false, value: []},
126 {expected: true, value: ''},
127 ],
128 },
129 {
130 schema: {
131 type: 'string',
132 minLength: 2,
133 },
134 inputs: [
135 {expected: false, value: ''},
136 {expected: false, value: '1'},
137 {expected: true, value: '12'},
138 {expected: true, value: '123'},
139 ],
140 },
141 {
142 schema: {
143 type: 'string',
144 maxLength: 2,
145 },
146 inputs: [
147 {expected: true, value: ''},
148 {expected: true, value: '1'},
149 {expected: true, value: '12'},
150 {expected: false, value: '123'},
151 ],
152 },
153 {
154 schema: {
155 type: 'string',
156 pattern: 'test',
157 },
158 inputs: [
159 {expected: false, value: ''},
160 {expected: true, value: 'test'},
161 {expected: false, value: 'TEST'},
162 {expected: true, value: 'ABCtestDEF'},
163 {expected: false, value: 'ABCTESTDEF'},
164 ],
165 },
166 {
167 schema: {
168 type: 'string',
169 pattern: '^test$',
170 },
171 inputs: [
172 {expected: false, value: ''},
173 {expected: true, value: 'test'},
174 {expected: false, value: 'TEST'},
175 {expected: false, value: 'ABCtestDEF'},
176 {expected: false, value: 'ABCTESTDEF'},
177 ],
178 },
179 {
180 schema: {
181 type: 'string',
182 pattern: '^test$',
183 patternFlags: 'i',
184 },
185 inputs: [
186 {expected: false, value: ''},
187 {expected: true, value: 'test'},
188 {expected: true, value: 'TEST'},
189 {expected: false, value: 'ABCtestDEF'},
190 {expected: false, value: 'ABCTESTDEF'},
191 ],
192 },
193 {
194 schema: {
195 type: 'string',
196 pattern: '*',
197 },
198 inputs: [
199 {expected: false, value: ''},
200 ],
201 },
202 {
203 schema: {
204 type: 'string',
205 pattern: '.',
206 patternFlags: '?',
207 },
208 inputs: [
209 {expected: false, value: ''},
210 ],
211 },
212
213 // Const tests
214 {
215 schema: {
216 const: 32,
217 },
218 inputs: [
219 {expected: true, value: 32},
220 {expected: false, value: 0},
221 {expected: false, value: '32'},
222 {expected: false, value: null},
223 {expected: false, value: {a: 'b'}},
224 {expected: false, value: [1, 2, 3]},
225 ],
226 },
227 {
228 schema: {
229 const: '32',
230 },
231 inputs: [
232 {expected: false, value: 32},
233 {expected: false, value: 0},
234 {expected: true, value: '32'},
235 {expected: false, value: null},
236 {expected: false, value: {a: 'b'}},
237 {expected: false, value: [1, 2, 3]},
238 ],
239 },
240 {
241 schema: {
242 const: null,
243 },
244 inputs: [
245 {expected: false, value: 32},
246 {expected: false, value: 0},
247 {expected: false, value: '32'},
248 {expected: true, value: null},
249 {expected: false, value: {a: 'b'}},
250 {expected: false, value: [1, 2, 3]},
251 ],
252 },
253 {
254 schema: {
255 const: {a: 'b'},
256 },
257 inputs: [
258 {expected: false, value: 32},
259 {expected: false, value: 0},
260 {expected: false, value: '32'},
261 {expected: false, value: null},
262 {expected: false, value: {a: 'b'}},
263 {expected: false, value: [1, 2, 3]},
264 ],
265 },
266 {
267 schema: {
268 const: [1, 2, 3],
269 },
270 inputs: [
271 {expected: false, value: 32},
272 {expected: false, value: 0},
273 {expected: false, value: '32'},
274 {expected: false, value: null},
275 {expected: false, value: {a: 'b'}},
276 {expected: false, value: [1, 2, 3]},
277 ],
278 },
279
280 // Array contains tests
281 {
282 schema: {
283 type: 'array',
284 contains: {const: 32},
285 },
286 inputs: [
287 {expected: false, value: []},
288 {expected: true, value: [32]},
289 {expected: true, value: [1, 32]},
290 {expected: true, value: [1, 32, 1]},
291 {expected: false, value: [33]},
292 {expected: false, value: [1, 33]},
293 {expected: false, value: [1, 33, 1]},
294 ],
295 },
296
297 // Number limits tests
298 {
299 schema: {
300 type: 'number',
301 minimum: 0,
302 },
303 inputs: [
304 {expected: false, value: -1},
305 {expected: true, value: 0},
306 {expected: true, value: 1},
307 ],
308 },
309 {
310 schema: {
311 type: 'number',
312 exclusiveMinimum: 0,
313 },
314 inputs: [
315 {expected: false, value: -1},
316 {expected: false, value: 0},
317 {expected: true, value: 1},
318 ],
319 },
320 {
321 schema: {
322 type: 'number',
323 maximum: 0,
324 },
325 inputs: [
326 {expected: true, value: -1},
327 {expected: true, value: 0},
328 {expected: false, value: 1},
329 ],
330 },
331 {
332 schema: {
333 type: 'number',
334 exclusiveMaximum: 0,
335 },
336 inputs: [
337 {expected: true, value: -1},
338 {expected: false, value: 0},
339 {expected: false, value: 1},
340 ],
341 },
342
343 // Integer limits tests
344 {
345 schema: {
346 type: 'integer',
347 minimum: 0,
348 },
349 inputs: [
350 {expected: false, value: -1},
351 {expected: true, value: 0},
352 {expected: true, value: 1},
353 ],
354 },
355 {
356 schema: {
357 type: 'integer',
358 exclusiveMinimum: 0,
359 },
360 inputs: [
361 {expected: false, value: -1},
362 {expected: false, value: 0},
363 {expected: true, value: 1},
364 ],
365 },
366 {
367 schema: {
368 type: 'integer',
369 maximum: 0,
370 },
371 inputs: [
372 {expected: true, value: -1},
373 {expected: true, value: 0},
374 {expected: false, value: 1},
375 ],
376 },
377 {
378 schema: {
379 type: 'integer',
380 exclusiveMaximum: 0,
381 },
382 inputs: [
383 {expected: true, value: -1},
384 {expected: false, value: 0},
385 {expected: false, value: 1},
386 ],
387 },
388 {
389 schema: {
390 type: 'integer',
391 multipleOf: 2,
392 },
393 inputs: [
394 {expected: true, value: -2},
395 {expected: false, value: -1},
396 {expected: true, value: 0},
397 {expected: false, value: 1},
398 {expected: true, value: 2},
399 ],
400 },
401
402 // Numeric type tests
403 {
404 schema: {
405 type: 'number',
406 },
407 inputs: [
408 {expected: true, value: 0},
409 {expected: true, value: 0.5},
410 {expected: true, value: 1},
411 {expected: false, value: '0'},
412 {expected: false, value: null},
413 {expected: false, value: []},
414 {expected: false, value: {}},
415 ],
416 },
417 {
418 schema: {
419 type: 'integer',
420 },
421 inputs: [
422 {expected: true, value: 0},
423 {expected: false, value: 0.5},
424 {expected: true, value: 1},
425 {expected: false, value: '0'},
426 {expected: false, value: null},
427 {expected: false, value: []},
428 {expected: false, value: {}},
429 ],
430 },
431
432 // Reference tests
433 {
434 schema: {
435 definitions: {
436 example: {
437 type: 'number',
438 },
439 },
440 $ref: '#/definitions/example',
441 },
442 inputs: [
443 {expected: true, value: 0},
444 {expected: true, value: 0.5},
445 {expected: true, value: 1},
446 {expected: false, value: '0'},
447 {expected: false, value: null},
448 {expected: false, value: []},
449 {expected: false, value: {}},
450 ],
451 },
452 {
453 schema: {
454 definitions: {
455 example: {
456 type: 'integer',
457 },
458 },
459 $ref: '#/definitions/example',
460 },
461 inputs: [
462 {expected: true, value: 0},
463 {expected: false, value: 0.5},
464 {expected: true, value: 1},
465 {expected: false, value: '0'},
466 {expected: false, value: null},
467 {expected: false, value: []},
468 {expected: false, value: {}},
469 ],
470 },
471 {
472 schema: {
473 definitions: {
474 example: {
475 type: 'object',
476 additionalProperties: false,
477 properties: {
478 test: {
479 $ref: '#/definitions/example',
480 },
481 },
482 },
483 },
484 $ref: '#/definitions/example',
485 },
486 inputs: [
487 {expected: false, value: 0},
488 {expected: false, value: 0.5},
489 {expected: false, value: 1},
490 {expected: false, value: '0'},
491 {expected: false, value: null},
492 {expected: false, value: []},
493 {expected: true, value: {}},
494 {expected: false, value: {test: 0}},
495 {expected: false, value: {test: 0.5}},
496 {expected: false, value: {test: 1}},
497 {expected: false, value: {test: '0'}},
498 {expected: false, value: {test: null}},
499 {expected: false, value: {test: []}},
500 {expected: true, value: {test: {}}},
501 {expected: true, value: {test: {test: {}}}},
502 {expected: true, value: {test: {test: {test: {}}}}},
503 ],
504 },
505 ];
506 /* eslint-enable @stylistic/no-multi-spaces */
507
508 describe.each(data)('Schema %#', ({schema, inputs}) => {
509 test.each(inputs)(`schemaValidate(${JSON.stringify(schema)}, $value) -> $expected`, ({expected, value}) => {
510 const actual = schemaValidate(schema, value);
511 expect(actual).toStrictEqual(expected);
512 });
513 });
514 });
515
516 describe('GetValidValueOrDefault1', () => {
517 /** @type {{schema: import('ext/json-schema').Schema, inputs: [value: unknown, expected: unknown][]}[]} */
518 const data = [
519 // Test value defaulting on objects with additionalProperties=false
520 {
521 schema: {
522 type: 'object',
523 required: ['test'],
524 properties: {
525 test: {
526 type: 'string',
527 default: 'default',
528 },
529 },
530 additionalProperties: false,
531 },
532 inputs: [
533 [
534 void 0,
535 {test: 'default'},
536 ],
537 [
538 null,
539 {test: 'default'},
540 ],
541 [
542 0,
543 {test: 'default'},
544 ],
545 [
546 '',
547 {test: 'default'},
548 ],
549 [
550 [],
551 {test: 'default'},
552 ],
553 [
554 {},
555 {test: 'default'},
556 ],
557 [
558 {test: 'value'},
559 {test: 'value'},
560 ],
561 [
562 {test2: 'value2'},
563 {test: 'default'},
564 ],
565 [
566 {test: 'value', test2: 'value2'},
567 {test: 'value'},
568 ],
569 ],
570 },
571
572 // Test value defaulting on objects with additionalProperties=true
573 {
574 schema: {
575 type: 'object',
576 required: ['test'],
577 properties: {
578 test: {
579 type: 'string',
580 default: 'default',
581 },
582 },
583 additionalProperties: true,
584 },
585 inputs: [
586 [
587 {},
588 {test: 'default'},
589 ],
590 [
591 {test: 'value'},
592 {test: 'value'},
593 ],
594 [
595 {test2: 'value2'},
596 {test: 'default', test2: 'value2'},
597 ],
598 [
599 {test: 'value', test2: 'value2'},
600 {test: 'value', test2: 'value2'},
601 ],
602 ],
603 },
604
605 // Test value defaulting on objects with additionalProperties={schema}
606 {
607 schema: {
608 type: 'object',
609 required: ['test'],
610 properties: {
611 test: {
612 type: 'string',
613 default: 'default',
614 },
615 },
616 additionalProperties: {
617 type: 'number',
618 default: 10,
619 },
620 },
621 inputs: [
622 [
623 {},
624 {test: 'default'},
625 ],
626 [
627 {test: 'value'},
628 {test: 'value'},
629 ],
630 [
631 {test2: 'value2'},
632 {test: 'default', test2: 10},
633 ],
634 [
635 {test: 'value', test2: 'value2'},
636 {test: 'value', test2: 10},
637 ],
638 [
639 {test2: 2},
640 {test: 'default', test2: 2},
641 ],
642 [
643 {test: 'value', test2: 2},
644 {test: 'value', test2: 2},
645 ],
646 [
647 {test: 'value', test2: 2, test3: null},
648 {test: 'value', test2: 2, test3: 10},
649 ],
650 [
651 {test: 'value', test2: 2, test3: void 0},
652 {test: 'value', test2: 2, test3: 10},
653 ],
654 ],
655 },
656
657 // Test value defaulting where hasOwnProperty is false
658 {
659 schema: {
660 type: 'object',
661 required: ['test'],
662 properties: {
663 test: {
664 type: 'string',
665 default: 'default',
666 },
667 },
668 },
669 inputs: [
670 [
671 {},
672 {test: 'default'},
673 ],
674 [
675 {test: 'value'},
676 {test: 'value'},
677 ],
678 [
679 Object.create({test: 'value'}),
680 {test: 'default'},
681 ],
682 ],
683 },
684 {
685 schema: {
686 type: 'object',
687 required: ['toString'],
688 properties: {
689 toString: /** @type {import('ext/json-schema').SchemaObject} */ ({
690 type: 'string',
691 default: 'default',
692 }),
693 },
694 },
695 inputs: [
696 [
697 {},
698 {toString: 'default'},
699 ],
700 [
701 {toString: 'value'},
702 {toString: 'value'},
703 ],
704 [
705 Object.create({toString: 'value'}),
706 {toString: 'default'},
707 ],
708 ],
709 },
710
711 // Test enum
712 {
713 schema: {
714 type: 'object',
715 required: ['test'],
716 properties: {
717 test: {
718 type: 'string',
719 default: 'value1',
720 enum: ['value1', 'value2', 'value3'],
721 },
722 },
723 },
724 inputs: [
725 [
726 {test: 'value1'},
727 {test: 'value1'},
728 ],
729 [
730 {test: 'value2'},
731 {test: 'value2'},
732 ],
733 [
734 {test: 'value3'},
735 {test: 'value3'},
736 ],
737 [
738 {test: 'value4'},
739 {test: 'value1'},
740 ],
741 ],
742 },
743
744 // Test valid vs invalid default
745 {
746 schema: {
747 type: 'object',
748 required: ['test'],
749 properties: {
750 test: {
751 type: 'integer',
752 default: 2,
753 minimum: 1,
754 },
755 },
756 },
757 inputs: [
758 [
759 {test: -1},
760 {test: 2},
761 ],
762 ],
763 },
764 {
765 schema: {
766 type: 'object',
767 required: ['test'],
768 properties: {
769 test: {
770 type: 'integer',
771 default: 1,
772 minimum: 2,
773 },
774 },
775 },
776 inputs: [
777 [
778 {test: -1},
779 {test: -1},
780 ],
781 ],
782 },
783
784 // Test references
785 {
786 schema: {
787 definitions: {
788 example: {
789 type: 'number',
790 default: 0,
791 },
792 },
793 $ref: '#/definitions/example',
794 },
795 inputs: [
796 [
797 1,
798 1,
799 ],
800 [
801 null,
802 0,
803 ],
804 [
805 'test',
806 0,
807 ],
808 [
809 {test: 'value'},
810 0,
811 ],
812 ],
813 },
814 {
815 schema: {
816 definitions: {
817 example: {
818 type: 'object',
819 additionalProperties: false,
820 properties: {
821 test: {
822 $ref: '#/definitions/example',
823 },
824 },
825 },
826 },
827 $ref: '#/definitions/example',
828 },
829 inputs: [
830 [
831 1,
832 {},
833 ],
834 [
835 null,
836 {},
837 ],
838 [
839 'test',
840 {},
841 ],
842 [
843 {},
844 {},
845 ],
846 [
847 {test: {}},
848 {test: {}},
849 ],
850 [
851 {test: 'value'},
852 {test: {}},
853 ],
854 [
855 {test: {test: {}}},
856 {test: {test: {}}},
857 ],
858 ],
859 },
860 ];
861
862 describe.each(data)('Schema %#', ({schema, inputs}) => {
863 test.each(inputs)(`getValidValueOrDefault(${JSON.stringify(schema)}, %o) -> %o`, (value, expected) => {
864 const actual = getValidValueOrDefault(schema, value);
865 expect(actual).toStrictEqual(expected);
866 });
867 });
868 });
869
870 describe('Proxy1', () => {
871 /* eslint-disable @stylistic/no-multi-spaces */
872 /** @type {{schema: import('ext/json-schema').Schema, tests: {error: boolean, value?: import('ext/json-schema').Value, action: (value: import('core').SafeAny) => void}[]}[]} */
873 const data = [
874 // Object tests
875 {
876 schema: {
877 type: 'object',
878 required: ['test'],
879 additionalProperties: false,
880 properties: {
881 test: {
882 type: 'string',
883 default: 'default',
884 },
885 },
886 },
887 tests: [
888 {error: false, value: {test: 'default'}, action: (value) => { value.test = 'string'; }},
889 {error: true, value: {test: 'default'}, action: (value) => { value.test = null; }},
890 {error: true, value: {test: 'default'}, action: (value) => { delete value.test; }},
891 {error: true, value: {test: 'default'}, action: (value) => { value.test2 = 'string'; }},
892 {error: false, value: {test: 'default'}, action: (value) => { delete value.test2; }},
893 ],
894 },
895 {
896 schema: {
897 type: 'object',
898 required: ['test'],
899 additionalProperties: true,
900 properties: {
901 test: {
902 type: 'string',
903 default: 'default',
904 },
905 },
906 },
907 tests: [
908 {error: false, value: {test: 'default'}, action: (value) => { value.test = 'string'; }},
909 {error: true, value: {test: 'default'}, action: (value) => { value.test = null; }},
910 {error: true, value: {test: 'default'}, action: (value) => { delete value.test; }},
911 {error: false, value: {test: 'default'}, action: (value) => { value.test2 = 'string'; }},
912 {error: false, value: {test: 'default'}, action: (value) => { delete value.test2; }},
913 ],
914 },
915 {
916 schema: {
917 type: 'object',
918 required: ['test1'],
919 additionalProperties: false,
920 properties: {
921 test1: {
922 type: 'object',
923 required: ['test2'],
924 additionalProperties: false,
925 properties: {
926 test2: {
927 type: 'object',
928 required: ['test3'],
929 additionalProperties: false,
930 properties: {
931 test3: {
932 type: 'string',
933 default: 'default',
934 },
935 },
936 },
937 },
938 },
939 },
940 },
941 tests: [
942 {error: false, action: (value) => { value.test1.test2.test3 = 'string'; }},
943 {error: true, action: (value) => { value.test1.test2.test3 = null; }},
944 {error: true, action: (value) => { delete value.test1.test2.test3; }},
945 {error: true, action: (value) => { value.test1.test2 = null; }},
946 {error: true, action: (value) => { value.test1 = null; }},
947 {error: true, action: (value) => { value.test4 = 'string'; }},
948 {error: false, action: (value) => { delete value.test4; }},
949 ],
950 },
951
952 // Array tests
953 {
954 schema: {
955 type: 'array',
956 items: {
957 type: 'string',
958 default: 'default',
959 },
960 },
961 tests: [
962 {error: false, value: ['default'], action: (value) => { value[0] = 'string'; }},
963 {error: true, value: ['default'], action: (value) => { value[0] = null; }},
964 {error: false, value: ['default'], action: (value) => { delete value[0]; }},
965 {error: false, value: ['default'], action: (value) => { value[1] = 'string'; }},
966 {
967 error: false,
968 value: ['default'],
969 action: (value) => {
970 value[1] = 'string';
971 if (value.length !== 2) { throw new Error(`Invalid length; expected=2; actual=${value.length}`); }
972 if (typeof value.push !== 'function') { throw new Error(`Invalid push; expected=function; actual=${typeof value.push}`); }
973 },
974 },
975 ],
976 },
977
978 // Reference tests
979 {
980 schema: {
981 definitions: {
982 example: {
983 type: 'object',
984 additionalProperties: false,
985 properties: {
986 test: {
987 $ref: '#/definitions/example',
988 },
989 },
990 },
991 },
992 $ref: '#/definitions/example',
993 },
994 tests: [
995 {error: false, value: {}, action: (value) => { value.test = {}; }},
996 {error: false, value: {}, action: (value) => { value.test = {}; value.test.test = {}; }},
997 {error: false, value: {}, action: (value) => { value.test = {test: {}}; }},
998 {error: true, value: {}, action: (value) => { value.test = null; }},
999 {error: true, value: {}, action: (value) => { value.test = 'string'; }},
1000 {error: true, value: {}, action: (value) => { value.test = {}; value.test.test = 'string'; }},
1001 {error: true, value: {}, action: (value) => { value.test = {test: 'string'}; }},
1002 ],
1003 },
1004 ];
1005 /* eslint-enable @stylistic/no-multi-spaces */
1006
1007 describe.each(data)('Schema %#', ({schema, tests}) => {
1008 test.each(tests)('proxy %#', ({error, value, action}) => {
1009 if (typeof value === 'undefined') { value = getValidValueOrDefault(schema, void 0); }
1010 value = structuredClone(value);
1011 expect(schemaValidate(schema, value)).toBe(true);
1012 const valueProxy = createProxy(schema, value);
1013 if (error) {
1014 expect(() => action(valueProxy)).toThrow();
1015 } else {
1016 expect(() => action(valueProxy)).not.toThrow();
1017 }
1018 });
1019 });
1020
1021 for (const {schema, tests} of data) {
1022 for (let {error, value, action} of tests) {
1023 if (typeof value === 'undefined') { value = getValidValueOrDefault(schema, void 0); }
1024 value = structuredClone(value);
1025 expect(schemaValidate(schema, value)).toBe(true);
1026 const valueProxy = createProxy(schema, value);
1027 if (error) {
1028 expect(() => action(valueProxy)).toThrow();
1029 } else {
1030 expect(() => action(valueProxy)).not.toThrow();
1031 }
1032 }
1033 }
1034 });
1035});