Felipe97/llama-cpp-compiled
01.1k
1#ifdef NDEBUG2#undef NDEBUG3#endif4 5#include "json-schema-to-grammar.h"6 7#include "../src/llama-grammar.h"8 9#include "json.h"10 11#include <cassert>12#include <regex>13 14static std::string trim(const std::string & source) {15 std::string s(source);16 s.erase(0,s.find_first_not_of(" \n\r\t"));17 s.erase(s.find_last_not_of(" \n\r\t")+1);18 return std::regex_replace(s, std::regex("(^|\n)[ \t]+"), "$1");19}20 21enum TestCaseStatus {22 SUCCESS,23 FAILURE24};25 26struct TestCase {27 TestCaseStatus expected_status;28 std::string name;29 std::string schema;30 std::string expected_grammar;31 32 void _print_failure_header() const {33 fprintf(stderr, "#\n# Test '%s' failed.\n#\n%s\n", name.c_str(), schema.c_str());34 }35 void verify(const std::string & actual_grammar) const {36 if (trim(actual_grammar) != trim(expected_grammar)) {37 _print_failure_header();38 fprintf(stderr, "# EXPECTED:\n%s\n# ACTUAL:\n%s\n", expected_grammar.c_str(), actual_grammar.c_str());39 assert(false);40 }41 }42 void verify_expectation_parseable() const {43 try {44 llama_grammar_parser state;45 state.parse(expected_grammar.c_str());46 if (state.symbol_ids.find("root") == state.symbol_ids.end()) {47 throw std::runtime_error("Grammar failed to parse:\n" + expected_grammar);48 }49 } catch (const std::runtime_error & ex) {50 _print_failure_header();51 fprintf(stderr, "# GRAMMAR ERROR: %s\n", ex.what());52 assert(false);53 }54 }55 void verify_status(TestCaseStatus status) const {56 if (status != expected_status) {57 _print_failure_header();58 fprintf(stderr, "# EXPECTED STATUS: %s\n", expected_status == SUCCESS ? "SUCCESS" : "FAILURE");59 fprintf(stderr, "# ACTUAL STATUS: %s\n", status == SUCCESS ? "SUCCESS" : "FAILURE");60 assert(false);61 }62 }63};64 65static void test_all(const std::string & title, std::function<void(const TestCase &)> runner) {66 fprintf(stderr, "#\n# %s\n#\n", title.c_str());67 auto test = [&](const TestCase & tc) {68 fprintf(stderr, "- %s%s\n", tc.name.c_str(), tc.expected_status == FAILURE ? " (failure expected)" : "");69 runner(tc);70 };71 72 test({73 SUCCESS,74 "min 0",75 R"""({76 "type": "integer",77 "minimum": 078 })""",79 R"""(80 root ::= ([0] | [1-9] [0-9]{0,15})81 space ::= | " " | "\n"{1,2} [ \t]{0,20}82 )"""83 });84 85 test({86 SUCCESS,87 "min 1",88 R"""({89 "type": "integer",90 "minimum": 191 })""",92 R"""(93 root ::= ([1-9] [0-9]{0,15})94 space ::= | " " | "\n"{1,2} [ \t]{0,20}95 )"""96 });97 98 test({99 SUCCESS,100 "min 3",101 R"""({102 "type": "integer",103 "minimum": 3104 })""",105 R"""(106 root ::= ([1-2] [0-9]{1,15} | [3-9] [0-9]{0,15})107 space ::= | " " | "\n"{1,2} [ \t]{0,20}108 )"""109 });110 111 test({112 SUCCESS,113 "min 9",114 R"""({115 "type": "integer",116 "minimum": 9117 })""",118 R"""(119 root ::= ([1-8] [0-9]{1,15} | [9] [0-9]{0,15})120 space ::= | " " | "\n"{1,2} [ \t]{0,20}121 )"""122 });123 124 test({125 SUCCESS,126 "min 10",127 R"""({128 "type": "integer",129 "minimum": 10130 })""",131 R"""(132 root ::= ([1] ([0-9]{1,15}) | [2-9] [0-9]{1,15})133 space ::= | " " | "\n"{1,2} [ \t]{0,20}134 )"""135 });136 137 test({138 SUCCESS,139 "min 25",140 R"""({141 "type": "integer",142 "minimum": 25143 })""",144 R"""(145 root ::= ([1] [0-9]{2,15} | [2] ([0-4] [0-9]{1,14} | [5-9] [0-9]{0,14}) | [3-9] [0-9]{1,15})146 space ::= | " " | "\n"{1,2} [ \t]{0,20}147 )"""148 });149 150 test({151 SUCCESS,152 "max 30",153 R"""({154 "type": "integer",155 "maximum": 30156 })""",157 R"""(158 root ::= ("-" [1-9] [0-9]{0,15} | [0-9] | ([1-2] [0-9] | [3] "0"))159 space ::= | " " | "\n"{1,2} [ \t]{0,20}160 )"""161 });162 163 test({164 SUCCESS,165 "min -5",166 R"""({167 "type": "integer",168 "minimum": -5169 })""",170 R"""(171 root ::= ("-" ([0-5]) | [0] | [1-9] [0-9]{0,15})172 space ::= | " " | "\n"{1,2} [ \t]{0,20}173 )"""174 });175 176 test({177 SUCCESS,178 "min -123",179 R"""({180 "type": "integer",181 "minimum": -123182 })""",183 R"""(184 root ::= ("-" ([0-9] | ([1-8] [0-9] | [9] [0-9]) | "1" ([0-1] [0-9] | [2] [0-3])) | [0] | [1-9] [0-9]{0,15})185 space ::= | " " | "\n"{1,2} [ \t]{0,20}186 )"""187 });188 189 test({190 SUCCESS,191 "max -5",192 R"""({193 "type": "integer",194 "maximum": -5195 })""",196 R"""(197 root ::= ("-" ([0-4] [0-9]{1,15} | [5-9] [0-9]{0,15}))198 space ::= | " " | "\n"{1,2} [ \t]{0,20}199 )"""200 });201 202 test({203 SUCCESS,204 "max 1",205 R"""({206 "type": "integer",207 "maximum": 1208 })""",209 R"""(210 root ::= ("-" [1-9] [0-9]{0,15} | [0-1])211 space ::= | " " | "\n"{1,2} [ \t]{0,20}212 )"""213 });214 215 test({216 SUCCESS,217 "max 100",218 R"""({219 "type": "integer",220 "maximum": 100221 })""",222 R"""(223 root ::= ("-" [1-9] [0-9]{0,15} | [0-9] | ([1-8] [0-9] | [9] [0-9]) | "100")224 space ::= | " " | "\n"{1,2} [ \t]{0,20}225 )"""226 });227 228 test({229 SUCCESS,230 "min 0 max 23",231 R"""({232 "type": "integer",233 "minimum": 0,234 "maximum": 23235 })""",236 R"""(237 root ::= ([0-9] | ([1] [0-9] | [2] [0-3]))238 space ::= | " " | "\n"{1,2} [ \t]{0,20}239 )"""240 });241 242 test({243 SUCCESS,244 "min 15 max 300",245 R"""({246 "type": "integer",247 "minimum": 15,248 "maximum": 300249 })""",250 R"""(251 root ::= (([1] ([5-9]) | [2-9] [0-9]) | ([1-2] [0-9]{2} | [3] "00"))252 space ::= | " " | "\n"{1,2} [ \t]{0,20}253 )"""254 });255 256 test({257 SUCCESS,258 "min 5 max 30",259 R"""({260 "type": "integer",261 "minimum": 5,262 "maximum": 30263 })""",264 R"""(265 root ::= ([5-9] | ([1-2] [0-9] | [3] "0"))266 space ::= | " " | "\n"{1,2} [ \t]{0,20}267 )"""268 });269 270 test({271 SUCCESS,272 "min -123 max 42",273 R"""({274 "type": "integer",275 "minimum": -123,276 "maximum": 42277 })""",278 R"""(279 root ::= ("-" ([0-9] | ([1-8] [0-9] | [9] [0-9]) | "1" ([0-1] [0-9] | [2] [0-3])) | [0-9] | ([1-3] [0-9] | [4] [0-2]))280 space ::= | " " | "\n"{1,2} [ \t]{0,20}281 )"""282 });283 284 test({285 SUCCESS,286 "min -10 max 10",287 R"""({288 "type": "integer",289 "minimum": -10,290 "maximum": 10291 })""",292 R"""(293 root ::= ("-" ([0-9] | "10") | [0-9] | "10")294 space ::= | " " | "\n"{1,2} [ \t]{0,20}295 )"""296 });297 298 test({299 FAILURE,300 "unknown type",301 R"""({302 "type": "kaboom"303 })""",304 ""305 });306 307 test({308 FAILURE,309 "invalid type",310 R"""({311 "type": 123312 })""",313 ""314 });315 316 test({317 SUCCESS,318 "empty schema (any value)",319 "{}",320 R"""(321 array ::= "[" space ( value ("," space value)* )? space "]"322 boolean ::= ("true" | "false")323 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})324 decimal-part ::= [0-9]{1,16}325 integral-part ::= [0] | [1-9] [0-9]{0,15}326 null ::= "null"327 number ::= ("-"? integral-part) ("." decimal-part)? ([eE] [-+]? integral-part)?328 object ::= "{" space ( string ":" space value ("," space string ":" space value)* )? space "}"329 root ::= value330 space ::= | " " | "\n"{1,2} [ \t]{0,20}331 string ::= "\"" char* "\""332 value ::= object | array | string | number | boolean | null333 )"""334 });335 336 test({337 SUCCESS,338 "exotic formats",339 R"""({340 "items": [341 { "format": "date" },342 { "format": "uuid" },343 { "format": "time" },344 { "format": "date-time" }345 ]346 })""",347 R"""(348 date ::= [0-9]{4} "-" ( "0" [1-9] | "1" [0-2] ) "-" ( "0" [1-9] | [1-2] [0-9] | "3" [0-1] )349 date-string ::= "\"" date "\""350 date-time ::= date "T" time351 date-time-string ::= "\"" date-time "\""352 root ::= "[" space tuple-0 "," space uuid "," space tuple-2 "," space tuple-3 space "]"353 space ::= | " " | "\n"{1,2} [ \t]{0,20}354 time ::= ([01] [0-9] | "2" [0-3]) ":" [0-5] [0-9] ":" [0-5] [0-9] ( "." [0-9]{3} )? ( "Z" | ( "+" | "-" ) ( [01] [0-9] | "2" [0-3] ) ":" [0-5] [0-9] )355 time-string ::= "\"" time "\""356 tuple-0 ::= date-string357 tuple-2 ::= time-string358 tuple-3 ::= date-time-string359 uuid ::= "\"" [0-9a-fA-F]{8} "-" [0-9a-fA-F]{4} "-" [0-9a-fA-F]{4} "-" [0-9a-fA-F]{4} "-" [0-9a-fA-F]{12} "\""360 )"""361 });362 363 test({364 SUCCESS,365 "string",366 R"""({367 "type": "string"368 })""",369 R"""(370 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})371 root ::= "\"" char* "\""372 space ::= | " " | "\n"{1,2} [ \t]{0,20}373 )"""374 });375 376 test({377 SUCCESS,378 "string w/ min length 1",379 R"""({380 "type": "string",381 "minLength": 1382 })""",383 R"""(384 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})385 root ::= "\"" char+ "\""386 space ::= | " " | "\n"{1,2} [ \t]{0,20}387 )"""388 });389 390 test({391 SUCCESS,392 "string w/ min length 3",393 R"""({394 "type": "string",395 "minLength": 3396 })""",397 R"""(398 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})399 root ::= "\"" char{3,} "\""400 space ::= | " " | "\n"{1,2} [ \t]{0,20}401 )"""402 });403 404 test({405 SUCCESS,406 "string w/ max length",407 R"""({408 "type": "string",409 "maxLength": 3410 })""",411 R"""(412 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})413 root ::= "\"" char{0,3} "\""414 space ::= | " " | "\n"{1,2} [ \t]{0,20}415 )"""416 });417 418 test({419 SUCCESS,420 "string w/ min & max length",421 R"""({422 "type": "string",423 "minLength": 1,424 "maxLength": 4425 })""",426 R"""(427 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})428 root ::= "\"" char{1,4} "\""429 space ::= | " " | "\n"{1,2} [ \t]{0,20}430 )"""431 });432 433 test({434 SUCCESS,435 "boolean",436 R"""({437 "type": "boolean"438 })""",439 R"""(440 root ::= ("true" | "false")441 space ::= | " " | "\n"{1,2} [ \t]{0,20}442 )"""443 });444 445 test({446 SUCCESS,447 "integer",448 R"""({449 "type": "integer"450 })""",451 R"""(452 integral-part ::= [0] | [1-9] [0-9]{0,15}453 root ::= ("-"? integral-part)454 space ::= | " " | "\n"{1,2} [ \t]{0,20}455 )"""456 });457 458 test({459 SUCCESS,460 "string const",461 R"""({462 "const": "foo"463 })""",464 R"""(465 root ::= "\"foo\""466 space ::= | " " | "\n"{1,2} [ \t]{0,20}467 )"""468 });469 470 test({471 SUCCESS,472 "non-string const",473 R"""({474 "const": 123475 })""",476 R"""(477 root ::= "123"478 space ::= | " " | "\n"{1,2} [ \t]{0,20}479 )"""480 });481 482 test({483 SUCCESS,484 "non-string enum",485 R"""({486 "enum": ["red", "amber", "green", null, 42, ["foo"]]487 })""",488 R"""(489 root ::= ("\"red\"" | "\"amber\"" | "\"green\"" | "null" | "42" | "[\"foo\"]")490 space ::= | " " | "\n"{1,2} [ \t]{0,20}491 )"""492 });493 494 test({495 SUCCESS,496 "string array",497 R"""({498 "type": "array",499 "prefixItems": { "type": "string" }500 })""",501 R"""(502 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})503 root ::= "[" space (string ("," space string)*)? space "]"504 space ::= | " " | "\n"{1,2} [ \t]{0,20}505 string ::= "\"" char* "\""506 )"""507 });508 509 test({510 SUCCESS,511 "nullable string array",512 R"""({513 "type": ["array", "null"],514 "prefixItems": { "type": "string" }515 })""",516 R"""(517 alternative-0 ::= "[" space (string ("," space string)*)? space "]"518 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})519 null ::= "null"520 root ::= alternative-0 | null521 space ::= | " " | "\n"{1,2} [ \t]{0,20}522 string ::= "\"" char* "\""523 )"""524 });525 526 test({527 SUCCESS,528 "tuple1",529 R"""({530 "prefixItems": [{ "type": "string" }]531 })""",532 R"""(533 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})534 root ::= "[" space string space "]"535 space ::= | " " | "\n"{1,2} [ \t]{0,20}536 string ::= "\"" char* "\""537 )"""538 });539 540 test({541 SUCCESS,542 "tuple2",543 R"""({544 "prefixItems": [{ "type": "string" }, { "type": "number" }]545 })""",546 R"""(547 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})548 decimal-part ::= [0-9]{1,16}549 integral-part ::= [0] | [1-9] [0-9]{0,15}550 number ::= ("-"? integral-part) ("." decimal-part)? ([eE] [-+]? integral-part)?551 root ::= "[" space string "," space number space "]"552 space ::= | " " | "\n"{1,2} [ \t]{0,20}553 string ::= "\"" char* "\""554 )"""555 });556 557 // items {} constrains nothing, the same as no items at all558 test({559 SUCCESS,560 "array with empty items",561 R"""({562 "type": "array",563 "items": {}564 })""",565 R"""(566 array ::= "[" space ( value ("," space value)* )? space "]"567 boolean ::= ("true" | "false")568 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})569 decimal-part ::= [0-9]{1,16}570 integral-part ::= [0] | [1-9] [0-9]{0,15}571 null ::= "null"572 number ::= ("-"? integral-part) ("." decimal-part)? ([eE] [-+]? integral-part)?573 object ::= "{" space ( string ":" space value ("," space string ":" space value)* )? space "}"574 root ::= "[" space ( value ("," space value)* )? space "]"575 space ::= | " " | "\n"{1,2} [ \t]{0,20}576 string ::= "\"" char* "\""577 value ::= object | array | string | number | boolean | null578 )"""579 });580 581 test({582 SUCCESS,583 "array with empty items and prefixItems",584 R"""({585 "type": "array",586 "items": {},587 "prefixItems": { "type": "string" }588 })""",589 R"""(590 array ::= "[" space ( value ("," space value)* )? space "]"591 boolean ::= ("true" | "false")592 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})593 decimal-part ::= [0-9]{1,16}594 integral-part ::= [0] | [1-9] [0-9]{0,15}595 null ::= "null"596 number ::= ("-"? integral-part) ("." decimal-part)? ([eE] [-+]? integral-part)?597 object ::= "{" space ( string ":" space value ("," space string ":" space value)* )? space "}"598 root ::= "[" space ( value ("," space value)* )? space "]"599 space ::= | " " | "\n"{1,2} [ \t]{0,20}600 string ::= "\"" char* "\""601 value ::= object | array | string | number | boolean | null602 )"""603 });604 605 test({606 SUCCESS,607 "number",608 R"""({609 "type": "number"610 })""",611 R"""(612 decimal-part ::= [0-9]{1,16}613 integral-part ::= [0] | [1-9] [0-9]{0,15}614 root ::= ("-"? integral-part) ("." decimal-part)? ([eE] [-+]? integral-part)?615 space ::= | " " | "\n"{1,2} [ \t]{0,20}616 )"""617 });618 619 test({620 SUCCESS,621 "minItems",622 R"""({623 "items": {624 "type": "boolean"625 },626 "minItems": 2627 })""",628 R"""(629 boolean ::= ("true" | "false")630 root ::= "[" space boolean ("," space boolean)+ space "]"631 space ::= | " " | "\n"{1,2} [ \t]{0,20}632 )"""633 });634 635 test({636 SUCCESS,637 "maxItems 0",638 R"""({639 "items": {640 "type": "boolean"641 },642 "maxItems": 0643 })""",644 R"""(645 boolean ::= ("true" | "false")646 root ::= "[" space space "]"647 space ::= | " " | "\n"{1,2} [ \t]{0,20}648 )"""649 });650 651 test({652 SUCCESS,653 "maxItems 1",654 R"""({655 "items": {656 "type": "boolean"657 },658 "maxItems": 1659 })""",660 R"""(661 boolean ::= ("true" | "false")662 root ::= "[" space boolean? space "]"663 space ::= | " " | "\n"{1,2} [ \t]{0,20}664 )"""665 });666 667 test({668 SUCCESS,669 "maxItems 2",670 R"""({671 "items": {672 "type": "boolean"673 },674 "maxItems": 2675 })""",676 R"""(677 boolean ::= ("true" | "false")678 root ::= "[" space (boolean ("," space boolean)?)? space "]"679 space ::= | " " | "\n"{1,2} [ \t]{0,20}680 )"""681 });682 683 test({684 SUCCESS,685 "min + maxItems",686 R"""({687 "items": {688 "type": ["number", "integer"]689 },690 "minItems": 3,691 "maxItems": 5692 })""",693 R"""(694 decimal-part ::= [0-9]{1,16}695 integer ::= ("-"? integral-part)696 integral-part ::= [0] | [1-9] [0-9]{0,15}697 item ::= number | integer698 number ::= ("-"? integral-part) ("." decimal-part)? ([eE] [-+]? integral-part)?699 root ::= "[" space item ("," space item){2,4} space "]"700 space ::= | " " | "\n"{1,2} [ \t]{0,20}701 )"""702 });703 704 test({705 SUCCESS,706 "min + max items with min + max values across zero",707 R"""({708 "items": {709 "type": "integer",710 "minimum": -12,711 "maximum": 207712 },713 "minItems": 3,714 "maxItems": 5715 })""",716 R"""(717 item ::= ("-" ([0-9] | "1" [0-2]) | [0-9] | ([1-8] [0-9] | [9] [0-9]) | ([1] [0-9]{2} | [2] "0" [0-7]))718 root ::= "[" space item ("," space item){2,4} space "]"719 space ::= | " " | "\n"{1,2} [ \t]{0,20}720 )"""721 });722 723 test({724 SUCCESS,725 "min + max items with min + max values",726 R"""({727 "items": {728 "type": "integer",729 "minimum": 12,730 "maximum": 207731 },732 "minItems": 3,733 "maxItems": 5734 })""",735 R"""(736 item ::= (([1] ([2-9]) | [2-9] [0-9]) | ([1] [0-9]{2} | [2] "0" [0-7]))737 root ::= "[" space item ("," space item){2,4} space "]"738 space ::= | " " | "\n"{1,2} [ \t]{0,20}739 )"""740 });741 742 test({743 SUCCESS,744 "simple regexp",745 R"""({746 "type": "string",747 "pattern": "^abc?d*efg+(hij)?kl$"748 })""",749 R"""(750 root ::= "\"" ("ab" "c"? "d"* "ef" "g"+ ("hij")? "kl") "\""751 space ::= | " " | "\n"{1,2} [ \t]{0,20}752 )"""753 });754 755 test({756 SUCCESS,757 "regexp escapes",758 R"""({759 "type": "string",760 "pattern": "^\\[\\]\\{\\}\\(\\)\\|\\+\\*\\?$"761 })""",762 R"""(763 root ::= "\"" ("[]{}()|+*?") "\""764 space ::= | " " | "\n"{1,2} [ \t]{0,20}765 )"""766 });767 768 test({769 SUCCESS,770 "regexp quote",771 R"""({772 "type": "string",773 "pattern": "^\"$"774 })""",775 R"""(776 root ::= "\"" ("\"") "\""777 space ::= | " " | "\n"{1,2} [ \t]{0,20}778 )"""779 });780 781 test({782 SUCCESS,783 "regexp with top-level alternation",784 R"""({785 "type": "string",786 "pattern": "^A|B|C|D$"787 })""",788 R"""(789 root ::= "\"" ("A" | "B" | "C" | "D") "\""790 space ::= | " " | "\n"{1,2} [ \t]{0,20}791 )"""792 });793 794 test({795 SUCCESS,796 "regexp",797 R"""({798 "type": "string",799 "pattern": "^(\\([0-9]{1,3}\\))?[0-9]{3}-[0-9]{4} a{3,5}nd...$"800 })""",801 R"""(802 dot ::= [^\x0A\x0D]803 root ::= "\"" (("(" root-1{1,3} ")")? root-1{3,3} "-" root-1{4,4} " " "a"{3,5} "nd" dot dot dot) "\""804 root-1 ::= [0-9]805 space ::= | " " | "\n"{1,2} [ \t]{0,20}806 )"""807 });808 809 test({810 SUCCESS,811 "required props in original order",812 R"""({813 "type": "object",814 "properties": {815 "b": {"type": "string"},816 "c": {"type": "string"},817 "a": {"type": "string"}818 },819 "required": [820 "a",821 "b",822 "c"823 ],824 "additionalProperties": false,825 "definitions": {}826 })""",827 R"""(828 a-kv ::= "\"a\"" space ":" space string829 b-kv ::= "\"b\"" space ":" space string830 c-kv ::= "\"c\"" space ":" space string831 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})832 root ::= "{" space b-kv "," space c-kv "," space a-kv space "}"833 space ::= | " " | "\n"{1,2} [ \t]{0,20}834 string ::= "\"" char* "\""835 )"""836 });837 838 test({839 SUCCESS,840 "1 optional prop",841 R"""({842 "properties": {843 "a": {844 "type": "string"845 }846 },847 "additionalProperties": false848 })""",849 R"""(850 a-kv ::= "\"a\"" space ":" space string851 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})852 root ::= "{" space (a-kv )? space "}"853 space ::= | " " | "\n"{1,2} [ \t]{0,20}854 string ::= "\"" char* "\""855 )"""856 });857 858 test({859 SUCCESS,860 "N optional props",861 R"""({862 "properties": {863 "a": {"type": "string"},864 "b": {"type": "string"},865 "c": {"type": "string"}866 },867 "additionalProperties": false868 })""",869 R"""(870 a-kv ::= "\"a\"" space ":" space string871 a-rest ::= ( "," space b-kv )? b-rest872 b-kv ::= "\"b\"" space ":" space string873 b-rest ::= ( "," space c-kv )?874 c-kv ::= "\"c\"" space ":" space string875 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})876 root ::= "{" space (a-kv a-rest | b-kv b-rest | c-kv )? space "}"877 space ::= | " " | "\n"{1,2} [ \t]{0,20}878 string ::= "\"" char* "\""879 )"""880 });881 882 test({883 SUCCESS,884 "required + optional props each in original order",885 R"""({886 "properties": {887 "b": {"type": "string"},888 "a": {"type": "string"},889 "d": {"type": "string"},890 "c": {"type": "string"}891 },892 "required": ["a", "b"],893 "additionalProperties": false894 })""",895 R"""(896 a-kv ::= "\"a\"" space ":" space string897 b-kv ::= "\"b\"" space ":" space string898 c-kv ::= "\"c\"" space ":" space string899 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})900 d-kv ::= "\"d\"" space ":" space string901 d-rest ::= ( "," space c-kv )?902 root ::= "{" space b-kv "," space a-kv ( "," space ( d-kv d-rest | c-kv ) )? space "}"903 space ::= | " " | "\n"{1,2} [ \t]{0,20}904 string ::= "\"" char* "\""905 )"""906 });907 908 test({909 SUCCESS,910 "additional props",911 R"""({912 "type": "object",913 "additionalProperties": {"type": "array", "items": {"type": "number"}}914 })""",915 R"""(916 additional-kv ::= string ":" space additional-value917 additional-value ::= "[" space (number ("," space number)*)? space "]"918 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})919 decimal-part ::= [0-9]{1,16}920 integral-part ::= [0] | [1-9] [0-9]{0,15}921 number ::= ("-"? integral-part) ("." decimal-part)? ([eE] [-+]? integral-part)?922 root ::= "{" space (additional-kv ( "," space additional-kv )* )? space "}"923 space ::= | " " | "\n"{1,2} [ \t]{0,20}924 string ::= "\"" char* "\""925 )"""926 });927 928 test({929 SUCCESS,930 "additional props (true)",931 R"""({932 "type": "object",933 "additionalProperties": true934 })""",935 R"""(936 array ::= "[" space ( value ("," space value)* )? space "]"937 boolean ::= ("true" | "false")938 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})939 decimal-part ::= [0-9]{1,16}940 integral-part ::= [0] | [1-9] [0-9]{0,15}941 null ::= "null"942 number ::= ("-"? integral-part) ("." decimal-part)? ([eE] [-+]? integral-part)?943 object ::= "{" space ( string ":" space value ("," space string ":" space value)* )? space "}"944 root ::= object945 space ::= | " " | "\n"{1,2} [ \t]{0,20}946 string ::= "\"" char* "\""947 value ::= object | array | string | number | boolean | null948 )"""949 });950 951 test({952 SUCCESS,953 "additional props (implicit)",954 R"""({955 "type": "object"956 })""",957 R"""(958 array ::= "[" space ( value ("," space value)* )? space "]"959 boolean ::= ("true" | "false")960 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})961 decimal-part ::= [0-9]{1,16}962 integral-part ::= [0] | [1-9] [0-9]{0,15}963 null ::= "null"964 number ::= ("-"? integral-part) ("." decimal-part)? ([eE] [-+]? integral-part)?965 object ::= "{" space ( string ":" space value ("," space string ":" space value)* )? space "}"966 root ::= object967 space ::= | " " | "\n"{1,2} [ \t]{0,20}968 string ::= "\"" char* "\""969 value ::= object | array | string | number | boolean | null970 )"""971 });972 973 test({974 SUCCESS,975 "empty w/o additional props",976 R"""({977 "type": "object",978 "additionalProperties": false979 })""",980 R"""(981 root ::= "{" space "}"982 space ::= | " " | "\n"{1,2} [ \t]{0,20}983 )"""984 });985 986 test({987 SUCCESS,988 "required + additional props",989 R"""({990 "type": "object",991 "properties": {992 "a": {"type": "number"}993 },994 "required": ["a"],995 "additionalProperties": {"type": "string"}996 })""",997 R"""(998 a-kv ::= "\"a\"" space ":" space number999 additional-k ::= ["] ( [a] char+ | [^"a] char* )? ["]1000 additional-kv ::= additional-k ":" space string1001 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})1002 decimal-part ::= [0-9]{1,16}1003 integral-part ::= [0] | [1-9] [0-9]{0,15}1004 number ::= ("-"? integral-part) ("." decimal-part)? ([eE] [-+]? integral-part)?1005 root ::= "{" space a-kv ( "," space ( additional-kv ( "," space additional-kv )* ) )? space "}"1006 space ::= | " " | "\n"{1,2} [ \t]{0,20}1007 string ::= "\"" char* "\""1008 )"""1009 });1010 1011 test({1012 SUCCESS,1013 "optional + additional props",1014 R"""({1015 "type": "object",1016 "properties": {1017 "a": {"type": "number"}1018 },1019 "additionalProperties": {"type": "number"}1020 })""",1021 R"""(1022 a-kv ::= "\"a\"" space ":" space number1023 a-rest ::= ( "," space additional-kv )*1024 additional-k ::= ["] ( [a] char+ | [^"a] char* )? ["]1025 additional-kv ::= additional-k ":" space number1026 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})1027 decimal-part ::= [0-9]{1,16}1028 integral-part ::= [0] | [1-9] [0-9]{0,15}1029 number ::= ("-"? integral-part) ("." decimal-part)? ([eE] [-+]? integral-part)?1030 root ::= "{" space (a-kv a-rest | additional-kv ( "," space additional-kv )* )? space "}"1031 space ::= | " " | "\n"{1,2} [ \t]{0,20}1032 )"""1033 });1034 1035 test({1036 SUCCESS,1037 "required + optional + additional props",1038 R"""({1039 "type": "object",1040 "properties": {1041 "and": {"type": "number"},1042 "also": {"type": "number"}1043 },1044 "required": ["and"],1045 "additionalProperties": {"type": "number"}1046 })""",1047 R"""(1048 additional-k ::= ["] ( [a] ([l] ([s] ([o] char+ | [^"o] char*) | [^"s] char*) | [n] ([d] char+ | [^"d] char*) | [^"ln] char*) | [^"a] char* )? ["]1049 additional-kv ::= additional-k ":" space number1050 also-kv ::= "\"also\"" space ":" space number1051 also-rest ::= ( "," space additional-kv )*1052 and-kv ::= "\"and\"" space ":" space number1053 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})1054 decimal-part ::= [0-9]{1,16}1055 integral-part ::= [0] | [1-9] [0-9]{0,15}1056 number ::= ("-"? integral-part) ("." decimal-part)? ([eE] [-+]? integral-part)?1057 root ::= "{" space and-kv ( "," space ( also-kv also-rest | additional-kv ( "," space additional-kv )* ) )? space "}"1058 space ::= | " " | "\n"{1,2} [ \t]{0,20}1059 )"""1060 });1061 1062 test({1063 SUCCESS,1064 "optional props with empty name",1065 R"""({1066 "properties": {1067 "": {"type": "integer"},1068 "a": {"type": "integer"}1069 },1070 "additionalProperties": {"type": "integer"}1071 })""",1072 R"""(1073 -kv ::= "\"\"" space ":" space root1074 -rest ::= ( "," space a-kv )? a-rest1075 a-kv ::= "\"a\"" space ":" space integer1076 a-rest ::= ( "," space additional-kv )*1077 additional-k ::= ["] ( [a] char+ | [^"a] char* ) ["]1078 additional-kv ::= additional-k ":" space integer1079 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})1080 integer ::= ("-"? integral-part)1081 integral-part ::= [0] | [1-9] [0-9]{0,15}1082 root ::= ("-"? integral-part)1083 root0 ::= "{" space (-kv -rest | a-kv a-rest | additional-kv ( "," space additional-kv )* )? space "}"1084 space ::= | " " | "\n"{1,2} [ \t]{0,20}1085 )"""1086 });1087 1088 test({1089 SUCCESS,1090 "optional props with nested names",1091 R"""({1092 "properties": {1093 "a": {"type": "integer"},1094 "aa": {"type": "integer"}1095 },1096 "additionalProperties": {"type": "integer"}1097 })""",1098 R"""(1099 a-kv ::= "\"a\"" space ":" space integer1100 a-rest ::= ( "," space aa-kv )? aa-rest1101 aa-kv ::= "\"aa\"" space ":" space integer1102 aa-rest ::= ( "," space additional-kv )*1103 additional-k ::= ["] ( [a] ([a] char+ | [^"a] char*) | [^"a] char* )? ["]1104 additional-kv ::= additional-k ":" space integer1105 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})1106 integer ::= ("-"? integral-part)1107 integral-part ::= [0] | [1-9] [0-9]{0,15}1108 root ::= "{" space (a-kv a-rest | aa-kv aa-rest | additional-kv ( "," space additional-kv )* )? space "}"1109 space ::= | " " | "\n"{1,2} [ \t]{0,20}1110 )"""1111 });1112 1113 test({1114 SUCCESS,1115 "optional props with common prefix",1116 R"""({1117 "properties": {1118 "ab": {"type": "integer"},1119 "ac": {"type": "integer"}1120 },1121 "additionalProperties": {"type": "integer"}1122 })""",1123 R"""(1124 ab-kv ::= "\"ab\"" space ":" space integer1125 ab-rest ::= ( "," space ac-kv )? ac-rest1126 ac-kv ::= "\"ac\"" space ":" space integer1127 ac-rest ::= ( "," space additional-kv )*1128 additional-k ::= ["] ( [a] ([b] char+ | [c] char+ | [^"bc] char*) | [^"a] char* )? ["]1129 additional-kv ::= additional-k ":" space integer1130 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})1131 integer ::= ("-"? integral-part)1132 integral-part ::= [0] | [1-9] [0-9]{0,15}1133 root ::= "{" space (ab-kv ab-rest | ac-kv ac-rest | additional-kv ( "," space additional-kv )* )? space "}"1134 space ::= | " " | "\n"{1,2} [ \t]{0,20}1135 )"""1136 });1137 1138 test({1139 SUCCESS,1140 "top-level $ref",1141 R"""({1142 "$ref": "#/definitions/foo",1143 "definitions": {1144 "foo": {1145 "type": "object",1146 "properties": {1147 "a": {1148 "type": "string"1149 }1150 },1151 "required": [1152 "a"1153 ],1154 "additionalProperties": false1155 }1156 }1157 })""",1158 R"""(1159 char ::= [^"\\\x7F\x00-\x1F] | [\\] (["\\bfnrt] | "u" [0-9a-fA-F]{4})1160 ref-definitions-foo ::= "{" space ref-definitions-foo-a-kv space "}"1161 ref-definitions-foo-a-kv ::= "\"a\"" space ":" space string1162 root ::= ref-definitions-foo1163 space ::= | " " | "\n"{1,2} [ \t]{0,20}1164 string ::= "\"" char* "\""1165 )"""1166 });1167 1168 test({1169 SUCCESS,1170 "anyOf",1171 R"""({1172 "anyOf": [1173 {"$ref": "#/definitions/foo"},1174 {"$ref": "#/definitions/bar"}1175 ],1176 "definitions": {1177 "foo": {1178 "properties": {"a": {"type": "number"}}1179 },1180 "bar": {1181 "properties": {"b": {"type": "number"}}1182 }1183 },1184 "type": "object"1185 })""",1186 R"""(1187 alternative-0 ::= ref-definitions-foo1188 alternative-1 ::= ref-definitions-bar1189 decimal-part ::= [0-9]{1,16}1190 integral-part ::= [0] | [1-9] [0-9]{0,15}1191 number ::= ("-"? integral-part) ("." decimal-part)? ([eE] [-+]? integral-part)?1192 ref-definitions-bar ::= "{" space (ref-definitions-bar-b-kv )? space "}"1193 ref-definitions-bar-b-kv ::= "\"b\"" space ":" space number1194 ref-definitions-foo ::= "{" space (ref-definitions-foo-a-kv )? space "}"1195 ref-definitions-foo-a-kv ::= "\"a\"" space ":" space number1196 root ::= alternative-0 | alternative-11197 space ::= | " " | "\n"{1,2} [ \t]{0,20}1198 )"""1199 });1200 