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 r#""http://example.com""#,
1052 r#""https://example.com/path?query=param#fragment""#,
1053 r#""ftp://ftp.example.com/resource""#,
1054 r#""urn:isbn:0451450523""#,
1055 ],
1056 vec![
1057 r#""http:/example.com""#, r#""htp://example.com""#, r#""http://""#, r#""example.com""#, ]
1062 ),
1063 (
1064 r#"{"title": "Bar", "type": "string", "format": "email"}"#,
1065 EMAIL,
1066 vec![
1067 r#""user@example.com""#, r#""user.name+tag+sorting@example.com""#, r#""user_name@example.co.uk""#, r#""user-name@sub.example.com""#, ],
1073 vec![
1074 r#""plainaddress""#, r#""@missingusername.com""#, r#""username@.com""#, r#""username@com""#, r#""username@example,com""#, r#""username@.example.com""#, r#""username@-example.com""#, r#""username@example-.com""#, r#""username@example..com""#, r#""username@.example..com""#, ]
1086 ),
1087 (
1089 r#"{
1090 "title": "Test Schema",
1091 "type": "object",
1092 "properties": {
1093 "test_str": {"title": "Test string", "type": "string"},
1094 "test_uri": {"title": "Test URI", "type": "string", "format": "uri"},
1095 "test_email": {"title": "Test email", "type": "string", "format": "email"}
1096 },
1097 "required": ["test_str", "test_uri", "test_email"]
1098 }"#,
1099 format!(
1100 r#"\{{{0}"test_str"{0}:{0}{STRING}{0},{0}"test_uri"{0}:{0}{URI}{0},{0}"test_email"{0}:{0}{EMAIL}{0}\}}"#,
1101 WHITESPACE
1102 ).as_str(),
1103 vec![
1104 r#"{ "test_str": "cat", "test_uri": "http://example.com", "test_email": "user@example.com" }"#,
1105 ],
1106 vec![
1107 r#"{ "test_str": "cat", "test_uri": "http:/example.com", "test_email": "user@example.com" }"#,
1109 r#"{ "test_str": "cat", "test_uri": "http://example.com", "test_email": "username@.com" }"#,
1111 ]
1112 ),
1113
1114 (
1118 r#"{
1119 "title": "Foo",
1120 "type": ["string", "number", "boolean"]
1121 }"#,
1122 format!(r#"((?:"{STRING_INNER}*")|(?:{NUMBER})|(?:{BOOLEAN}))"#).as_str(),
1123 vec!["12.3", "true", r#""a""#],
1124 vec![
1125 "null",
1126 "",
1127 "12true",
1128 r#"1.3"a""#,
1129 r#"12.3true"a""#,
1130 ],
1131 ),
1132 (
1142 r##"{
1143 "$defs": {
1144 "Cat": {
1145 "properties": {
1146 "pet_type": {
1147 "const": "cat",
1148 "enum": ["cat"],
1149 "title": "Pet Type",
1150 "type": "string"
1151 },
1152 "meows": {
1153 "title": "Meows",
1154 "type": "integer"
1155 }
1156 },
1157 "required": ["pet_type", "meows"],
1158 "title": "Cat",
1159 "type": "object"
1160 },
1161 "Dog": {
1162 "properties": {
1163 "pet_type": {
1164 "const": "dog",
1165 "enum": ["dog"],
1166 "title": "Pet Type",
1167 "type": "string"
1168 },
1169 "barks": {
1170 "title": "Barks",
1171 "type": "number"
1172 }
1173 },
1174 "required": ["pet_type", "barks"],
1175 "title": "Dog",
1176 "type": "object"
1177 }
1178 },
1179 "properties": {
1180 "pet": {
1181 "discriminator": {
1182 "mapping": {
1183 "cat": "#/$defs/Cat",
1184 "dog": "#/$defs/Dog"
1185 },
1186 "propertyName": "pet_type"
1187 },
1188 "oneOf": [
1189 {"$ref": "#/$defs/Cat"},
1190 {"$ref": "#/$defs/Dog"}
1191 ],
1192 "title": "Pet"
1193 },
1194 "n": {
1195 "title": "N",
1196 "type": "integer"
1197 }
1198 },
1199 "required": ["pet", "n"],
1200 "title": "Model",
1201 "type": "object"
1202 }"##,
1203 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]*)[ ]?\}"#,
1204 vec![
1205 r#"{ "pet": { "pet_type": "cat", "meows": 5 }, "n": 10 }"#,
1206 r#"{ "pet": { "pet_type": "dog", "barks": 3.5 }, "n": 7 }"#,
1207 ],
1208 vec![
1209 r#"{ "pet": { "pet_type": "cat" }, "n": 10 }"#,
1211 r#"{ "pet": { "pet_type": "bird", "meows": 2 }, "n": 5 }"#
1213 ],
1214 ),
1215 ] {
1216 let result = regex_from_str(schema, None).expect("To regex failed");
1217 assert_eq!(result, regex, "JSON Schema {} didn't match", schema);
1218
1219 let re = Regex::new(&result).expect("Regex failed");
1220 for m in a_match {
1221 should_match(&re, m);
1222 }
1223 for not_m in not_a_match {
1224 should_not_match(&re, not_m);
1225 }
1226 }
1227 }
1228
1229 #[test]
1230 fn test_unconstrained_others() {
1231 for (schema, a_match, not_a_match) in [
1232 (
1234 r#"{
1235 "title": "Foo",
1236 "type": "object"
1237 }"#,
1238 vec![
1239 "{}",
1240 r#"{"a": 1, "b": null}"#,
1241 r#"{"a": {"z": {"g": 4}}, "b": null}"#,
1242 ],
1243 vec![
1244 "1234", r#"["a", "a"]"#, ],
1247 ),
1248 (
1250 r#"{"type": "array"}"#,
1251 vec![
1252 r#"[1, {}, false]"#,
1253 r#"[{}]"#,
1254 r#"[{"a": {"z": "q"}, "b": null}]"#,
1255 r#"[{"a": [1, 2, true], "b": null}]"#,
1256 r#"[{"a": [1, 2, true], "b": {"a": "b"}}, 1, true, [1, [2]]]"#,
1257 ],
1258 vec![
1259 r#"[{"a": [1, 2, true], "b": {"a": "b"}}, 1, true, [1, [2, [3]]]]"#,
1261 r#"[{"a": {"z": {"g": 4}}, "b": null}]"#,
1262 r#"[[[[1]]]]"#,
1263 r#"{}"#,
1265 r#"{"a": 1, "b": null}"#,
1266 r#"{"a": {"z": {"g": 4}}, "b": null}"#,
1267 "1234",
1268 r#"{"a": "a"}"#,
1269 ],
1270 ),
1271 ] {
1272 let regex = regex_from_str(schema, None).expect("To regex failed");
1273 let re = Regex::new(®ex).expect("Regex failed");
1274 for m in a_match {
1275 should_match(&re, m);
1276 }
1277 for not_m in not_a_match {
1278 should_not_match(&re, not_m);
1279 }
1280 }
1281 }
1282
1283 #[test]
1284 fn with_whitespace_patterns() {
1285 let schema = r#"{
1286 "title": "Foo",
1287 "type": "object",
1288 "properties": {"date": {"type": "string", "format": "date"}}
1289 }"#;
1290
1291 for (whitespace_pattern, expected_regex, a_match) in [
1292 (
1294 None,
1295 format!(
1296 r#"\{{({WHITESPACE}"date"{WHITESPACE}:{WHITESPACE}{DATE})?{WHITESPACE}\}}"#
1297 ),
1298 vec![
1299 r#"{"date": "2018-11-13"}"#,
1300 r#"{ "date": "2018-11-13"}"#,
1301 r#"{"date": "2018-11-13" }"#,
1302 ],
1303 ),
1304 (
1305 Some(r#"[\n ]*"#),
1306 format!(
1307 r#"\{{({ws}"date"{ws}:{ws}{DATE})?{ws}\}}"#,
1308 ws = r#"[\n ]*"#
1309 ),
1310 vec![
1311 r#"{
1312 "date": "2018-11-13"
1313 }"#,
1314 r#"{ "date":
1315
1316 "2018-11-13" }"#,
1317 ],
1318 ),
1319 (
1320 Some("SPACE"),
1321 format!(r#"\{{({ws}"date"{ws}:{ws}{DATE})?{ws}\}}"#, ws = "SPACE"),
1322 vec![r#"{SPACE"date"SPACE:SPACE"2018-11-13"SPACE}"#],
1323 ),
1324 ] {
1325 let regex = regex_from_str(schema, whitespace_pattern).expect("To regex failed");
1326 assert_eq!(regex, expected_regex);
1327
1328 let re = Regex::new(®ex).expect("Regex failed");
1329 for m in a_match {
1330 should_match(&re, m);
1331 }
1332 }
1333 }
1334
1335 #[test]
1336 fn direct_recursion_in_array_and_default_behaviour() {
1337 let schema = r##"
1338 {
1339 "type": "object",
1340 "properties": {
1341 "name": { "type": "string" },
1342 "children": {
1343 "type": "array",
1344 "items": { "$ref": "#" }
1345 }
1346 }
1347 }"##;
1348
1349 let regex = regex_from_str(schema, None);
1350 assert!(regex.is_ok(), "{:?}", regex);
1351
1352 let re = Regex::new(®ex.unwrap()).expect("Regex failed");
1355 for lvl in [
1356 r#"{ "name": "Az"}"#,
1358 r#"{ "name": "Az", "children": [] }"#,
1359 r#"{ "name": "Az", "children": [{"name": "Bo"}] }"#,
1360 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [] }] }"#,
1362 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li"}] }] }"#,
1363 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [] }] }] }"#,
1365 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho"}] }] }] }"#,
1366 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho", "children": [] }] }] }] }"#,
1368 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho", "children": [{"name": "Ro"}] }] }] }] }"#,
1369 ] {
1370 should_match(&re, lvl);
1371 }
1372
1373 for lvl in [
1374 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho", "children": [{"name": "Ro", "children": [] }] }] }] }] }"#,
1376 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho", "children": [{"name": "Ro", "children": [{"name": "Ks"}] }] }] }] }] }"#,
1377 ] {
1378 should_not_match(&re, lvl);
1379 }
1380 }
1381
1382 #[test]
1383 fn indirect_recursion_with_recursion_level_regex_match() {
1384 let json = r##"{
1385 "type": "object",
1386 "properties": {
1387 "node": { "$ref": "#/definitions/node" }
1388 },
1389 "definitions": {
1390 "node": {
1391 "type": "object",
1392 "properties": {
1393 "value": { "type": "integer" },
1394 "next": { "$ref": "#/definitions/node" }
1395 }
1396 }
1397 }
1398 }"##;
1399 let json_value: Value = serde_json::from_str(json).expect("Can't parse json");
1400 let mut parser = parsing::Parser::new(&json_value).with_max_recursion_depth(0);
1401
1402 let result = parser.to_regex(&json_value);
1403 assert!(result.is_ok(), "{:?}", result);
1404 let regex = result.unwrap();
1405 assert_eq!(
1406 r#"\{([ ]?"node"[ ]?:[ ]?\{([ ]?"value"[ ]?:[ ]?(-)?(0|[1-9][0-9]*))?[ ]?\})?[ ]?\}"#,
1407 regex,
1408 );
1409
1410 let mut parser = parser.with_max_recursion_depth(1);
1440 let result = parser.to_regex(&json_value);
1441 assert!(result.is_ok(), "{:?}", result);
1442 let regex = result.unwrap();
1443 assert_eq!(
1444 r#"\{([ ]?"node"[ ]?:[ ]?\{([ ]?"value"[ ]?:[ ]?(-)?(0|[1-9][0-9]*)|([ ]?"value"[ ]?:[ ]?(-)?(0|[1-9][0-9]*)[ ]?,)?[ ]?"next"[ ]?:[ ]?\{([ ]?"value"[ ]?:[ ]?(-)?(0|[1-9][0-9]*))?[ ]?\})?[ ]?\})?[ ]?\}"#,
1445 regex,
1446 );
1447 }
1448
1449 #[test]
1450 fn triple_recursion_doesnt_fail() {
1451 let schema = r##"
1452 {
1453 "definitions": {
1454 "typeA": {
1455 "type": "object",
1456 "properties": {
1457 "name": { "type": "string" },
1458 "child": { "$ref": "#/definitions/typeB" }
1459 },
1460 "required": ["name"]
1461 },
1462 "typeB": {
1463 "type": "object",
1464 "properties": {
1465 "value": { "type": "number" },
1466 "next": { "$ref": "#/definitions/typeC" }
1467 },
1468 "required": ["value"]
1469 },
1470 "typeC": {
1471 "type": "object",
1472 "properties": {
1473 "flag": { "type": "boolean" },
1474 "parent": { "$ref": "#/definitions/typeA" }
1475 },
1476 "required": ["flag"]
1477 }
1478 },
1479 "$ref": "#/definitions/typeA"
1480 }"##;
1481
1482 let regex = regex_from_str(schema, None);
1483 assert!(regex.is_ok(), "{:?}", regex);
1484 }
1485}