1use serde_json::Value;
103pub use types::*;
104
105mod parsing;
106pub mod types;
107
108use crate::Result;
109
110pub fn regex_from_str(
142 json: &str,
143 whitespace_pattern: Option<&str>,
144 max_recursion_depth: Option<usize>,
145) -> Result<String> {
146 let json_value: Value = serde_json::from_str(json)?;
147 regex_from_value(&json_value, whitespace_pattern, max_recursion_depth)
148}
149
150pub fn regex_from_value(
186 json: &Value,
187 whitespace_pattern: Option<&str>,
188 max_recursion_depth: Option<usize>,
189) -> Result<String> {
190 let mut parser = parsing::Parser::new(json);
191 if let Some(pattern) = whitespace_pattern {
192 parser = parser.with_whitespace_pattern(pattern)
193 }
194 if let Some(depth) = max_recursion_depth {
195 parser = parser.with_max_recursion_depth(depth)
196 }
197 parser.to_regex(json)
198}
199
200#[cfg(test)]
201mod tests {
202 use regex::Regex;
203
204 use super::*;
205
206 fn should_match(re: &Regex, value: &str) {
207 match re.find(value) {
209 Some(matched) => {
210 assert_eq!(
211 matched.as_str(),
212 value,
213 "Value should match, but does not for: {value}, re:\n{re}"
214 );
215 assert_eq!(matched.range(), 0..value.len());
216 }
217 None => unreachable!(
218 "Value should match, but does not, in unreachable for: {value}, re:\n{re}"
219 ),
220 }
221 }
222
223 fn should_not_match(re: &Regex, value: &str) {
224 if let Some(matched) = re.find(value) {
226 assert_ne!(
227 matched.as_str(),
228 value,
229 "Value should NOT match, but does for: {value}, re:\n{re}"
230 );
231 assert_ne!(matched.range(), 0..value.len());
232 }
233 }
234
235 #[test]
236 fn test_schema_matches_regex() {
237 for (schema, regex, a_match, not_a_match) in [
238 (
242 r#"{"title": "Foo", "type": "integer"}"#,
243 INTEGER,
244 vec!["0", "1", "-1"],
245 vec!["01", "1.3", "t"],
246 ),
247 (
249 r#"{
250 "title": "Foo",
251 "type": "object",
252 "properties": {"count": {"title": "Count", "type": "integer"}},
253 "required": ["count"]
254 }"#,
255 r#"\{[ ]?"count"[ ]?:[ ]?(-)?(0|[1-9][0-9]*)[ ]?\}"#,
256 vec![r#"{ "count": 100 }"#],
257 vec![r#"{ "count": "a" }"#, ""],
258 ),
259 (
261 r#"{
262 "title": "Foo",
263 "type": "object",
264 "properties": {
265 "count": {"title": "Count", "type": "integer", "minDigits": 3}
266 },
267 "required": ["count"]
268 }"#,
269 r#"\{[ ]?"count"[ ]?:[ ]?(-)?(0|[1-9][0-9]{2,})[ ]?\}"#,
270 vec![r#"{ "count": 100 }"#, r#"{ "count": 1000 }"#],
271 vec![r#"{ "count": 10 }"#],
272 ),
273 (
275 r#"{
276 "title": "Foo",
277 "type": "object",
278 "properties": {
279 "count": {"title": "Count", "type": "integer", "maxDigits": 3}
280 },
281 "required": ["count"]
282 }"#,
283 r#"\{[ ]?"count"[ ]?:[ ]?(-)?(0|[1-9][0-9]{0,2})[ ]?\}"#,
284 vec![r#"{ "count": 100 }"#, r#"{ "count": 10 }"#],
285 vec![r#"{ "count": 1000 }"#],
286 ),
287 (
289 r#"{
290 "title": "Foo",
291 "type": "object",
292 "properties": {
293 "count": {
294 "title": "Count",
295 "type": "integer",
296 "minDigits": 3,
297 "maxDigits": 5
298 }
299 },
300 "required": ["count"]
301 }"#,
302 r#"\{[ ]?"count"[ ]?:[ ]?(-)?(0|[1-9][0-9]{2,4})[ ]?\}"#,
303 vec![r#"{ "count": 100 }"#, r#"{ "count": 10000 }"#],
304 vec![r#"{ "count": 10 }"#, r#"{ "count": 100000 }"#],
305 ),
306 (
310 r#"{"title": "Foo", "type": "number"}"#,
311 NUMBER,
312 vec!["1", "0", "1.3", "-1.3", "1.3e+9"],
313 vec!["01", ".3", "1.3e9"],
314 ),
315 (
317 r#"{
318 "title": "Foo",
319 "type": "object",
320 "properties": {"count": {"title": "Count", "type": "number"}},
321 "required": ["count"]
322 }"#,
323 r#"\{[ ]?"count"[ ]?:[ ]?((-)?(0|[1-9][0-9]*))(\.[0-9]+)?([eE][+-][0-9]+)?[ ]?\}"#,
324 vec![r#"{ "count": 100 }"#, r#"{ "count": 100.5 }"#],
325 vec![""],
326 ),
327 (
329 r#"{
330 "title": "Foo",
331 "type": "object",
332 "properties": {
333 "count": {
334 "title": "Count",
335 "type": "number",
336 "minDigitsInteger": 3,
337 "maxDigitsInteger": 5
338 }
339 },
340 "required": ["count"]
341 }"#,
342 r#"\{[ ]?"count"[ ]?:[ ]?((-)?(0|[1-9][0-9]{2,4}))(\.[0-9]+)?([eE][+-][0-9]+)?[ ]?\}"#,
343 vec![r#"{ "count": 100.005 }"#, r#"{ "count": 10000.005 }"#],
344 vec![r#"{ "count": 10.005 }"#, r#"{ "count": 100000.005 }"#],
345 ),
346 (
348 r#"{
349 "title": "Foo",
350 "type": "object",
351 "properties": {
352 "count": {
353 "title": "Count",
354 "type": "number",
355 "minDigitsFraction": 3,
356 "maxDigitsFraction": 5
357 }
358 },
359 "required": ["count"]
360 }"#,
361 r#"\{[ ]?"count"[ ]?:[ ]?((-)?(0|[1-9][0-9]*))(\.[0-9]{3,5})?([eE][+-][0-9]+)?[ ]?\}"#,
362 vec![r#"{ "count": 1.005 }"#, r#"{ "count": 1.00005 }"#],
363 vec![r#"{ "count": 1.05 }"#, r#"{ "count": 1.000005 }"#],
364 ),
365 (
367 r#"{
368 "title": "Foo",
369 "type": "object",
370 "properties": {
371 "count": {
372 "title": "Count",
373 "type": "number",
374 "minDigitsExponent": 3,
375 "maxDigitsExponent": 5
376 }
377 },
378 "required": ["count"]
379 }"#,
380 r#"\{[ ]?"count"[ ]?:[ ]?((-)?(0|[1-9][0-9]*))(\.[0-9]+)?([eE][+-][0-9]{3,5})?[ ]?\}"#,
381 vec![r#"{ "count": 1.05e+001 }"#, r#"{ "count": 1.05e-00001 }"#],
382 vec![r#"{ "count": 1.05e1 }"#, r#"{ "count": 1.05e0000001 }"#],
383 ),
384 (
386 r#"{
387 "title": "Foo",
388 "type": "object",
389 "properties": {
390 "count": {
391 "title": "Count",
392 "type": "number",
393 "minDigitsInteger": 3,
394 "maxDigitsInteger": 5,
395 "minDigitsFraction": 3,
396 "maxDigitsFraction": 5,
397 "minDigitsExponent": 3,
398 "maxDigitsExponent": 5
399 }
400 },
401 "required": ["count"]
402 }"#,
403 r#"\{[ ]?"count"[ ]?:[ ]?((-)?(0|[1-9][0-9]{2,4}))(\.[0-9]{3,5})?([eE][+-][0-9]{3,5})?[ ]?\}"#,
404 vec![r#"{ "count": 100.005e+001 }"#, r#"{ "count": 10000.00005e-00001 }"#],
405 vec![r#"{ "count": 1.05e1 }"#, r#"{ "count": 100000.0000005e0000001 }"#],
406 ),
407 (
411 r#"{"title": "Foo", "type": "array", "items": {"type": "number"}}"#,
412 format!(r#"\[{WHITESPACE}(({NUMBER})(,{WHITESPACE}({NUMBER})){{0,}})?{WHITESPACE}\]"#).as_str(),
413 vec!["[1e+9,1.3]", "[]"], vec!["[1", r#"["a"]"#],
414 ),
415 (
417 r#"{
418 "title": "Foo",
419 "type": "array",
420 "items": {"type": "integer"},
421 "minItems": 3
422 }"#,
423 format!(r#"\[{WHITESPACE}(({INTEGER})(,{WHITESPACE}({INTEGER})){{2,}}){WHITESPACE}\]"#).as_str(),
424 vec!["[1,2,3]", "[1,2,3,4]"], vec!["[1]", "[1,2]", "[]"],
425 ),
426 (
428 r#"{
429 "title": "Foo",
430 "type": "array",
431 "items": {"type": "integer"},
432 "maxItems": 3
433 }"#,
434 format!(r#"\[{WHITESPACE}(({INTEGER})(,{WHITESPACE}({INTEGER})){{0,2}})?{WHITESPACE}\]"#).as_str(),
435 vec!["[1,2,3]", "[1,2]", "[]"], vec!["[1,2,3,4]"],
436 ),
437 (
439 r#"{
440 "title": "Foo",
441 "type": "array",
442 "items": {"type": "integer"},
443 "minItems": 1,
444 "maxItems": 1
445 }"#,
446 format!(r#"\[{WHITESPACE}(({INTEGER})(,{WHITESPACE}({INTEGER})){{0,0}}){WHITESPACE}\]"#).as_str(),
447 vec!["[1]"], vec!["[1, 2]", r#"["a"]"#, "[]"],
448 ),
449 (
451 r#"{
452 "title": "Foo",
453 "type": "array",
454 "items": {"type": "integer"},
455 "minItems": 0,
456 "maxItems": 0
457 }"#,
458 format!(r#"\[{WHITESPACE}\]"#).as_str(),
459 vec!["[]"], vec!["[1, 2]", "[1]", "[1,2,3,4]"],
460 ),
461 (
465 r#"{"title": "Foo", "type": "string"}"#,
466 STRING,
467 vec![
468 r#""(parenthesized_string)""#,
469 r#""malformed) parenthesis (((() string""#,
470 r#""quoted_string""#,
471 r#""double_\\escape""#,
472 r#""\\n""#,
473 r#""escaped \" quote""#,
474 r#""\n""#,
475 r#""\/""#,
476 r#""\b""#,
477 r#""\f""#,
478 r#""\r""#,
479 r#""\t""#
480 ],
481 vec![
482 "unquotedstring",
483 r#""escape_\character""#,
484 r#""unescaped " quote""#,
485 ],
486 ),
487 (
488 r#"{"title": "Foo", "type": "boolean"}"#,
489 BOOLEAN,
490 vec!["true", "false"],
491 vec!["null", "0"],
492 ),
493 (
494 r#"{"title": "Foo", "type": "null"}"#,
495 NULL,
496 vec!["null"],
497 vec!["true", "0"],
498 ),
499 (
501 r#"{"title": "Foo", "type": "string", "maxLength": 3}"#,
502 format!(r#""{STRING_INNER}{{0,3}}""#).as_str(),
503 vec![r#""ab""#], vec![r#""a"""#, r#""abcd""#],
504 ),
505 (
507 r#"{"title": "Foo", "type": "string", "minLength": 3}"#,
508 format!(r#""{STRING_INNER}{{3,}}""#).as_str(),
509 vec![r#""abcd""#], vec![r#""ab""#, r#""abc"""#],
510 ),
511 (
513 r#"{"title": "Foo", "type": "string", "minLength": 3, "maxLength": 5}"#,
514 format!(r#""{STRING_INNER}{{3,5}}""#).as_str(),
515 vec![r#""abcd""#], vec![r#""ab""#, r#""abcdef"""#],
516 ),
517 (
519 r#"{"title": "Foo", "type": "string", "pattern": "^[a-z]$"}"#,
520 r#"("[a-z]")"#,
521 vec![r#""a""#], vec![r#""1""#],
522 ),
523 (
525 r#"{"title": "Foo", "const": ".*", "type": "string"}"#,
526 r#""\.\*""#,
527 vec![r#"".*""#], vec![r#""\s*""#, r#""\.\*""#],
528 ),
529 (
531 r#"{"title": "Foo", "const": "\"", "type": "string"}"#,
532 r#""\\"""#,
533 vec![r#""\"""#], vec![r#"""""#],
534 ),
535 (
540 r#"{"title": "Foo", "const": "Marc", "type": "string"}"#,
541 r#""Marc""#,
542 vec![r#""Marc""#], vec![r#""Jonh""#, r#""Mar""#],
543 ),
544 (
546 r#"{"title": "Foo", "const": 0, "type": "integer"}"#,
547 "0",
548 vec!["0"], vec!["1", "a"],
549 ),
550 (
552 r#"{"title": "Foo", "const": 0.2, "type": "float"}"#,
553 r#"0\.2"#,
554 vec!["0.2"], vec!["032"],
555 ),
556 (
558 r#"{"title": "Foo", "const": true, "type": "boolean"}"#,
559 "true",
560 vec!["true"], vec!["false", "null"],
561 ),
562 (
564 r#"{"title": "Foo", "const": null, "type": "null"}"#,
565 "null",
566 vec!["null"], vec!["none", ""],
567 ),
568 (
572 r#"{"title": "Foo", "enum": ["Marc", "Jean"], "type": "string"}"#,
573 r#"("Marc"|"Jean")"#,
574 vec![r#""Marc""#, r#""Jean""#], vec![r#""Jonh""#],
575 ),
576 (
578 r#"{"title": "Foo", "enum": [".*", "\\s*"], "type": "string"}"#,
579 r#"("\.\*"|"\\\\s\*")"#,
580 vec![r#"".*""#, r#""\\s*""#], vec![r#""\.\*""#],
581 ),
582 (
584 r#"{"title": "Foo", "enum": [0, 1], "type": "integer"}"#,
585 r#"(0|1)"#,
586 vec!["0", "1"], vec!["a"],
587 ),
588 (
590 r#"{"title": "Foo", "enum": [[1,2],[3,4]], "type": "array"}"#,
591 format!(r#"(\[{0}1{0},{0}2{0}\]|\[{0}3{0},{0}4{0}\])"#, WHITESPACE).as_str(),
592 vec!["[1,2]", "[3,4]", "[1, 2 ]"], vec!["1", "[1,3]"],
593 ),
594 (
596 r#"{"title": "Foo", "enum": [{"a":"b","c":"d"}, {"e":"f"}], "type": "object"}"#,
597 format!(r#"(\{{{0}"a"{0}:{0}"b"{0},{0}"c"{0}:{0}"d"{0}\}}|\{{{0}"e"{0}:{0}"f"{0}\}})"#, WHITESPACE).as_str(),
598 vec![r#"{"a":"b","c":"d"}"#, r#"{"e":"f"}"#, r#"{"a" : "b", "c": "d" }"#], vec!["a", r#"{"a":"b"}"#],
599 ),
600 (
602 r#"{"title": "Foo", "enum": [6, 5.3, "potato", true, null, [1,2], {"a":"b"}]}"#,
603 format!(r#"(6|5\.3|"potato"|true|null|\[{0}1{0},{0}2{0}\]|\{{{0}"a"{0}:{0}"b"{0}\}})"#, WHITESPACE).as_str(),
604 vec!["6", "5.3", r#""potato""#, "true", "null", "[1, 2]", r#"{"a": "b" }"#], vec!["none", "53"],
605 ),
606 (
610 r#"{"title": "Foo", "type": "string", "format": "uuid"}"#,
611 UUID,
612 vec![
613 r#""123e4567-e89b-12d3-a456-426614174000""#,
614 ],
615 vec![
616 r#"123e4567-e89b-12d3-a456-426614174000"#,
617 r#""123e4567-e89b-12d3-a456-42661417400""#,
618 r#""123e4567-e89b-12d3-a456-42661417400g""#,
619 r#""123e4567-e89b-12d3-a456-42661417400-""#,
620 r#""""#,
621 ],
622 ),
623 (
625 r#"{
626 "title": "Foo",
627 "type": "object",
628 "properties": {"uuid": {"type": "string", "format": "uuid"}}
629 }"#,
630 format!(r#"\{{([ ]?"uuid"[ ]?:[ ]?{UUID})?[ ]?\}}"#).as_str(),
631 vec![
632 r#"{"uuid": "123e4567-e89b-12d3-a456-426614174000"}"#,
633 ],
634 vec![
635 r#"{"uuid":"123e4567-e89b-12d3-a456-42661417400"}"#,
636 r#"{"uuid":"123e4567-e89b-12d3-a456-42661417400g"}"#,
637 r#"{"uuid":"123e4567-e89b-12d3-a456-42661417400-"}"#,
638 r#"{"uuid":123e4567-e89b-12d3-a456-426614174000}"#, r#"{"uuid":""}"#,
640 ],
641 ),
642 (
647 r#"{"title": "Foo", "type": "string", "format": "date-time"}"#,
648 DATE_TIME,
649 vec![
650 r#""2018-11-13T20:20:39Z""#,
651 r#""2016-09-18T17:34:02.666Z""#,
652 r#""2008-05-11T15:30:00Z""#,
653 r#""2021-01-01T00:00:00""#,
654 ],
655 vec![
656 "2018-11-13T20:20:39Z",
657 r#""2022-01-10 07:19:30""#, r#""2022-12-10T10-04-29""#, r#""2023-01-01""#,
660 ],
661 ),
662 (
664 r#"{"title": "Foo", "type": "string", "format": "date"}"#,
665 DATE,
666 vec![
667 r#""2018-11-13""#,
668 r#""2016-09-18""#,
669 r#""2008-05-11""#,
670 ],
671 vec![
672 "2018-11-13",
673 r#""2015-13-01""#, r#""2022-01""#, r#""2022/12/01""#, ],
677 ),
678 (
680 r#"{"title": "Foo", "type": "string", "format": "time"}"#,
681 TIME,
682 vec![
683 r#""20:20:39Z""#,
684 r#""15:30:00Z""#,
685 ],
686 vec![
687 "20:20:39Z",
688 r#""25:30:00""#, r#""15:30""#, r#""15:30:00.000""#, r#""15-30-00""#, r#""15:30:00+01:00""#, ],
694 ),
695 (
697 r#"{
698 "title": "Foo",
699 "type": "object",
700 "properties": {"dateTime": {"type": "string", "format": "date-time"}}
701 }"#,
702 format!(r#"\{{([ ]?"dateTime"[ ]?:[ ]?{DATE_TIME})?[ ]?\}}"#).as_str(),
703 vec![
704 r#"{"dateTime": "2018-11-13T20:20:39Z"}"#,
705 r#"{"dateTime":"2016-09-18T17:34:02.666Z"}"#,
706 r#"{"dateTime":"2008-05-11T15:30:00Z"}"#,
707 r#"{"dateTime":"2021-01-01T00:00:00"}"#,
708 ],
709 vec![
710 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"}"#,
714 ],
715 ),
716 (
718 r#"{
719 "title": "Foo",
720 "type": "object",
721 "properties": {"date": {"type": "string", "format": "date"}}
722 }"#,
723 format!(r#"\{{([ ]?"date"[ ]?:[ ]?{DATE})?[ ]?\}}"#).as_str(),
724 vec![
725 r#"{"date": "2018-11-13"}"#,
726 r#"{"date":"2016-09-18"}"#,
727 r#"{"date":"2008-05-11"}"#,
728 ],
729 vec![
730 r#"{"date":"2015-13-01"}"#, r#"{"date":"2022-01"}"#, r#"{"date":"2022/12/01"}"#, r#"{"date":2018-11-13}"#, ],
735 ),
736 (
738 r#"{
739 "title": "Foo",
740 "type": "object",
741 "properties": {"time": {"type": "string", "format": "time"}}
742 }"#,
743 format!(r#"\{{([ ]?"time"[ ]?:[ ]?{TIME})?[ ]?\}}"#).as_str(),
744 vec![
745 r#"{"time": "20:20:39Z"}"#,
746 r#"{"time":"15:30:00Z"}"#,
747 ],
748 vec![
749 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}"#, ],
756 ),
757 (
762 r#"{
763 "title": "Foo",
764 "oneOf": [{"type": "string"}, {"type": "number"}, {"type": "boolean"}]
765 }"#,
766 format!(r#"((?:"{STRING_INNER}*")|(?:{NUMBER})|(?:{BOOLEAN}))"#).as_str(),
767 vec!["12.3", "true", r#""a""#],
768 vec![
769 "null",
770 "",
771 "12true",
772 r#"1.3"a""#,
773 r#"12.3true"a""#,
774 ],
775 ),
776 (
778 r#"{
779 "title": "Foo",
780 "anyOf": [{"type": "string"}, {"type": "integer"}]
781 }"#,
782 format!(r#"({STRING}|{INTEGER})"#).as_str(),
783 vec!["12", r#""a""#],
784 vec![r#"1"a""#],
785 ),
786 (
788 r#"{
789 "title": "Foo",
790 "allOf": [{"type": "string"}, {"type": "integer"}]
791 }"#,
792 format!(r#"({STRING}{INTEGER})"#).as_str(),
793 vec![r#""a"1"#],
794 vec![r#""a""#, r#""1""#],
795 ),
796 (
800 r#"{
801 "title": "TestSchema",
802 "type": "object",
803 "properties": {
804 "test_dict": {
805 "title": "Test Dict",
806 "additionalProperties": {"type": "string"},
807 "type": "object"
808 }
809 },
810 "required": ["test_dict"]
811 }"#,
812 format!(r#"\{{{WHITESPACE}"test_dict"{WHITESPACE}:{WHITESPACE}\{{{WHITESPACE}({STRING}{WHITESPACE}:{WHITESPACE}{STRING}({WHITESPACE},{WHITESPACE}{STRING}{WHITESPACE}:{WHITESPACE}{STRING}){{0,}})?{WHITESPACE}\}}{WHITESPACE}\}}"#).as_str(),
813 vec![
814 r#"{ "test_dict":{"foo":"bar","baz": "bif"}}"#,
815 r#"{ "test_dict":{"foo":"bar" }}"#,
816 r#"{ "test_dict":{}}"#,
817 ],
818 vec![
819 r#"{ "WRONG_KEY":{}}"#,
820 r#"{ "test_dict":{"wrong_type" 1}}"#,
821 ],
822 ),
823 (
825 r#"{
826 "title": "TestSchema",
827 "type": "object",
828 "properties": {
829 "test_dict": {
830 "title": "Test Dict",
831 "additionalProperties": {
832 "additionalProperties": {"type": "integer"},
833 "type": "object"
834 },
835 "type": "object"
836 }
837 },
838 "required": ["test_dict"]
839 }"#,
840 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(),
841 vec![
842 r#"{"test_dict": {"foo": {"bar": 123, "apple": 99}, "baz": {"bif": 456}}}"#,
843 r#"{"test_dict": {"anykey": {"anykey": 123}, "anykey2": {"bif": 456}}}"#,
844 r#"{"test_dict": {}}"#,
845 r#"{"test_dict": {"dict of empty dicts are ok": {} }}"#,
846 ],
847 vec![
848 r#"{"test_dict": {"anykey": {"ONLY Dict[Dict]": 123}, "No Dict[int]" 1: }}"#,
849 r#"{"test_dict": {"anykey": {"anykey": 123}, "anykey2": {"bif": "bof"}}}"#,
850 ],
851 ),
852 (
854 r#"{
855 "title": "Bar",
856 "type": "object",
857 "properties": {
858 "fuzz": {
859 "title": "Foo",
860 "type": "object",
861 "properties": {"spam": {"title": "Spam", "type": "integer"}},
862 "required": ["spam"]
863 }
864 },
865 "required": ["fuzz"]
866 }"#,
867 format!(r#"\{{[ ]?"fuzz"[ ]?:[ ]?\{{[ ]?"spam"[ ]?:[ ]?{INTEGER}[ ]?\}}[ ]?\}}"#).as_str(),
868 vec![r#"{ "fuzz": { "spam": 100 }}"#],
869 vec![r#"{ "fuzz": { "spam": 100, "notspam": 500 }}"#, r#"{ "fuzz": {}}"#, r#"{ "spam": 5}"#],
870 ),
871 (
873 r##"{
874 "title": "User",
875 "type": "object",
876 "properties": {
877 "user_id": {"title": "User Id", "type": "integer"},
878 "name": {"title": "Name", "type": "string"},
879 "a": {"$ref": "#/properties/name"}
880 },
881 "required": ["user_id", "name", "a"]
882 }"##,
883 format!(r#"\{{[ ]?"user_id"[ ]?:[ ]?{INTEGER}[ ]?,[ ]?"name"[ ]?:[ ]?{STRING}[ ]?,[ ]?"a"[ ]?:[ ]?{STRING}[ ]?\}}"#).as_str(),
884 vec![r#"{"user_id": 100, "name": "John", "a": "Marc"}"#],
885 vec![r#"{"user_id": 100, "name": "John", "a": 0}"#],
886 ),
887 (
889 r##"{
890 "title": "User",
891 "type": "object",
892 "$defs": {"name": {"title": "Name2", "type": "string"}},
893 "properties": {
894 "user_id": {"title": "User Id", "type": "integer"},
895 "name": {"title": "Name", "type": "string"},
896 "name2": {"$ref": "#/$defs/name"}
897 },
898 "required": ["user_id", "name", "name2"]
899 }"##,
900 format!(r#"\{{[ ]?"user_id"[ ]?:[ ]?{INTEGER}[ ]?,[ ]?"name"[ ]?:[ ]?{STRING}[ ]?,[ ]?"name2"[ ]?:[ ]?{STRING}[ ]?\}}"#).as_str(),
901 vec![r#"{"user_id": 100, "name": "John", "name2": "Marc"}"#],
902 vec![r#"{"user_id": 100, "name": "John", "name2": 0}"#],
903 ),
904 (
907 r##"{
908 "$id": "customer",
909 "$schema": "https://json-schema.org/draft/2020-12/schema",
910 "title": "Customer",
911 "type": "object",
912 "properties": {
913 "name": {"type": "string"},
914 "last_name": {"type": "string"},
915 "address": {"$ref": "customer#/$defs/address"}
916 },
917 "required": [
918 "name",
919 "first_name",
920 "last_name",
921 "address",
922 "shipping_address",
923 "billing_address"
924 ],
925 "$defs": {
926 "address": {
927 "title": "Address",
928 "$schema": "http://json-schema.org/draft-07/schema#",
929 "type": "object",
930 "properties": {
931 "city": {"type": "string"}
932 },
933 "required": ["street_address", "city", "state"],
934 "definitions": {
935 "state": {
936 "type": "object",
937 "title": "State",
938 "properties": {"name": {"type": "string"}},
939 "required": ["name"]
940 }
941 }
942 }
943 }
944 }"##,
945 format!(r#"\{{[ ]?"name"[ ]?:[ ]?{STRING}[ ]?,[ ]?"last_name"[ ]?:[ ]?{STRING}[ ]?,[ ]?"address"[ ]?:[ ]?\{{[ ]?"city"[ ]?:[ ]?{STRING}[ ]?\}}[ ]?\}}"#).as_str(),
946 vec![
947 r#"{"name": "John", "last_name": "Doe", "address": {"city": "Paris"}}"#,
948 ],
949 vec![
950 r#"{"name": "John", "last_name": "Doe", "address": {}}"#,
951 r#"{"name": "John", "last_name": "Doe"}"#,
952 ],
953 ),
954 (
957 r#"{
958 "properties": {
959 "name": {"type": "string"},
960 "age": {"anyOf": [{"type": "integer"}, {"type": "null"}]},
961 "weapon": {"anyOf": [{"type": "string"}, {"type": "null"}]}
962 },
963 "required": ["name"],
964 "title": "Character",
965 "type": "object"
966 }"#,
967 format!(r#"\{{[ ]?"name"[ ]?:[ ]?{STRING}([ ]?,[ ]?"age"[ ]?:[ ]?({INTEGER}|null))?([ ]?,[ ]?"weapon"[ ]?:[ ]?({STRING}|null))?[ ]?\}}"#).as_str(),
968 vec![
969 r#"{ "name" : "Player" }"#,
970 r#"{ "name" : "Player", "weapon" : "sword" }"#,
971 ],
972 vec![
973 r#"{ "age" : 10, "weapon" : "sword" }"#,
974 ],
975 ),
976 (
979 r#"{
980 "properties": {
981 "name": {"type": "string"},
982 "age": {"anyOf": [{"type": "integer"}, {"type": "null"}]},
983 "weapon": {"type": "string"},
984 "strength": {"anyOf": [{"type": "integer"}, {"type": "null"}]}
985 },
986 "required": ["name", "weapon"],
987 "title": "Character",
988 "type": "object"
989 }"#,
990 format!(r#"\{{[ ]?"name"[ ]?:[ ]?{STRING}[ ]?,([ ]?"age"[ ]?:[ ]?({INTEGER}|null)[ ]?,)?[ ]?"weapon"[ ]?:[ ]?{STRING}([ ]?,[ ]?"strength"[ ]?:[ ]?({INTEGER}|null))?[ ]?\}}"#).as_str(),
991 vec![
992 r#"{ "name" : "Player" , "weapon" : "sword" }"#,
993 r#"{ "name" : "Player", "age" : 10, "weapon" : "sword" , "strength" : 10 }"#,
994 ],
995 vec![
996 r#"{ "weapon" : "sword" }"#,
997 ],
998 ),
999 (
1002 r#"{
1003 "properties": {
1004 "name": {"anyOf": [{"type": "string"}, {"type": "null"}]},
1005 "age": {"type": "integer"},
1006 "armor": {"type": "string"},
1007 "strength": {"anyOf": [{"type": "integer"}, {"type": "null"}]},
1008 "weapon": {"title": "Weapon", "type": "string"}
1009 },
1010 "required": ["age", "armor", "weapon"],
1011 "title": "Character",
1012 "type": "object"
1013 }"#,
1014 format!(r#"\{{([ ]?"name"[ ]?:[ ]?({STRING}|null)[ ]?,)?[ ]?"age"[ ]?:[ ]?{INTEGER}[ ]?,[ ]?"armor"[ ]?:[ ]?{STRING}[ ]?,([ ]?"strength"[ ]?:[ ]?({INTEGER}|null)[ ]?,)?[ ]?"weapon"[ ]?:[ ]?{STRING}[ ]?\}}"#).as_str(),
1015 vec![
1016 r#"{ "name" : "Player", "age" : 10, "armor" : "plate", "strength" : 11, "weapon" : "sword" }"#,
1017 r#"{ "age" : 10, "armor" : "plate", "weapon" : "sword" }"#,
1018 ],
1019 vec![
1020 r#"{ "name" : "Kahlhanbeh", "armor" : "plate", "weapon" : "sword" }"#,
1021 ],
1022 ),
1023 (
1025 r#"{
1026 "properties": {
1027 "name": {"anyOf": [{"type": "string"}, {"type": "null"}]},
1028 "age": {"anyOf": [{"type": "integer"}, {"type": "null"}]},
1029 "strength": {"anyOf": [{"type": "integer"}, {"type": "null"}]}
1030 },
1031 "title": "Character",
1032 "type": "object"
1033 }"#,
1034 format!(r#"\{{([ ]?"name"[ ]?:[ ]?({STRING}|null)|([ ]?"name"[ ]?:[ ]?({STRING}|null)[ ]?,)?[ ]?"age"[ ]?:[ ]?({INTEGER}|null)|([ ]?"name"[ ]?:[ ]?({STRING}|null)[ ]?,)?([ ]?"age"[ ]?:[ ]?({INTEGER}|null)[ ]?,)?[ ]?"strength"[ ]?:[ ]?({INTEGER}|null))?[ ]?\}}"#).as_str(),
1035 vec![
1036 r#"{ "name" : "Player" }"#,
1037 r#"{ "name" : "Player", "age" : 10, "strength" : 10 }"#,
1038 r#"{ "age" : 10, "strength" : 10 }"#,
1039 "{ }",
1040 ],
1041 vec![r#"{ "foo": 0 } "#],
1042 ),
1043 (
1048 r#"{
1049 "title": "Foo",
1050 "prefixItems": [{"type": "string"}, {"type": "integer"}]
1051 }"#,
1052 format!(r#"\[{WHITESPACE}{STRING}{WHITESPACE},{WHITESPACE}{INTEGER}{WHITESPACE}\]"#).as_str(),
1053 vec![r#"["a", 1]"#],
1054 vec![r#"["a", 1, 1]"#, "[]"],
1055 ),
1056 (
1059 "{}",
1060 "((true|false))|(null)|(((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?)|((-)?(0|[1-9][0-9]*))|(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")|(\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(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]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(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]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(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]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(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]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])){0,})?[ ]?\\])(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(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]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(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]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(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]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(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]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])){0,})?[ ]?\\])){0,})?[ ]?\\])|(\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(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]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(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]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(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]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(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]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])){0,})?[ ]?\\])([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(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]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(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]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(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]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(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]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])){0,})?[ ]?\\])){0,})?[ ]?\\})",
1061 vec![
1062 r#""aaabbuecuh""#,
1063 "5.554",
1064 "true",
1065 "null",
1066 "5999",
1067 r#"["a", "b"]"#,
1068 r#"{"key": {"k2": "value"}}"#,
1069 ],
1070 vec!["this isnt valid json"],
1071 ),
1072 (
1076 r#"{"title": "Foo", "type": "string", "format": "uri"}"#,
1077 URI,
1078 vec![
1079 r#""http://example.com""#,
1080 r#""https://example.com/path?query=param#fragment""#,
1081 r#""ftp://ftp.example.com/resource""#,
1082 r#""urn:isbn:0451450523""#,
1083 ],
1084 vec![
1085 r#""http:/example.com""#, r#""htp://example.com""#, r#""http://""#, r#""example.com""#, ]
1090 ),
1091 (
1092 r#"{"title": "Bar", "type": "string", "format": "email"}"#,
1093 EMAIL,
1094 vec![
1095 r#""user@example.com""#, r#""user.name+tag+sorting@example.com""#, r#""user_name@example.co.uk""#, r#""user-name@sub.example.com""#, ],
1101 vec![
1102 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""#, ]
1114 ),
1115 (
1117 r#"{
1118 "title": "Test Schema",
1119 "type": "object",
1120 "properties": {
1121 "test_str": {"title": "Test string", "type": "string"},
1122 "test_uri": {"title": "Test URI", "type": "string", "format": "uri"},
1123 "test_email": {"title": "Test email", "type": "string", "format": "email"}
1124 },
1125 "required": ["test_str", "test_uri", "test_email"]
1126 }"#,
1127 format!(
1128 r#"\{{{0}"test_str"{0}:{0}{STRING}{0},{0}"test_uri"{0}:{0}{URI}{0},{0}"test_email"{0}:{0}{EMAIL}{0}\}}"#,
1129 WHITESPACE
1130 ).as_str(),
1131 vec![
1132 r#"{ "test_str": "cat", "test_uri": "http://example.com", "test_email": "user@example.com" }"#,
1133 ],
1134 vec![
1135 r#"{ "test_str": "cat", "test_uri": "http:/example.com", "test_email": "user@example.com" }"#,
1137 r#"{ "test_str": "cat", "test_uri": "http://example.com", "test_email": "username@.com" }"#,
1139 ]
1140 ),
1141
1142 (
1146 r#"{
1147 "title": "Foo",
1148 "type": ["string", "number", "boolean"]
1149 }"#,
1150 format!(r#"((?:"{STRING_INNER}*")|(?:{NUMBER})|(?:{BOOLEAN}))"#).as_str(),
1151 vec!["12.3", "true", r#""a""#],
1152 vec![
1153 "null",
1154 "",
1155 "12true",
1156 r#"1.3"a""#,
1157 r#"12.3true"a""#,
1158 ],
1159 ),
1160 (
1170 r##"{
1171 "$defs": {
1172 "Cat": {
1173 "properties": {
1174 "pet_type": {
1175 "const": "cat",
1176 "enum": ["cat"],
1177 "title": "Pet Type",
1178 "type": "string"
1179 },
1180 "meows": {
1181 "title": "Meows",
1182 "type": "integer"
1183 }
1184 },
1185 "required": ["pet_type", "meows"],
1186 "title": "Cat",
1187 "type": "object"
1188 },
1189 "Dog": {
1190 "properties": {
1191 "pet_type": {
1192 "const": "dog",
1193 "enum": ["dog"],
1194 "title": "Pet Type",
1195 "type": "string"
1196 },
1197 "barks": {
1198 "title": "Barks",
1199 "type": "number"
1200 }
1201 },
1202 "required": ["pet_type", "barks"],
1203 "title": "Dog",
1204 "type": "object"
1205 }
1206 },
1207 "properties": {
1208 "pet": {
1209 "discriminator": {
1210 "mapping": {
1211 "cat": "#/$defs/Cat",
1212 "dog": "#/$defs/Dog"
1213 },
1214 "propertyName": "pet_type"
1215 },
1216 "oneOf": [
1217 {"$ref": "#/$defs/Cat"},
1218 {"$ref": "#/$defs/Dog"}
1219 ],
1220 "title": "Pet"
1221 },
1222 "n": {
1223 "title": "N",
1224 "type": "integer"
1225 }
1226 },
1227 "required": ["pet", "n"],
1228 "title": "Model",
1229 "type": "object"
1230 }"##,
1231 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]*)[ ]?\}"#,
1232 vec![
1233 r#"{ "pet": { "pet_type": "cat", "meows": 5 }, "n": 10 }"#,
1234 r#"{ "pet": { "pet_type": "dog", "barks": 3.5 }, "n": 7 }"#,
1235 ],
1236 vec![
1237 r#"{ "pet": { "pet_type": "cat" }, "n": 10 }"#,
1239 r#"{ "pet": { "pet_type": "bird", "meows": 2 }, "n": 5 }"#
1241 ],
1242 ),
1243 ] {
1244 let result = regex_from_str(schema, None, None).expect("To regex failed");
1245 assert_eq!(result, regex, "JSON Schema {} didn't match", schema);
1246
1247 let re = Regex::new(&result).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 test_unconstrained_others() {
1259 for (schema, a_match, not_a_match) in [
1260 (
1262 r#"{
1263 "title": "Foo",
1264 "type": "object"
1265 }"#,
1266 vec![
1267 "{}",
1268 r#"{"a": 1, "b": null}"#,
1269 r#"{"a": {"z": {"g": 4}}, "b": null}"#,
1270 ],
1271 vec![
1272 "1234", r#"["a", "a"]"#, ],
1275 ),
1276 (
1278 r#"{"type": "array"}"#,
1279 vec![
1280 r#"[1, {}, false]"#,
1281 r#"[{}]"#,
1282 r#"[{"a": {"z": "q"}, "b": null}]"#,
1283 r#"[{"a": [1, 2, true], "b": null}]"#,
1284 r#"[{"a": [1, 2, true], "b": {"a": "b"}}, 1, true, [1, [2]]]"#,
1285 ],
1286 vec![
1287 r#"[{"a": [1, 2, true], "b": {"a": "b"}}, 1, true, [1, [2, [3]]]]"#,
1289 r#"[{"a": {"z": {"g": 4}}, "b": null}]"#,
1290 r#"[[[[1]]]]"#,
1291 r#"{}"#,
1293 r#"{"a": 1, "b": null}"#,
1294 r#"{"a": {"z": {"g": 4}}, "b": null}"#,
1295 "1234",
1296 r#"{"a": "a"}"#,
1297 ],
1298 ),
1299 ] {
1300 let regex = regex_from_str(schema, None, None).expect("To regex failed");
1301 let re = Regex::new(®ex).expect("Regex failed");
1302 for m in a_match {
1303 should_match(&re, m);
1304 }
1305 for not_m in not_a_match {
1306 should_not_match(&re, not_m);
1307 }
1308 }
1309 }
1310
1311 #[test]
1312 fn with_whitespace_patterns() {
1313 let schema = r#"{
1314 "title": "Foo",
1315 "type": "object",
1316 "properties": {"date": {"type": "string", "format": "date"}}
1317 }"#;
1318
1319 for (whitespace_pattern, expected_regex, a_match) in [
1320 (
1322 None,
1323 format!(
1324 r#"\{{({WHITESPACE}"date"{WHITESPACE}:{WHITESPACE}{DATE})?{WHITESPACE}\}}"#
1325 ),
1326 vec![
1327 r#"{"date": "2018-11-13"}"#,
1328 r#"{ "date": "2018-11-13"}"#,
1329 r#"{"date": "2018-11-13" }"#,
1330 ],
1331 ),
1332 (
1333 Some(r#"[\n ]*"#),
1334 format!(
1335 r#"\{{({ws}"date"{ws}:{ws}{DATE})?{ws}\}}"#,
1336 ws = r#"[\n ]*"#
1337 ),
1338 vec![
1339 r#"{
1340 "date": "2018-11-13"
1341 }"#,
1342 r#"{ "date":
1343
1344 "2018-11-13" }"#,
1345 ],
1346 ),
1347 (
1348 Some("SPACE"),
1349 format!(r#"\{{({ws}"date"{ws}:{ws}{DATE})?{ws}\}}"#, ws = "SPACE"),
1350 vec![r#"{SPACE"date"SPACE:SPACE"2018-11-13"SPACE}"#],
1351 ),
1352 ] {
1353 let regex = regex_from_str(schema, whitespace_pattern, None).expect("To regex failed");
1354 assert_eq!(regex, expected_regex);
1355
1356 let re = Regex::new(®ex).expect("Regex failed");
1357 for m in a_match {
1358 should_match(&re, m);
1359 }
1360 }
1361 }
1362
1363 #[test]
1364 fn direct_recursion_in_array_and_default_behaviour() {
1365 let schema = r##"
1366 {
1367 "type": "object",
1368 "properties": {
1369 "name": { "type": "string" },
1370 "children": {
1371 "type": "array",
1372 "items": { "$ref": "#" }
1373 }
1374 }
1375 }"##;
1376
1377 let regex = regex_from_str(schema, None, None);
1378 assert!(regex.is_ok(), "{:?}", regex);
1379
1380 let re = Regex::new(®ex.unwrap()).expect("Regex failed");
1383 for lvl in [
1384 r#"{ "name": "Az"}"#,
1386 r#"{ "name": "Az", "children": [] }"#,
1387 r#"{ "name": "Az", "children": [{"name": "Bo"}] }"#,
1388 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [] }] }"#,
1390 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li"}] }] }"#,
1391 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [] }] }] }"#,
1393 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho"}] }] }] }"#,
1394 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho", "children": [] }] }] }] }"#,
1396 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho", "children": [{"name": "Ro"}] }] }] }] }"#,
1397 ] {
1398 should_match(&re, lvl);
1399 }
1400
1401 for lvl in [
1402 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho", "children": [{"name": "Ro", "children": [] }] }] }] }] }"#,
1404 r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho", "children": [{"name": "Ro", "children": [{"name": "Ks"}] }] }] }] }] }"#,
1405 ] {
1406 should_not_match(&re, lvl);
1407 }
1408 }
1409
1410 #[test]
1411 fn indirect_recursion_with_recursion_level_regex_match() {
1412 let json = r##"{
1413 "type": "object",
1414 "properties": {
1415 "node": { "$ref": "#/definitions/node" }
1416 },
1417 "definitions": {
1418 "node": {
1419 "type": "object",
1420 "properties": {
1421 "value": { "type": "integer" },
1422 "next": { "$ref": "#/definitions/node" }
1423 }
1424 }
1425 }
1426 }"##;
1427 let json_value: Value = serde_json::from_str(json).expect("Can't parse json");
1428 let mut parser = parsing::Parser::new(&json_value).with_max_recursion_depth(0);
1429
1430 let result = parser.to_regex(&json_value);
1431 assert!(result.is_ok(), "{:?}", result);
1432 let regex = result.unwrap();
1433 assert_eq!(
1434 r#"\{([ ]?"node"[ ]?:[ ]?\{([ ]?"value"[ ]?:[ ]?(-)?(0|[1-9][0-9]*))?[ ]?\})?[ ]?\}"#,
1435 regex,
1436 );
1437
1438 let mut parser = parser.with_max_recursion_depth(1);
1468 let result = parser.to_regex(&json_value);
1469 assert!(result.is_ok(), "{:?}", result);
1470 let regex = result.unwrap();
1471 assert_eq!(
1472 r#"\{([ ]?"node"[ ]?:[ ]?\{([ ]?"value"[ ]?:[ ]?(-)?(0|[1-9][0-9]*)|([ ]?"value"[ ]?:[ ]?(-)?(0|[1-9][0-9]*)[ ]?,)?[ ]?"next"[ ]?:[ ]?\{([ ]?"value"[ ]?:[ ]?(-)?(0|[1-9][0-9]*))?[ ]?\})?[ ]?\})?[ ]?\}"#,
1473 regex,
1474 );
1475 }
1476
1477 #[test]
1478 fn triple_recursion_doesnt_fail() {
1479 let schema = r##"
1480 {
1481 "definitions": {
1482 "typeA": {
1483 "type": "object",
1484 "properties": {
1485 "name": { "type": "string" },
1486 "child": { "$ref": "#/definitions/typeB" }
1487 },
1488 "required": ["name"]
1489 },
1490 "typeB": {
1491 "type": "object",
1492 "properties": {
1493 "value": { "type": "number" },
1494 "next": { "$ref": "#/definitions/typeC" }
1495 },
1496 "required": ["value"]
1497 },
1498 "typeC": {
1499 "type": "object",
1500 "properties": {
1501 "flag": { "type": "boolean" },
1502 "parent": { "$ref": "#/definitions/typeA" }
1503 },
1504 "required": ["flag"]
1505 }
1506 },
1507 "$ref": "#/definitions/typeA"
1508 }"##;
1509
1510 let regex = regex_from_str(schema, None, None);
1511 assert!(regex.is_ok(), "{:?}", regex);
1512 }
1513
1514 #[test]
1515 fn quadruple_recursion_doesnt_include_leaf() {
1516 let schema = r##"
1517 {
1518 "definitions": {
1519 "typeA": {
1520 "type": "object",
1521 "properties": {
1522 "data": { "type": "string" },
1523 "typeB": { "$ref": "#/definitions/typeB" }
1524 },
1525 "required": ["data", "typeB"]
1526 },
1527 "typeB": {
1528 "type": "object",
1529 "properties": {
1530 "data": { "type": "string" },
1531 "typeC": { "$ref": "#/definitions/typeC" }
1532 },
1533 "required": ["data", "typeC"]
1534 },
1535 "typeC": {
1536 "type": "object",
1537 "properties": {
1538 "data": { "type": "string" },
1539 "typeD": { "$ref": "#/definitions/typeD" }
1540 },
1541 "required": ["data", "typeD"]
1542 },
1543 "typeD": {
1544 "type": "object",
1545 "properties": {
1546 "data": { "type": "string" },
1547 "typeE": { "$ref": "#/definitions/typeE" }
1548 },
1549 "required": ["data", "typeE"]
1550 },
1551 "typeE": {
1552 "type": "object",
1553 "properties": {
1554 "data": { "type": "string" },
1555 "typeA": { "$ref": "#/definitions/typeA" }
1556 },
1557 "required": ["data", "typeA"]
1558 }
1559 },
1560 "$ref": "#/definitions/typeA"
1561 }"##;
1562
1563 let regex = regex_from_str(schema, None, None);
1564 assert!(regex.is_ok(), "{:?}", regex);
1565 let regex_str = regex.unwrap();
1566 assert!(
1567 !regex_str.contains("typeE"),
1568 "Regex should not contain typeE when max_recursion_depth is not specified"
1569 );
1570 }
1571
1572 #[test]
1573 fn quadruple_recursion_includes_leaf_when_max_recursion_depth_is_specified() {
1574 let schema = r##"
1575 {
1576 "definitions": {
1577 "typeA": {
1578 "type": "object",
1579 "properties": {
1580 "data": { "type": "string" },
1581 "typeB": { "$ref": "#/definitions/typeB" }
1582 },
1583 "required": ["data", "typeB"]
1584 },
1585 "typeB": {
1586 "type": "object",
1587 "properties": {
1588 "data": { "type": "string" },
1589 "typeC": { "$ref": "#/definitions/typeC" }
1590 },
1591 "required": ["data", "typeC"]
1592 },
1593 "typeC": {
1594 "type": "object",
1595 "properties": {
1596 "data": { "type": "string" },
1597 "typeD": { "$ref": "#/definitions/typeD" }
1598 },
1599 "required": ["data", "typeD"]
1600 },
1601 "typeD": {
1602 "type": "object",
1603 "properties": {
1604 "data": { "type": "string" },
1605 "typeE": { "$ref": "#/definitions/typeE" }
1606 },
1607 "required": ["data", "typeE"]
1608 },
1609 "typeE": {
1610 "type": "object",
1611 "properties": {
1612 "data": { "type": "string" },
1613 "typeA": { "$ref": "#/definitions/typeA" }
1614 },
1615 "required": ["data", "typeA"]
1616 }
1617 },
1618 "$ref": "#/definitions/typeA"
1619 }"##;
1620
1621 let regex = regex_from_str(schema, None, Some(4));
1622 assert!(regex.is_ok(), "{:?}", regex);
1623 let regex_str = regex.unwrap();
1624 assert!(
1625 regex_str.contains("typeE"),
1626 "Regex should contain typeE when max_recursion_depth is specified"
1627 );
1628 }
1629}