1use serde_json::Value;
103pub use types::*;
104
105mod parsing;
106pub mod types;
107
108use crate::Result;
109
110pub fn regex_from_str(json: &str, whitespace_pattern: Option<&str>) -> Result<String> {
142 let json_value: Value = serde_json::from_str(json)?;
143 regex_from_value(&json_value, whitespace_pattern)
144}
145
146pub fn regex_from_value(json: &Value, whitespace_pattern: Option<&str>) -> Result<String> {
182 let mut parser = parsing::Parser::new(json);
183 if let Some(pattern) = whitespace_pattern {
184 parser = parser.with_whitespace_pattern(pattern)
185 }
186 parser.to_regex(json)
187}
188
189#[cfg(test)]
190mod tests {
191 use regex::Regex;
192
193 use super::*;
194
195 fn should_match(re: &Regex, value: &str) {
196 match re.find(value) {
198 Some(matched) => {
199 assert_eq!(
200 matched.as_str(),
201 value,
202 "Value should match, but does not for: {value}, re:\n{re}"
203 );
204 assert_eq!(matched.range(), 0..value.len());
205 }
206 None => unreachable!(
207 "Value should match, but does not, in unreachable for: {value}, re:\n{re}"
208 ),
209 }
210 }
211
212 fn should_not_match(re: &Regex, value: &str) {
213 if let Some(matched) = re.find(value) {
215 assert_ne!(
216 matched.as_str(),
217 value,
218 "Value should NOT match, but does for: {value}, re:\n{re}"
219 );
220 assert_ne!(matched.range(), 0..value.len());
221 }
222 }
223
224 #[test]
225 fn test_schema_matches_regex() {
226 for (schema, regex, a_match, not_a_match) in [
227 (
231 r#"{"title": "Foo", "type": "integer"}"#,
232 INTEGER,
233 vec!["0", "1", "-1"],
234 vec!["01", "1.3", "t"],
235 ),
236 (
238 r#"{
239 "title": "Foo",
240 "type": "object",
241 "properties": {"count": {"title": "Count", "type": "integer"}},
242 "required": ["count"]
243 }"#,
244 r#"\{[ ]?"count"[ ]?:[ ]?(-)?(0|[1-9][0-9]*)[ ]?\}"#,
245 vec![r#"{ "count": 100 }"#],
246 vec![r#"{ "count": "a" }"#, ""],
247 ),
248 (
250 r#"{
251 "title": "Foo",
252 "type": "object",
253 "properties": {
254 "count": {"title": "Count", "type": "integer", "minDigits": 3}
255 },
256 "required": ["count"]
257 }"#,
258 r#"\{[ ]?"count"[ ]?:[ ]?(-)?(0|[1-9][0-9]{2,})[ ]?\}"#,
259 vec![r#"{ "count": 100 }"#, r#"{ "count": 1000 }"#],
260 vec![r#"{ "count": 10 }"#],
261 ),
262 (
264 r#"{
265 "title": "Foo",
266 "type": "object",
267 "properties": {
268 "count": {"title": "Count", "type": "integer", "maxDigits": 3}
269 },
270 "required": ["count"]
271 }"#,
272 r#"\{[ ]?"count"[ ]?:[ ]?(-)?(0|[1-9][0-9]{0,2})[ ]?\}"#,
273 vec![r#"{ "count": 100 }"#, r#"{ "count": 10 }"#],
274 vec![r#"{ "count": 1000 }"#],
275 ),
276 (
278 r#"{
279 "title": "Foo",
280 "type": "object",
281 "properties": {
282 "count": {
283 "title": "Count",
284 "type": "integer",
285 "minDigits": 3,
286 "maxDigits": 5
287 }
288 },
289 "required": ["count"]
290 }"#,
291 r#"\{[ ]?"count"[ ]?:[ ]?(-)?(0|[1-9][0-9]{2,4})[ ]?\}"#,
292 vec![r#"{ "count": 100 }"#, r#"{ "count": 10000 }"#],
293 vec![r#"{ "count": 10 }"#, r#"{ "count": 100000 }"#],
294 ),
295 (
299 r#"{"title": "Foo", "type": "number"}"#,
300 NUMBER,
301 vec!["1", "0", "1.3", "-1.3", "1.3e+9"],
302 vec!["01", ".3", "1.3e9"],
303 ),
304 (
306 r#"{
307 "title": "Foo",
308 "type": "object",
309 "properties": {"count": {"title": "Count", "type": "number"}},
310 "required": ["count"]
311 }"#,
312 r#"\{[ ]?"count"[ ]?:[ ]?((-)?(0|[1-9][0-9]*))(\.[0-9]+)?([eE][+-][0-9]+)?[ ]?\}"#,
313 vec![r#"{ "count": 100 }"#, r#"{ "count": 100.5 }"#],
314 vec![""],
315 ),
316 (
318 r#"{
319 "title": "Foo",
320 "type": "object",
321 "properties": {
322 "count": {
323 "title": "Count",
324 "type": "number",
325 "minDigitsInteger": 3,
326 "maxDigitsInteger": 5
327 }
328 },
329 "required": ["count"]
330 }"#,
331 r#"\{[ ]?"count"[ ]?:[ ]?((-)?(0|[1-9][0-9]{2,4}))(\.[0-9]+)?([eE][+-][0-9]+)?[ ]?\}"#,
332 vec![r#"{ "count": 100.005 }"#, r#"{ "count": 10000.005 }"#],
333 vec![r#"{ "count": 10.005 }"#, r#"{ "count": 100000.005 }"#],
334 ),
335 (
337 r#"{
338 "title": "Foo",
339 "type": "object",
340 "properties": {
341 "count": {
342 "title": "Count",
343 "type": "number",
344 "minDigitsFraction": 3,
345 "maxDigitsFraction": 5
346 }
347 },
348 "required": ["count"]
349 }"#,
350 r#"\{[ ]?"count"[ ]?:[ ]?((-)?(0|[1-9][0-9]*))(\.[0-9]{3,5})?([eE][+-][0-9]+)?[ ]?\}"#,
351 vec![r#"{ "count": 1.005 }"#, r#"{ "count": 1.00005 }"#],
352 vec![r#"{ "count": 1.05 }"#, r#"{ "count": 1.000005 }"#],
353 ),
354 (
356 r#"{
357 "title": "Foo",
358 "type": "object",
359 "properties": {
360 "count": {
361 "title": "Count",
362 "type": "number",
363 "minDigitsExponent": 3,
364 "maxDigitsExponent": 5
365 }
366 },
367 "required": ["count"]
368 }"#,
369 r#"\{[ ]?"count"[ ]?:[ ]?((-)?(0|[1-9][0-9]*))(\.[0-9]+)?([eE][+-][0-9]{3,5})?[ ]?\}"#,
370 vec![r#"{ "count": 1.05e+001 }"#, r#"{ "count": 1.05e-00001 }"#],
371 vec![r#"{ "count": 1.05e1 }"#, r#"{ "count": 1.05e0000001 }"#],
372 ),
373 (
375 r#"{
376 "title": "Foo",
377 "type": "object",
378 "properties": {
379 "count": {
380 "title": "Count",
381 "type": "number",
382 "minDigitsInteger": 3,
383 "maxDigitsInteger": 5,
384 "minDigitsFraction": 3,
385 "maxDigitsFraction": 5,
386 "minDigitsExponent": 3,
387 "maxDigitsExponent": 5
388 }
389 },
390 "required": ["count"]
391 }"#,
392 r#"\{[ ]?"count"[ ]?:[ ]?((-)?(0|[1-9][0-9]{2,4}))(\.[0-9]{3,5})?([eE][+-][0-9]{3,5})?[ ]?\}"#,
393 vec![r#"{ "count": 100.005e+001 }"#, r#"{ "count": 10000.00005e-00001 }"#],
394 vec![r#"{ "count": 1.05e1 }"#, r#"{ "count": 100000.0000005e0000001 }"#],
395 ),
396 (
400 r#"{"title": "Foo", "type": "array", "items": {"type": "number"}}"#,
401 format!(r#"\[{WHITESPACE}(({NUMBER})(,{WHITESPACE}({NUMBER})){{0,}})?{WHITESPACE}\]"#).as_str(),
402 vec!["[1e+9,1.3]", "[]"], vec!["[1", r#"["a"]"#],
403 ),
404 (
406 r#"{
407 "title": "Foo",
408 "type": "array",
409 "items": {"type": "integer"},
410 "minItems": 3
411 }"#,
412 format!(r#"\[{WHITESPACE}(({INTEGER})(,{WHITESPACE}({INTEGER})){{2,}}){WHITESPACE}\]"#).as_str(),
413 vec!["[1,2,3]", "[1,2,3,4]"], vec!["[1]", "[1,2]", "[]"],
414 ),
415 (
417 r#"{
418 "title": "Foo",
419 "type": "array",
420 "items": {"type": "integer"},
421 "maxItems": 3
422 }"#,
423 format!(r#"\[{WHITESPACE}(({INTEGER})(,{WHITESPACE}({INTEGER})){{0,2}})?{WHITESPACE}\]"#).as_str(),
424 vec!["[1,2,3]", "[1,2]", "[]"], vec!["[1,2,3,4]"],
425 ),
426 (
428 r#"{
429 "title": "Foo",
430 "type": "array",
431 "items": {"type": "integer"},
432 "minItems": 1,
433 "maxItems": 1
434 }"#,
435 format!(r#"\[{WHITESPACE}(({INTEGER})(,{WHITESPACE}({INTEGER})){{0,0}}){WHITESPACE}\]"#).as_str(),
436 vec!["[1]"], vec!["[1, 2]", r#"["a"]"#, "[]"],
437 ),
438 (
440 r#"{
441 "title": "Foo",
442 "type": "array",
443 "items": {"type": "integer"},
444 "minItems": 0,
445 "maxItems": 0
446 }"#,
447 format!(r#"\[{WHITESPACE}\]"#).as_str(),
448 vec!["[]"], vec!["[1, 2]", "[1]", "[1,2,3,4]"],
449 ),
450 (
454 r#"{"title": "Foo", "type": "string"}"#,
455 STRING,
456 vec![
457 r#""(parenthesized_string)""#,
458 r#""malformed) parenthesis (((() string""#,
459 r#""quoted_string""#,
460 r#""double_\\escape""#,
461 r#""\\n""#,
462 r#""escaped \" quote""#,
463 ],
464 vec![
465 "unquotedstring",
466 r#""escape_\character""#,
467 r#""\n""#,
468 r#""unescaped " quote""#,
469 ],
470 ),
471 (
472 r#"{"title": "Foo", "type": "boolean"}"#,
473 BOOLEAN,
474 vec!["true", "false"],
475 vec!["null", "0"],
476 ),
477 (
478 r#"{"title": "Foo", "type": "null"}"#,
479 NULL,
480 vec!["null"],
481 vec!["true", "0"],
482 ),
483 (
485 r#"{"title": "Foo", "type": "string", "maxLength": 3}"#,
486 format!(r#""{STRING_INNER}{{0,3}}""#).as_str(),
487 vec![r#""ab""#], vec![r#""a"""#, r#""abcd""#],
488 ),
489 (
491 r#"{"title": "Foo", "type": "string", "minLength": 3}"#,
492 format!(r#""{STRING_INNER}{{3,}}""#).as_str(),
493 vec![r#""abcd""#], vec![r#""ab""#, r#""abc"""#],
494 ),
495 (
497 r#"{"title": "Foo", "type": "string", "minLength": 3, "maxLength": 5}"#,
498 format!(r#""{STRING_INNER}{{3,5}}""#).as_str(),
499 vec![r#""abcd""#], vec![r#""ab""#, r#""abcdef"""#],
500 ),
501 (
503 r#"{"title": "Foo", "type": "string", "pattern": "^[a-z]$"}"#,
504 r#"("[a-z]")"#,
505 vec![r#""a""#], vec![r#""1""#],
506 ),
507 (
509 r#"{"title": "Foo", "const": ".*", "type": "string"}"#,
510 r#""\.\*""#,
511 vec![r#"".*""#], vec![r#""\s*""#, r#""\.\*""#],
512 ),
513 (
515 r#"{"title": "Foo", "const": "\"", "type": "string"}"#,
516 r#""\\"""#,
517 vec![r#""\"""#], vec![r#"""""#],
518 ),
519 (
524 r#"{"title": "Foo", "const": "Marc", "type": "string"}"#,
525 r#""Marc""#,
526 vec![r#""Marc""#], vec![r#""Jonh""#, r#""Mar""#],
527 ),
528 (
530 r#"{"title": "Foo", "const": 0, "type": "integer"}"#,
531 "0",
532 vec!["0"], vec!["1", "a"],
533 ),
534 (
536 r#"{"title": "Foo", "const": 0.2, "type": "float"}"#,
537 r#"0\.2"#,
538 vec!["0.2"], vec!["032"],
539 ),
540 (
542 r#"{"title": "Foo", "const": true, "type": "boolean"}"#,
543 "true",
544 vec!["true"], vec!["false", "null"],
545 ),
546 (
548 r#"{"title": "Foo", "const": null, "type": "null"}"#,
549 "null",
550 vec!["null"], vec!["none", ""],
551 ),
552 (
556 r#"{"title": "Foo", "enum": ["Marc", "Jean"], "type": "string"}"#,
557 r#"("Marc"|"Jean")"#,
558 vec![r#""Marc""#, r#""Jean""#], vec![r#""Jonh""#],
559 ),
560 (
562 r#"{"title": "Foo", "enum": [".*", "\\s*"], "type": "string"}"#,
563 r#"("\.\*"|"\\\\s\*")"#,
564 vec![r#"".*""#, r#""\\s*""#], vec![r#""\.\*""#],
565 ),
566 (
568 r#"{"title": "Foo", "enum": [0, 1], "type": "integer"}"#,
569 r#"(0|1)"#,
570 vec!["0", "1"], vec!["a"],
571 ),
572 (
574 r#"{"title": "Foo", "enum": [6, 5.3, "potato", true, null]}"#,
575 r#"(6|5\.3|"potato"|true|null)"#,
576 vec!["6", "5.3", r#""potato""#, "true", "null"], vec!["none", "53"],
577 ),
578 (
582 r#"{"title": "Foo", "type": "string", "format": "uuid"}"#,
583 UUID,
584 vec![
585 r#""123e4567-e89b-12d3-a456-426614174000""#,
586 ],
587 vec![
588 r#"123e4567-e89b-12d3-a456-426614174000"#,
589 r#""123e4567-e89b-12d3-a456-42661417400""#,
590 r#""123e4567-e89b-12d3-a456-42661417400g""#,
591 r#""123e4567-e89b-12d3-a456-42661417400-""#,
592 r#""""#,
593 ],
594 ),
595 (
597 r#"{
598 "title": "Foo",
599 "type": "object",
600 "properties": {"uuid": {"type": "string", "format": "uuid"}}
601 }"#,
602 format!(r#"\{{([ ]?"uuid"[ ]?:[ ]?{UUID})?[ ]?\}}"#).as_str(),
603 vec![
604 r#"{"uuid": "123e4567-e89b-12d3-a456-426614174000"}"#,
605 ],
606 vec![
607 r#"{"uuid":"123e4567-e89b-12d3-a456-42661417400"}"#,
608 r#"{"uuid":"123e4567-e89b-12d3-a456-42661417400g"}"#,
609 r#"{"uuid":"123e4567-e89b-12d3-a456-42661417400-"}"#,
610 r#"{"uuid":123e4567-e89b-12d3-a456-426614174000}"#, r#"{"uuid":""}"#,
612 ],
613 ),
614 (
619 r#"{"title": "Foo", "type": "string", "format": "date-time"}"#,
620 DATE_TIME,
621 vec![
622 r#""2018-11-13T20:20:39Z""#,
623 r#""2016-09-18T17:34:02.666Z""#,
624 r#""2008-05-11T15:30:00Z""#,
625 r#""2021-01-01T00:00:00""#,
626 ],
627 vec![
628 "2018-11-13T20:20:39Z",
629 r#""2022-01-10 07:19:30""#, r#""2022-12-10T10-04-29""#, r#""2023-01-01""#,
632 ],
633 ),
634 (
636 r#"{"title": "Foo", "type": "string", "format": "date"}"#,
637 DATE,
638 vec![
639 r#""2018-11-13""#,
640 r#""2016-09-18""#,
641 r#""2008-05-11""#,
642 ],
643 vec![
644 "2018-11-13",
645 r#""2015-13-01""#, r#""2022-01""#, r#""2022/12/01""#, ],
649 ),
650 (
652 r#"{"title": "Foo", "type": "string", "format": "time"}"#,
653 TIME,
654 vec![
655 r#""20:20:39Z""#,
656 r#""15:30:00Z""#,
657 ],
658 vec![
659 "20:20:39Z",
660 r#""25:30:00""#, r#""15:30""#, r#""15:30:00.000""#, r#""15-30-00""#, r#""15:30:00+01:00""#, ],
666 ),
667 (
669 r#"{
670 "title": "Foo",
671 "type": "object",
672 "properties": {"dateTime": {"type": "string", "format": "date-time"}}
673 }"#,
674 format!(r#"\{{([ ]?"dateTime"[ ]?:[ ]?{DATE_TIME})?[ ]?\}}"#).as_str(),
675 vec![
676 r#"{"dateTime": "2018-11-13T20:20:39Z"}"#,
677 r#"{"dateTime":"2016-09-18T17:34:02.666Z"}"#,
678 r#"{"dateTime":"2008-05-11T15:30:00Z"}"#,
679 r#"{"dateTime":"2021-01-01T00:00:00"}"#,
680 ],
681 vec![
682 r#"{"dateTime":"2022-01-10 07:19:30"}"#, r#"{"dateTime":"2022-12-10T10-04-29"}"#, r#"{"dateTime":2018-11-13T20:20:39Z}"#, r#"{"dateTime":"2023-01-01"}"#,
686 ],
687 ),
688 (
690 r#"{
691 "title": "Foo",
692 "type": "object",
693 "properties": {"date": {"type": "string", "format": "date"}}
694 }"#,
695 format!(r#"\{{([ ]?"date"[ ]?:[ ]?{DATE})?[ ]?\}}"#).as_str(),
696 vec![
697 r#"{"date": "2018-11-13"}"#,
698 r#"{"date":"2016-09-18"}"#,
699 r#"{"date":"2008-05-11"}"#,
700 ],
701 vec![
702 r#"{"date":"2015-13-01"}"#, r#"{"date":"2022-01"}"#, r#"{"date":"2022/12/01"}"#, r#"{"date":2018-11-13}"#, ],
707 ),
708 (
710 r#"{
711 "title": "Foo",
712 "type": "object",
713 "properties": {"time": {"type": "string", "format": "time"}}
714 }"#,
715 format!(r#"\{{([ ]?"time"[ ]?:[ ]?{TIME})?[ ]?\}}"#).as_str(),
716 vec![
717 r#"{"time": "20:20:39Z"}"#,
718 r#"{"time":"15:30:00Z"}"#,
719 ],
720 vec![
721 r#"{"time":"25:30:00"}"#, r#"{"time":"15:30"}"#, r#"{"time":"15:30:00.000"}"#, r#"{"time":"15-30-00"}"#, r#"{"time":"15:30:00+01:00"}"#, r#"{"time":20:20:39Z}"#, ],
728 ),
729 (
734 r#"{
735 "title": "Foo",
736 "oneOf": [{"type": "string"}, {"type": "number"}, {"type": "boolean"}]
737 }"#,
738 format!(r#"((?:"{STRING_INNER}*")|(?:{NUMBER})|(?:{BOOLEAN}))"#).as_str(),
739 vec!["12.3", "true", r#""a""#],
740 vec![
741 "null",
742 "",
743 "12true",
744 r#"1.3"a""#,
745 r#"12.3true"a""#,
746 ],
747 ),
748 (
750 r#"{
751 "title": "Foo",
752 "anyOf": [{"type": "string"}, {"type": "integer"}]
753 }"#,
754 format!(r#"({STRING}|{INTEGER})"#).as_str(),
755 vec!["12", r#""a""#],
756 vec![r#"1"a""#],
757 ),
758 (
760 r#"{
761 "title": "Foo",
762 "allOf": [{"type": "string"}, {"type": "integer"}]
763 }"#,
764 format!(r#"({STRING}{INTEGER})"#).as_str(),
765 vec![r#""a"1"#],
766 vec![r#""a""#, r#""1""#],
767 ),
768 (
772 r#"{
773 "title": "TestSchema",
774 "type": "object",
775 "properties": {
776 "test_dict": {
777 "title": "Test Dict",
778 "additionalProperties": {"type": "string"},
779 "type": "object"
780 }
781 },
782 "required": ["test_dict"]
783 }"#,
784 format!(r#"\{{{WHITESPACE}"test_dict"{WHITESPACE}:{WHITESPACE}\{{{WHITESPACE}({STRING}{WHITESPACE}:{WHITESPACE}{STRING}({WHITESPACE},{WHITESPACE}{STRING}{WHITESPACE}:{WHITESPACE}{STRING}){{0,}})?{WHITESPACE}\}}{WHITESPACE}\}}"#).as_str(),
785 vec![
786 r#"{ "test_dict":{"foo":"bar","baz": "bif"}}"#,
787 r#"{ "test_dict":{"foo":"bar" }}"#,
788 r#"{ "test_dict":{}}"#,
789 ],
790 vec![
791 r#"{ "WRONG_KEY":{}}"#,
792 r#"{ "test_dict":{"wrong_type" 1}}"#,
793 ],
794 ),
795 (
797 r#"{
798 "title": "TestSchema",
799 "type": "object",
800 "properties": {
801 "test_dict": {
802 "title": "Test Dict",
803 "additionalProperties": {
804 "additionalProperties": {"type": "integer"},
805 "type": "object"
806 },
807 "type": "object"
808 }
809 },
810 "required": ["test_dict"]
811 }"#,
812 format!(r#"\{{{WHITESPACE}"test_dict"{WHITESPACE}:{WHITESPACE}\{{{WHITESPACE}({STRING}{WHITESPACE}:{WHITESPACE}\{{{WHITESPACE}({STRING}{WHITESPACE}:{WHITESPACE}{INTEGER}({WHITESPACE},{WHITESPACE}{STRING}{WHITESPACE}:{WHITESPACE}{INTEGER}){{0,}})?{WHITESPACE}\}}({WHITESPACE},{WHITESPACE}{STRING}{WHITESPACE}:{WHITESPACE}\{{{WHITESPACE}({STRING}{WHITESPACE}:{WHITESPACE}{INTEGER}({WHITESPACE},{WHITESPACE}{STRING}{WHITESPACE}:{WHITESPACE}{INTEGER}){{0,}})?{WHITESPACE}\}}){{0,}})?{WHITESPACE}\}}{WHITESPACE}\}}"#).as_str(),
813 vec![
814 r#"{"test_dict": {"foo": {"bar": 123, "apple": 99}, "baz": {"bif": 456}}}"#,
815 r#"{"test_dict": {"anykey": {"anykey": 123}, "anykey2": {"bif": 456}}}"#,
816 r#"{"test_dict": {}}"#,
817 r#"{"test_dict": {"dict of empty dicts are ok": {} }}"#,
818 ],
819 vec![
820 r#"{"test_dict": {"anykey": {"ONLY Dict[Dict]": 123}, "No Dict[int]" 1: }}"#,
821 r#"{"test_dict": {"anykey": {"anykey": 123}, "anykey2": {"bif": "bof"}}}"#,
822 ],
823 ),
824 (
826 r#"{
827 "title": "Bar",
828 "type": "object",
829 "properties": {
830 "fuzz": {
831 "title": "Foo",
832 "type": "object",
833 "properties": {"spam": {"title": "Spam", "type": "integer"}},
834 "required": ["spam"]
835 }
836 },
837 "required": ["fuzz"]
838 }"#,
839 format!(r#"\{{[ ]?"fuzz"[ ]?:[ ]?\{{[ ]?"spam"[ ]?:[ ]?{INTEGER}[ ]?\}}[ ]?\}}"#).as_str(),
840 vec![r#"{ "fuzz": { "spam": 100 }}"#],
841 vec![r#"{ "fuzz": { "spam": 100, "notspam": 500 }}"#, r#"{ "fuzz": {}}"#, r#"{ "spam": 5}"#],
842 ),
843 (
845 r##"{
846 "title": "User",
847 "type": "object",
848 "properties": {
849 "user_id": {"title": "User Id", "type": "integer"},
850 "name": {"title": "Name", "type": "string"},
851 "a": {"$ref": "#/properties/name"}
852 },
853 "required": ["user_id", "name", "a"]
854 }"##,
855 format!(r#"\{{[ ]?"user_id"[ ]?:[ ]?{INTEGER}[ ]?,[ ]?"name"[ ]?:[ ]?{STRING}[ ]?,[ ]?"a"[ ]?:[ ]?{STRING}[ ]?\}}"#).as_str(),
856 vec![r#"{"user_id": 100, "name": "John", "a": "Marc"}"#],
857 vec![r#"{"user_id": 100, "name": "John", "a": 0}"#],
858 ),
859 (
861 r##"{
862 "title": "User",
863 "type": "object",
864 "$defs": {"name": {"title": "Name2", "type": "string"}},
865 "properties": {
866 "user_id": {"title": "User Id", "type": "integer"},
867 "name": {"title": "Name", "type": "string"},
868 "name2": {"$ref": "#/$defs/name"}
869 },
870 "required": ["user_id", "name", "name2"]
871 }"##,
872 format!(r#"\{{[ ]?"user_id"[ ]?:[ ]?{INTEGER}[ ]?,[ ]?"name"[ ]?:[ ]?{STRING}[ ]?,[ ]?"name2"[ ]?:[ ]?{STRING}[ ]?\}}"#).as_str(),
873 vec![r#"{"user_id": 100, "name": "John", "name2": "Marc"}"#],
874 vec![r#"{"user_id": 100, "name": "John", "name2": 0}"#],
875 ),
876 (
879 r##"{
880 "$id": "customer",
881 "$schema": "https://json-schema.org/draft/2020-12/schema",
882 "title": "Customer",
883 "type": "object",
884 "properties": {
885 "name": {"type": "string"},
886 "last_name": {"type": "string"},
887 "address": {"$ref": "customer#/$defs/address"}
888 },
889 "required": [
890 "name",
891 "first_name",
892 "last_name",
893 "address",
894 "shipping_address",
895 "billing_address"
896 ],
897 "$defs": {
898 "address": {
899 "title": "Address",
900 "$schema": "http://json-schema.org/draft-07/schema#",
901 "type": "object",
902 "properties": {
903 "city": {"type": "string"}
904 },
905 "required": ["street_address", "city", "state"],
906 "definitions": {
907 "state": {
908 "type": "object",
909 "title": "State",
910 "properties": {"name": {"type": "string"}},
911 "required": ["name"]
912 }
913 }
914 }
915 }
916 }"##,
917 format!(r#"\{{[ ]?"name"[ ]?:[ ]?{STRING}[ ]?,[ ]?"last_name"[ ]?:[ ]?{STRING}[ ]?,[ ]?"address"[ ]?:[ ]?\{{[ ]?"city"[ ]?:[ ]?{STRING}[ ]?\}}[ ]?\}}"#).as_str(),
918 vec![
919 r#"{"name": "John", "last_name": "Doe", "address": {"city": "Paris"}}"#,
920 ],
921 vec![
922 r#"{"name": "John", "last_name": "Doe", "address": {}}"#,
923 r#"{"name": "John", "last_name": "Doe"}"#,
924 ],
925 ),
926 (
929 r#"{
930 "properties": {
931 "name": {"type": "string"},
932 "age": {"anyOf": [{"type": "integer"}, {"type": "null"}]},
933 "weapon": {"anyOf": [{"type": "string"}, {"type": "null"}]}
934 },
935 "required": ["name"],
936 "title": "Character",
937 "type": "object"
938 }"#,
939 format!(r#"\{{[ ]?"name"[ ]?:[ ]?{STRING}([ ]?,[ ]?"age"[ ]?:[ ]?({INTEGER}|null))?([ ]?,[ ]?"weapon"[ ]?:[ ]?({STRING}|null))?[ ]?\}}"#).as_str(),
940 vec![
941 r#"{ "name" : "Player" }"#,
942 r#"{ "name" : "Player", "weapon" : "sword" }"#,
943 ],
944 vec![
945 r#"{ "age" : 10, "weapon" : "sword" }"#,
946 ],
947 ),
948 (
951 r#"{
952 "properties": {
953 "name": {"type": "string"},
954 "age": {"anyOf": [{"type": "integer"}, {"type": "null"}]},
955 "weapon": {"type": "string"},
956 "strength": {"anyOf": [{"type": "integer"}, {"type": "null"}]}
957 },
958 "required": ["name", "weapon"],
959 "title": "Character",
960 "type": "object"
961 }"#,
962 format!(r#"\{{[ ]?"name"[ ]?:[ ]?{STRING}[ ]?,([ ]?"age"[ ]?:[ ]?({INTEGER}|null)[ ]?,)?[ ]?"weapon"[ ]?:[ ]?{STRING}([ ]?,[ ]?"strength"[ ]?:[ ]?({INTEGER}|null))?[ ]?\}}"#).as_str(),
963 vec![
964 r#"{ "name" : "Player" , "weapon" : "sword" }"#,
965 r#"{ "name" : "Player", "age" : 10, "weapon" : "sword" , "strength" : 10 }"#,
966 ],
967 vec![
968 r#"{ "weapon" : "sword" }"#,
969 ],
970 ),
971 (
974 r#"{
975 "properties": {
976 "name": {"anyOf": [{"type": "string"}, {"type": "null"}]},
977 "age": {"type": "integer"},
978 "armor": {"type": "string"},
979 "strength": {"anyOf": [{"type": "integer"}, {"type": "null"}]},
980 "weapon": {"title": "Weapon", "type": "string"}
981 },
982 "required": ["age", "armor", "weapon"],
983 "title": "Character",
984 "type": "object"
985 }"#,
986 format!(r#"\{{([ ]?"name"[ ]?:[ ]?({STRING}|null)[ ]?,)?[ ]?"age"[ ]?:[ ]?{INTEGER}[ ]?,[ ]?"armor"[ ]?:[ ]?{STRING}[ ]?,([ ]?"strength"[ ]?:[ ]?({INTEGER}|null)[ ]?,)?[ ]?"weapon"[ ]?:[ ]?{STRING}[ ]?\}}"#).as_str(),
987 vec![
988 r#"{ "name" : "Player", "age" : 10, "armor" : "plate", "strength" : 11, "weapon" : "sword" }"#,
989 r#"{ "age" : 10, "armor" : "plate", "weapon" : "sword" }"#,
990 ],
991 vec![
992 r#"{ "name" : "Kahlhanbeh", "armor" : "plate", "weapon" : "sword" }"#,
993 ],
994 ),
995 (
997 r#"{
998 "properties": {
999 "name": {"anyOf": [{"type": "string"}, {"type": "null"}]},
1000 "age": {"anyOf": [{"type": "integer"}, {"type": "null"}]},
1001 "strength": {"anyOf": [{"type": "integer"}, {"type": "null"}]}
1002 },
1003 "title": "Character",
1004 "type": "object"
1005 }"#,
1006 format!(r#"\{{([ ]?"name"[ ]?:[ ]?({STRING}|null)|([ ]?"name"[ ]?:[ ]?({STRING}|null)[ ]?,)?[ ]?"age"[ ]?:[ ]?({INTEGER}|null)|([ ]?"name"[ ]?:[ ]?({STRING}|null)[ ]?,)?([ ]?"age"[ ]?:[ ]?({INTEGER}|null)[ ]?,)?[ ]?"strength"[ ]?:[ ]?({INTEGER}|null))?[ ]?\}}"#).as_str(),
1007 vec![
1008 r#"{ "name" : "Player" }"#,
1009 r#"{ "name" : "Player", "age" : 10, "strength" : 10 }"#,
1010 r#"{ "age" : 10, "strength" : 10 }"#,
1011 "{ }",
1012 ],
1013 vec![r#"{ "foo": 0 } "#],
1014 ),
1015 (
1020 r#"{
1021 "title": "Foo",
1022 "prefixItems": [{"type": "string"}, {"type": "integer"}]
1023 }"#,
1024 format!(r#"\[{WHITESPACE}{STRING}{WHITESPACE},{WHITESPACE}{INTEGER}{WHITESPACE}\]"#).as_str(),
1025 vec![r#"["a", 1]"#],
1026 vec![r#"["a", 1, 1]"#, "[]"],
1027 ),
1028 (
1031 "{}",
1032 "((true|false))|(null)|(((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?)|((-)?(0|[1-9][0-9]*))|(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")|(\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")){0,})?[ ]?\\])([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")){0,})?[ ]?\\])){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")){0,})?[ ]?\\])(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")){0,})?[ ]?\\])){0,})?[ ]?\\])(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")){0,})?[ ]?\\])([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")){0,})?[ ]?\\])){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")){0,})?[ ]?\\])(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")){0,})?[ ]?\\])){0,})?[ ]?\\])){0,})?[ ]?\\])|(\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")){0,})?[ ]?\\])([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")){0,})?[ ]?\\])){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")){0,})?[ ]?\\])(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")){0,})?[ ]?\\])){0,})?[ ]?\\])([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")){0,})?[ ]?\\])([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")){0,})?[ ]?\\])){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")){0,})?[ ]?\\])(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\])*\")){0,})?[ ]?\\])){0,})?[ ]?\\])){0,})?[ ]?\\})",
1033 vec![
1034 r#""aaabbuecuh""#,
1035 "5.554",
1036 "true",
1037 "null",
1038 "5999",
1039 r#"["a", "b"]"#,
1040 r#"{"key": {"k2": "value"}}"#,
1041 ],
1042 vec!["this isnt valid json"],
1043 ),
1044 (
1048 r#"{"title": "Foo", "type": "string", "format": "uri"}"#,
1049 URI,
1050 vec![
1051 "http://example.com",
1052 "https://example.com/path?query=param#fragment",
1053 "ftp://ftp.example.com/resource",
1054 "urn:isbn:0451450523",
1055 ],
1056 vec![
1057 "http:/example.com", "htp://example.com", "http://", "example.com", ]
1062 ),
1063 (
1064 r#"{"title": "Bar", "type": "string", "format": "email"}"#,
1065 EMAIL,
1066 vec![
1067 "user@example.com", "user.name+tag+sorting@example.com", "user_name@example.co.uk", "user-name@sub.example.com", ],
1073 vec![
1074 "plainaddress", "@missingusername.com", "username@.com", "username@com", "username@example,com", "username@.example.com", "username@-example.com", "username@example-.com", "username@example..com", "username@.example..com", ]
1086 ),
1087
1088 (
1092 r#"{
1093 "title": "Foo",
1094 "type": ["string", "number", "boolean"]
1095 }"#,
1096 format!(r#"((?:"{STRING_INNER}*")|(?:{NUMBER})|(?:{BOOLEAN}))"#).as_str(),
1097 vec!["12.3", "true", r#""a""#],
1098 vec![
1099 "null",
1100 "",
1101 "12true",
1102 r#"1.3"a""#,
1103 r#"12.3true"a""#,
1104 ],
1105 ),
1106 (
1116 r##"{
1117 "$defs": {
1118 "Cat": {
1119 "properties": {
1120 "pet_type": {
1121 "const": "cat",
1122 "enum": ["cat"],
1123 "title": "Pet Type",
1124 "type": "string"
1125 },
1126 "meows": {
1127 "title": "Meows",
1128 "type": "integer"
1129 }
1130 },
1131 "required": ["pet_type", "meows"],
1132 "title": "Cat",
1133 "type": "object"
1134 },
1135 "Dog": {
1136 "properties": {
1137 "pet_type": {
1138 "const": "dog",
1139 "enum": ["dog"],
1140 "title": "Pet Type",
1141 "type": "string"
1142 },
1143 "barks": {
1144 "title": "Barks",
1145 "type": "number"
1146 }
1147 },
1148 "required": ["pet_type", "barks"],
1149 "title": "Dog",
1150 "type": "object"
1151 }
1152 },
1153 "properties": {
1154 "pet": {
1155 "discriminator": {
1156 "mapping": {
1157 "cat": "#/$defs/Cat",
1158 "dog": "#/$defs/Dog"
1159 },
1160 "propertyName": "pet_type"
1161 },
1162 "oneOf": [
1163 {"$ref": "#/$defs/Cat"},
1164 {"$ref": "#/$defs/Dog"}
1165 ],
1166 "title": "Pet"
1167 },
1168 "n": {
1169 "title": "N",
1170 "type": "integer"
1171 }
1172 },
1173 "required": ["pet", "n"],
1174 "title": "Model",
1175 "type": "object"
1176 }"##,
1177 r#"\{[ ]?"pet"[ ]?:[ ]?((?:\{[ ]?"pet_type"[ ]?:[ ]?("cat")[ ]?,[ ]?"meows"[ ]?:[ ]?(-)?(0|[1-9][0-9]*)[ ]?\})|(?:\{[ ]?"pet_type"[ ]?:[ ]?("dog")[ ]?,[ ]?"barks"[ ]?:[ ]?((-)?(0|[1-9][0-9]*))(\.[0-9]+)?([eE][+-][0-9]+)?[ ]?\}))[ ]?,[ ]?"n"[ ]?:[ ]?(-)?(0|[1-9][0-9]*)[ ]?\}"#,
1178 vec![
1179 r#"{ "pet": { "pet_type": "cat", "meows": 5 }, "n": 10 }"#,
1180 r#"{ "pet": { "pet_type": "dog", "barks": 3.5 }, "n": 7 }"#,
1181 ],
1182 vec![
1183 r#"{ "pet": { "pet_type": "cat" }, "n": 10 }"#,
1185 r#"{ "pet": { "pet_type": "bird", "meows": 2 }, "n": 5 }"#
1187 ],
1188 ),
1189 ] {
1190 let result = regex_from_str(schema, None).expect("To regex failed");
1191 assert_eq!(result, regex, "JSON Schema {} didn't match", schema);
1192
1193 let re = Regex::new(&result).expect("Regex failed");
1194 for m in a_match {
1195 should_match(&re, m);
1196 }
1197 for not_m in not_a_match {
1198 should_not_match(&re, not_m);
1199 }
1200 }
1201 }
1202
1203 #[test]
1204 fn test_unconstrained_others() {
1205 for (schema, a_match, not_a_match) in [
1206 (
1208 r#"{
1209 "title": "Foo",
1210 "type": "object"
1211 }"#,
1212 vec![
1213 "{}",
1214 r#"{"a": 1, "b": null}"#,
1215 r#"{"a": {"z": {"g": 4}}, "b": null}"#,
1216 ],
1217 vec![
1218 "1234", r#"["a", "a"]"#, ],
1221 ),
1222 (
1224 r#"{"type": "array"}"#,
1225 vec![
1226 r#"[1, {}, false]"#,
1227 r#"[{}]"#,
1228 r#"[{"a": {"z": "q"}, "b": null}]"#,
1229 r#"[{"a": [1, 2, true], "b": null}]"#,
1230 r#"[{"a": [1, 2, true], "b": {"a": "b"}}, 1, true, [1, [2]]]"#,
1231 ],
1232 vec![
1233 r#"[{"a": [1, 2, true], "b": {"a": "b"}}, 1, true, [1, [2, [3]]]]"#,
1235 r#"[{"a": {"z": {"g": 4}}, "b": null}]"#,
1236 r#"[[[[1]]]]"#,
1237 r#"{}"#,
1239 r#"{"a": 1, "b": null}"#,
1240 r#"{"a": {"z": {"g": 4}}, "b": null}"#,
1241 "1234",
1242 r#"{"a": "a"}"#,
1243 ],
1244 ),
1245 ] {
1246 let regex = regex_from_str(schema, None).expect("To regex failed");
1247 let re = Regex::new(®ex).expect("Regex failed");
1248 for m in a_match {
1249 should_match(&re, m);
1250 }
1251 for not_m in not_a_match {
1252 should_not_match(&re, not_m);
1253 }
1254 }
1255 }
1256
1257 #[test]
1258 fn with_whitespace_patterns() {
1259 let schema = r#"{
1260 "title": "Foo",
1261 "type": "object",
1262 "properties": {"date": {"type": "string", "format": "date"}}
1263 }"#;
1264
1265 for (whitespace_pattern, expected_regex, a_match) in [
1266 (
1268 None,
1269 format!(
1270 r#"\{{({WHITESPACE}"date"{WHITESPACE}:{WHITESPACE}{DATE})?{WHITESPACE}\}}"#
1271 ),
1272 vec![
1273 r#"{"date": "2018-11-13"}"#,
1274 r#"{ "date": "2018-11-13"}"#,
1275 r#"{"date": "2018-11-13" }"#,
1276 ],
1277 ),
1278 (
1279 Some(r#"[\n ]*"#),
1280 format!(
1281 r#"\{{({ws}"date"{ws}:{ws}{DATE})?{ws}\}}"#,
1282 ws = r#"[\n ]*"#
1283 ),
1284 vec![
1285 r#"{
1286 "date": "2018-11-13"
1287 }"#,
1288 r#"{ "date":
1289
1290 "2018-11-13" }"#,
1291 ],
1292 ),
1293 (
1294 Some("SPACE"),
1295 format!(r#"\{{({ws}"date"{ws}:{ws}{DATE})?{ws}\}}"#, ws = "SPACE"),
1296 vec![r#"{SPACE"date"SPACE:SPACE"2018-11-13"SPACE}"#],
1297 ),
1298 ] {
1299 let regex = regex_from_str(schema, whitespace_pattern).expect("To regex failed");
1300 assert_eq!(regex, expected_regex);
1301
1302 let re = Regex::new(®ex).expect("Regex failed");
1303 for m in a_match {
1304 should_match(&re, m);
1305 }
1306 }
1307 }
1308
1309 #[test]
1310 fn direct_recursion_in_array_and_default_behaviour() {
1311 let schema = r##"
1312 {
1313 "type": "object",
1314 "properties": {
1315 "name": { "type": "string" },
1316 "children": {
1317 "type": "array",
1318 "items": { "$ref": "#" }
1319 }
1320 }
1321 }"##;
1322
1323 let regex = regex_from_str(schema, None);
1324 assert!(regex.is_ok(), "{:?}", regex);
1325
1326 let re = Regex::new(®ex.unwrap()).expect("Regex failed");
1329 for lvl in [
1330 r#"{ "name": "Az"}"#,
1332 r#"{ "name": "Az", "children": [] }"#,
1333 r#"{ "name": "Az", "children": [{"name": "Bo"}] }"#,
1334 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [] }] }"#,
1336 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li"}] }] }"#,
1337 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [] }] }] }"#,
1339 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho"}] }] }] }"#,
1340 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho", "children": [] }] }] }] }"#,
1342 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho", "children": [{"name": "Ro"}] }] }] }] }"#,
1343 ] {
1344 should_match(&re, lvl);
1345 }
1346
1347 for lvl in [
1348 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho", "children": [{"name": "Ro", "children": [] }] }] }] }] }"#,
1350 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho", "children": [{"name": "Ro", "children": [{"name": "Ks"}] }] }] }] }] }"#,
1351 ] {
1352 should_not_match(&re, lvl);
1353 }
1354 }
1355
1356 #[test]
1357 fn indirect_recursion_with_recursion_level_regex_match() {
1358 let json = r##"{
1359 "type": "object",
1360 "properties": {
1361 "node": { "$ref": "#/definitions/node" }
1362 },
1363 "definitions": {
1364 "node": {
1365 "type": "object",
1366 "properties": {
1367 "value": { "type": "integer" },
1368 "next": { "$ref": "#/definitions/node" }
1369 }
1370 }
1371 }
1372 }"##;
1373 let json_value: Value = serde_json::from_str(json).expect("Can't parse json");
1374 let mut parser = parsing::Parser::new(&json_value).with_max_recursion_depth(0);
1375
1376 let result = parser.to_regex(&json_value);
1377 assert!(result.is_ok(), "{:?}", result);
1378 let regex = result.unwrap();
1379 assert_eq!(
1380 r#"\{([ ]?"node"[ ]?:[ ]?\{([ ]?"value"[ ]?:[ ]?(-)?(0|[1-9][0-9]*))?[ ]?\})?[ ]?\}"#,
1381 regex,
1382 );
1383
1384 let mut parser = parser.with_max_recursion_depth(1);
1414 let result = parser.to_regex(&json_value);
1415 assert!(result.is_ok(), "{:?}", result);
1416 let regex = result.unwrap();
1417 assert_eq!(
1418 r#"\{([ ]?"node"[ ]?:[ ]?\{([ ]?"value"[ ]?:[ ]?(-)?(0|[1-9][0-9]*)|([ ]?"value"[ ]?:[ ]?(-)?(0|[1-9][0-9]*)[ ]?,)?[ ]?"next"[ ]?:[ ]?\{([ ]?"value"[ ]?:[ ]?(-)?(0|[1-9][0-9]*))?[ ]?\})?[ ]?\})?[ ]?\}"#,
1419 regex,
1420 );
1421 }
1422
1423 #[test]
1424 fn triple_recursion_doesnt_fail() {
1425 let schema = r##"
1426 {
1427 "definitions": {
1428 "typeA": {
1429 "type": "object",
1430 "properties": {
1431 "name": { "type": "string" },
1432 "child": { "$ref": "#/definitions/typeB" }
1433 },
1434 "required": ["name"]
1435 },
1436 "typeB": {
1437 "type": "object",
1438 "properties": {
1439 "value": { "type": "number" },
1440 "next": { "$ref": "#/definitions/typeC" }
1441 },
1442 "required": ["value"]
1443 },
1444 "typeC": {
1445 "type": "object",
1446 "properties": {
1447 "flag": { "type": "boolean" },
1448 "parent": { "$ref": "#/definitions/typeA" }
1449 },
1450 "required": ["flag"]
1451 }
1452 },
1453 "$ref": "#/definitions/typeA"
1454 }"##;
1455
1456 let regex = regex_from_str(schema, None);
1457 assert!(regex.is_ok(), "{:?}", regex);
1458 }
1459}