schematest.cpp 78 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072
  1. // Tencent is pleased to support the open source community by making RapidJSON available.
  2. //
  3. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
  4. //
  5. // Licensed under the MIT License (the "License"); you may not use this file except
  6. // in compliance with the License. You may obtain a copy of the License at
  7. //
  8. // http://opensource.org/licenses/MIT
  9. //
  10. // Unless required by applicable law or agreed to in writing, software distributed
  11. // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  12. // CONDITIONS OF ANY KIND, either express or implied. See the License for the
  13. // specific language governing permissions and limitations under the License.
  14. #include "unittest.h"
  15. #include "rapidjson/schema.h"
  16. #include "rapidjson/stringbuffer.h"
  17. #include "rapidjson/writer.h"
  18. #ifdef __clang__
  19. RAPIDJSON_DIAG_PUSH
  20. RAPIDJSON_DIAG_OFF(variadic-macros)
  21. #elif defined(_MSC_VER)
  22. RAPIDJSON_DIAG_PUSH
  23. RAPIDJSON_DIAG_OFF(4822) // local class member function does not have a body
  24. #endif
  25. using namespace rapidjson;
  26. #define TEST_HASHER(json1, json2, expected) \
  27. {\
  28. Document d1, d2;\
  29. d1.Parse(json1);\
  30. ASSERT_FALSE(d1.HasParseError());\
  31. d2.Parse(json2);\
  32. ASSERT_FALSE(d2.HasParseError());\
  33. internal::Hasher<Value, CrtAllocator> h1, h2;\
  34. d1.Accept(h1);\
  35. d2.Accept(h2);\
  36. ASSERT_TRUE(h1.IsValid());\
  37. ASSERT_TRUE(h2.IsValid());\
  38. /*printf("%s: 0x%016llx\n%s: 0x%016llx\n\n", json1, h1.GetHashCode(), json2, h2.GetHashCode());*/\
  39. EXPECT_TRUE(expected == (h1.GetHashCode() == h2.GetHashCode()));\
  40. }
  41. TEST(SchemaValidator, Hasher) {
  42. TEST_HASHER("null", "null", true);
  43. TEST_HASHER("true", "true", true);
  44. TEST_HASHER("false", "false", true);
  45. TEST_HASHER("true", "false", false);
  46. TEST_HASHER("false", "true", false);
  47. TEST_HASHER("true", "null", false);
  48. TEST_HASHER("false", "null", false);
  49. TEST_HASHER("1", "1", true);
  50. TEST_HASHER("2147483648", "2147483648", true); // 2^31 can only be fit in unsigned
  51. TEST_HASHER("-2147483649", "-2147483649", true); // -2^31 - 1 can only be fit in int64_t
  52. TEST_HASHER("2147483648", "2147483648", true); // 2^31 can only be fit in unsigned
  53. TEST_HASHER("4294967296", "4294967296", true); // 2^32 can only be fit in int64_t
  54. TEST_HASHER("9223372036854775808", "9223372036854775808", true); // 2^63 can only be fit in uint64_t
  55. TEST_HASHER("1.5", "1.5", true);
  56. TEST_HASHER("1", "1.0", true);
  57. TEST_HASHER("1", "-1", false);
  58. TEST_HASHER("0.0", "-0.0", false);
  59. TEST_HASHER("1", "true", false);
  60. TEST_HASHER("0", "false", false);
  61. TEST_HASHER("0", "null", false);
  62. TEST_HASHER("\"\"", "\"\"", true);
  63. TEST_HASHER("\"\"", "\"\\u0000\"", false);
  64. TEST_HASHER("\"Hello\"", "\"Hello\"", true);
  65. TEST_HASHER("\"Hello\"", "\"World\"", false);
  66. TEST_HASHER("\"Hello\"", "null", false);
  67. TEST_HASHER("\"Hello\\u0000\"", "\"Hello\"", false);
  68. TEST_HASHER("\"\"", "null", false);
  69. TEST_HASHER("\"\"", "true", false);
  70. TEST_HASHER("\"\"", "false", false);
  71. TEST_HASHER("[]", "[ ]", true);
  72. TEST_HASHER("[1, true, false]", "[1, true, false]", true);
  73. TEST_HASHER("[1, true, false]", "[1, true]", false);
  74. TEST_HASHER("[1, 2]", "[2, 1]", false);
  75. TEST_HASHER("[[1], 2]", "[[1, 2]]", false);
  76. TEST_HASHER("[1, 2]", "[1, [2]]", false);
  77. TEST_HASHER("[]", "null", false);
  78. TEST_HASHER("[]", "true", false);
  79. TEST_HASHER("[]", "false", false);
  80. TEST_HASHER("[]", "0", false);
  81. TEST_HASHER("[]", "0.0", false);
  82. TEST_HASHER("[]", "\"\"", false);
  83. TEST_HASHER("{}", "{ }", true);
  84. TEST_HASHER("{\"a\":1}", "{\"a\":1}", true);
  85. TEST_HASHER("{\"a\":1}", "{\"b\":1}", false);
  86. TEST_HASHER("{\"a\":1}", "{\"a\":2}", false);
  87. TEST_HASHER("{\"a\":1, \"b\":2}", "{\"b\":2, \"a\":1}", true); // Member order insensitive
  88. TEST_HASHER("{}", "null", false);
  89. TEST_HASHER("{}", "false", false);
  90. TEST_HASHER("{}", "true", false);
  91. TEST_HASHER("{}", "0", false);
  92. TEST_HASHER("{}", "0.0", false);
  93. TEST_HASHER("{}", "\"\"", false);
  94. }
  95. // Test cases following http://spacetelescope.github.io/understanding-json-schema
  96. #define VALIDATE(schema, json, expected) \
  97. {\
  98. SchemaValidator validator(schema);\
  99. Document d;\
  100. /*printf("\n%s\n", json);*/\
  101. d.Parse(json);\
  102. EXPECT_FALSE(d.HasParseError());\
  103. EXPECT_TRUE(expected == d.Accept(validator));\
  104. EXPECT_TRUE(expected == validator.IsValid());\
  105. if ((expected) && !validator.IsValid()) {\
  106. StringBuffer sb;\
  107. validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);\
  108. printf("Invalid schema: %s\n", sb.GetString());\
  109. printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());\
  110. sb.Clear();\
  111. validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);\
  112. printf("Invalid document: %s\n", sb.GetString());\
  113. sb.Clear();\
  114. Writer<StringBuffer> w(sb);\
  115. validator.GetError().Accept(w);\
  116. printf("Validation error: %s\n", sb.GetString());\
  117. }\
  118. }
  119. #define INVALIDATE(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error) \
  120. {\
  121. INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error, SchemaValidator, Pointer) \
  122. }
  123. #define INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error, \
  124. SchemaValidatorType, PointerType) \
  125. {\
  126. SchemaValidatorType validator(schema);\
  127. Document d;\
  128. /*printf("\n%s\n", json);*/\
  129. d.Parse(json);\
  130. EXPECT_FALSE(d.HasParseError());\
  131. EXPECT_FALSE(d.Accept(validator));\
  132. EXPECT_FALSE(validator.IsValid());\
  133. if (validator.GetInvalidSchemaPointer() != PointerType(invalidSchemaPointer)) {\
  134. StringBuffer sb;\
  135. validator.GetInvalidSchemaPointer().Stringify(sb);\
  136. printf("GetInvalidSchemaPointer() Expected: %s Actual: %s\n", invalidSchemaPointer, sb.GetString());\
  137. ADD_FAILURE();\
  138. }\
  139. ASSERT_TRUE(validator.GetInvalidSchemaKeyword() != 0);\
  140. if (strcmp(validator.GetInvalidSchemaKeyword(), invalidSchemaKeyword) != 0) {\
  141. printf("GetInvalidSchemaKeyword() Expected: %s Actual %s\n", invalidSchemaKeyword, validator.GetInvalidSchemaKeyword());\
  142. ADD_FAILURE();\
  143. }\
  144. if (validator.GetInvalidDocumentPointer() != PointerType(invalidDocumentPointer)) {\
  145. StringBuffer sb;\
  146. validator.GetInvalidDocumentPointer().Stringify(sb);\
  147. printf("GetInvalidDocumentPointer() Expected: %s Actual: %s\n", invalidDocumentPointer, sb.GetString());\
  148. ADD_FAILURE();\
  149. }\
  150. Document e;\
  151. e.Parse(error);\
  152. if (validator.GetError() != e) {\
  153. StringBuffer sb;\
  154. Writer<StringBuffer> w(sb);\
  155. validator.GetError().Accept(w);\
  156. printf("GetError() Expected: %s Actual: %s\n", error, sb.GetString());\
  157. ADD_FAILURE();\
  158. }\
  159. }
  160. TEST(SchemaValidator, Typeless) {
  161. Document sd;
  162. sd.Parse("{}");
  163. SchemaDocument s(sd);
  164. VALIDATE(s, "42", true);
  165. VALIDATE(s, "\"I'm a string\"", true);
  166. VALIDATE(s, "{ \"an\": [ \"arbitrarily\", \"nested\" ], \"data\": \"structure\" }", true);
  167. }
  168. TEST(SchemaValidator, MultiType) {
  169. Document sd;
  170. sd.Parse("{ \"type\": [\"number\", \"string\"] }");
  171. SchemaDocument s(sd);
  172. VALIDATE(s, "42", true);
  173. VALIDATE(s, "\"Life, the universe, and everything\"", true);
  174. INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "",
  175. "{ \"type\": {"
  176. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  177. " \"expected\": [\"string\", \"number\"], \"actual\": \"array\""
  178. "}}");
  179. }
  180. TEST(SchemaValidator, Enum_Typed) {
  181. Document sd;
  182. sd.Parse("{ \"type\": \"string\", \"enum\" : [\"red\", \"amber\", \"green\"] }");
  183. SchemaDocument s(sd);
  184. VALIDATE(s, "\"red\"", true);
  185. INVALIDATE(s, "\"blue\"", "", "enum", "",
  186. "{ \"enum\": { \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
  187. }
  188. TEST(SchemaValidator, Enum_Typless) {
  189. Document sd;
  190. sd.Parse("{ \"enum\": [\"red\", \"amber\", \"green\", null, 42] }");
  191. SchemaDocument s(sd);
  192. VALIDATE(s, "\"red\"", true);
  193. VALIDATE(s, "null", true);
  194. VALIDATE(s, "42", true);
  195. INVALIDATE(s, "0", "", "enum", "",
  196. "{ \"enum\": { \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
  197. }
  198. TEST(SchemaValidator, Enum_InvalidType) {
  199. Document sd;
  200. sd.Parse("{ \"type\": \"string\", \"enum\": [\"red\", \"amber\", \"green\", null] }");
  201. SchemaDocument s(sd);
  202. VALIDATE(s, "\"red\"", true);
  203. INVALIDATE(s, "null", "", "type", "",
  204. "{ \"type\": {"
  205. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  206. " \"expected\": [\"string\"], \"actual\": \"null\""
  207. "}}");
  208. }
  209. TEST(SchemaValidator, AllOf) {
  210. {
  211. Document sd;
  212. sd.Parse("{\"allOf\": [{ \"type\": \"string\" }, { \"type\": \"string\", \"maxLength\": 5 }]}");
  213. SchemaDocument s(sd);
  214. VALIDATE(s, "\"ok\"", true);
  215. INVALIDATE(s, "\"too long\"", "", "allOf", "",
  216. "{ \"maxLength\": { "
  217. " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\", "
  218. " \"expected\": 5, \"actual\": \"too long\""
  219. "}}");
  220. }
  221. {
  222. Document sd;
  223. sd.Parse("{\"allOf\": [{ \"type\": \"string\" }, { \"type\": \"number\" } ] }");
  224. SchemaDocument s(sd);
  225. VALIDATE(s, "\"No way\"", false);
  226. INVALIDATE(s, "-1", "", "allOf", "",
  227. "{ \"type\": { \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\","
  228. " \"expected\": [\"string\"], \"actual\": \"integer\""
  229. "}}");
  230. }
  231. }
  232. TEST(SchemaValidator, AnyOf) {
  233. Document sd;
  234. sd.Parse("{\"anyOf\": [{ \"type\": \"string\" }, { \"type\": \"number\" } ] }");
  235. SchemaDocument s(sd);
  236. VALIDATE(s, "\"Yes\"", true);
  237. VALIDATE(s, "42", true);
  238. INVALIDATE(s, "{ \"Not a\": \"string or number\" }", "", "anyOf", "",
  239. "{ \"anyOf\": {"
  240. " \"instanceRef\": \"#\", \"schemaRef\": \"#\", "
  241. " \"errors\": ["
  242. " { \"type\": {"
  243. " \"instanceRef\": \"#\", \"schemaRef\": \"#/anyOf/0\","
  244. " \"expected\": [\"string\"], \"actual\": \"object\""
  245. " }},"
  246. " { \"type\": {"
  247. " \"instanceRef\": \"#\", \"schemaRef\": \"#/anyOf/1\","
  248. " \"expected\": [\"number\"], \"actual\": \"object\""
  249. " }}"
  250. " ]"
  251. "}}");
  252. }
  253. TEST(SchemaValidator, OneOf) {
  254. Document sd;
  255. sd.Parse("{\"oneOf\": [{ \"type\": \"number\", \"multipleOf\": 5 }, { \"type\": \"number\", \"multipleOf\": 3 } ] }");
  256. SchemaDocument s(sd);
  257. VALIDATE(s, "10", true);
  258. VALIDATE(s, "9", true);
  259. INVALIDATE(s, "2", "", "oneOf", "",
  260. "{ \"oneOf\": {"
  261. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  262. " \"errors\": ["
  263. " { \"multipleOf\": {"
  264. " \"instanceRef\": \"#\", \"schemaRef\": \"#/oneOf/0\","
  265. " \"expected\": 5, \"actual\": 2"
  266. " }},"
  267. " { \"multipleOf\": {"
  268. " \"instanceRef\": \"#\", \"schemaRef\": \"#/oneOf/1\","
  269. " \"expected\": 3, \"actual\": 2"
  270. " }}"
  271. " ]"
  272. "}}");
  273. INVALIDATE(s, "15", "", "oneOf", "",
  274. "{ \"oneOf\": { \"instanceRef\": \"#\", \"schemaRef\": \"#\", \"errors\": [{}, {}]}}");
  275. }
  276. TEST(SchemaValidator, Not) {
  277. Document sd;
  278. sd.Parse("{\"not\":{ \"type\": \"string\"}}");
  279. SchemaDocument s(sd);
  280. VALIDATE(s, "42", true);
  281. VALIDATE(s, "{ \"key\": \"value\" }", true);
  282. INVALIDATE(s, "\"I am a string\"", "", "not", "",
  283. "{ \"not\": { \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
  284. }
  285. TEST(SchemaValidator, Ref) {
  286. Document sd;
  287. sd.Parse(
  288. "{"
  289. " \"$schema\": \"http://json-schema.org/draft-04/schema#\","
  290. ""
  291. " \"definitions\": {"
  292. " \"address\": {"
  293. " \"type\": \"object\","
  294. " \"properties\": {"
  295. " \"street_address\": { \"type\": \"string\" },"
  296. " \"city\": { \"type\": \"string\" },"
  297. " \"state\": { \"type\": \"string\" }"
  298. " },"
  299. " \"required\": [\"street_address\", \"city\", \"state\"]"
  300. " }"
  301. " },"
  302. " \"type\": \"object\","
  303. " \"properties\": {"
  304. " \"billing_address\": { \"$ref\": \"#/definitions/address\" },"
  305. " \"shipping_address\": { \"$ref\": \"#/definitions/address\" }"
  306. " }"
  307. "}");
  308. SchemaDocument s(sd);
  309. VALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\"}, \"billing_address\": {\"street_address\": \"1st Street SE\", \"city\": \"Washington\", \"state\": \"DC\"} }", true);
  310. }
  311. TEST(SchemaValidator, Ref_AllOf) {
  312. Document sd;
  313. sd.Parse(
  314. "{"
  315. " \"$schema\": \"http://json-schema.org/draft-04/schema#\","
  316. ""
  317. " \"definitions\": {"
  318. " \"address\": {"
  319. " \"type\": \"object\","
  320. " \"properties\": {"
  321. " \"street_address\": { \"type\": \"string\" },"
  322. " \"city\": { \"type\": \"string\" },"
  323. " \"state\": { \"type\": \"string\" }"
  324. " },"
  325. " \"required\": [\"street_address\", \"city\", \"state\"]"
  326. " }"
  327. " },"
  328. " \"type\": \"object\","
  329. " \"properties\": {"
  330. " \"billing_address\": { \"$ref\": \"#/definitions/address\" },"
  331. " \"shipping_address\": {"
  332. " \"allOf\": ["
  333. " { \"$ref\": \"#/definitions/address\" },"
  334. " { \"properties\":"
  335. " { \"type\": { \"enum\": [ \"residential\", \"business\" ] } },"
  336. " \"required\": [\"type\"]"
  337. " }"
  338. " ]"
  339. " }"
  340. " }"
  341. "}");
  342. SchemaDocument s(sd);
  343. INVALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\"} }", "/properties/shipping_address", "allOf", "/shipping_address",
  344. "{ \"required\": {"
  345. " \"instanceRef\": \"#/shipping_address\","
  346. " \"schemaRef\": \"#/properties/shipping_address/allOf/1\","
  347. " \"missing\": [\"type\"]"
  348. "}}");
  349. VALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\", \"type\": \"business\"} }", true);
  350. }
  351. TEST(SchemaValidator, String) {
  352. Document sd;
  353. sd.Parse("{\"type\":\"string\"}");
  354. SchemaDocument s(sd);
  355. VALIDATE(s, "\"I'm a string\"", true);
  356. INVALIDATE(s, "42", "", "type", "",
  357. "{ \"type\": {"
  358. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  359. " \"expected\": [\"string\"], \"actual\": \"integer\""
  360. "}}");
  361. INVALIDATE(s, "2147483648", "", "type", "",
  362. "{ \"type\": {"
  363. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  364. " \"expected\": [\"string\"], \"actual\": \"integer\""
  365. "}}"); // 2^31 can only be fit in unsigned
  366. INVALIDATE(s, "-2147483649", "", "type", "",
  367. "{ \"type\": {"
  368. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  369. " \"expected\": [\"string\"], \"actual\": \"integer\""
  370. "}}"); // -2^31 - 1 can only be fit in int64_t
  371. INVALIDATE(s, "4294967296", "", "type", "",
  372. "{ \"type\": {"
  373. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  374. " \"expected\": [\"string\"], \"actual\": \"integer\""
  375. "}}"); // 2^32 can only be fit in int64_t
  376. INVALIDATE(s, "3.1415926", "", "type", "",
  377. "{ \"type\": {"
  378. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  379. " \"expected\": [\"string\"], \"actual\": \"number\""
  380. "}}");
  381. }
  382. TEST(SchemaValidator, String_LengthRange) {
  383. Document sd;
  384. sd.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
  385. SchemaDocument s(sd);
  386. INVALIDATE(s, "\"A\"", "", "minLength", "",
  387. "{ \"minLength\": {"
  388. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  389. " \"expected\": 2, \"actual\": \"A\""
  390. "}}");
  391. VALIDATE(s, "\"AB\"", true);
  392. VALIDATE(s, "\"ABC\"", true);
  393. INVALIDATE(s, "\"ABCD\"", "", "maxLength", "",
  394. "{ \"maxLength\": {"
  395. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  396. " \"expected\": 3, \"actual\": \"ABCD\""
  397. "}}");
  398. }
  399. #if RAPIDJSON_SCHEMA_HAS_REGEX
  400. TEST(SchemaValidator, String_Pattern) {
  401. Document sd;
  402. sd.Parse("{\"type\":\"string\",\"pattern\":\"^(\\\\([0-9]{3}\\\\))?[0-9]{3}-[0-9]{4}$\"}");
  403. SchemaDocument s(sd);
  404. VALIDATE(s, "\"555-1212\"", true);
  405. VALIDATE(s, "\"(888)555-1212\"", true);
  406. INVALIDATE(s, "\"(888)555-1212 ext. 532\"", "", "pattern", "",
  407. "{ \"pattern\": {"
  408. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  409. " \"actual\": \"(888)555-1212 ext. 532\""
  410. "}}");
  411. INVALIDATE(s, "\"(800)FLOWERS\"", "", "pattern", "",
  412. "{ \"pattern\": {"
  413. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  414. " \"actual\": \"(800)FLOWERS\""
  415. "}}");
  416. }
  417. TEST(SchemaValidator, String_Pattern_Invalid) {
  418. Document sd;
  419. sd.Parse("{\"type\":\"string\",\"pattern\":\"a{0}\"}"); // TODO: report regex is invalid somehow
  420. SchemaDocument s(sd);
  421. VALIDATE(s, "\"\"", true);
  422. VALIDATE(s, "\"a\"", true);
  423. VALIDATE(s, "\"aa\"", true);
  424. }
  425. #endif
  426. TEST(SchemaValidator, Integer) {
  427. Document sd;
  428. sd.Parse("{\"type\":\"integer\"}");
  429. SchemaDocument s(sd);
  430. VALIDATE(s, "42", true);
  431. VALIDATE(s, "-1", true);
  432. VALIDATE(s, "2147483648", true); // 2^31 can only be fit in unsigned
  433. VALIDATE(s, "-2147483649", true); // -2^31 - 1 can only be fit in int64_t
  434. VALIDATE(s, "2147483648", true); // 2^31 can only be fit in unsigned
  435. VALIDATE(s, "4294967296", true); // 2^32 can only be fit in int64_t
  436. INVALIDATE(s, "3.1415926", "", "type", "",
  437. "{ \"type\": {"
  438. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  439. " \"expected\": [\"integer\"], \"actual\": \"number\""
  440. "}}");
  441. INVALIDATE(s, "\"42\"", "", "type", "",
  442. "{ \"type\": {"
  443. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  444. " \"expected\": [\"integer\"], \"actual\": \"string\""
  445. "}}");
  446. }
  447. TEST(SchemaValidator, Integer_Range) {
  448. Document sd;
  449. sd.Parse("{\"type\":\"integer\",\"minimum\":0,\"maximum\":100,\"exclusiveMaximum\":true}");
  450. SchemaDocument s(sd);
  451. INVALIDATE(s, "-1", "", "minimum", "",
  452. "{ \"minimum\": {"
  453. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  454. " \"expected\": 0, \"actual\": -1"
  455. "}}");
  456. VALIDATE(s, "0", true);
  457. VALIDATE(s, "10", true);
  458. VALIDATE(s, "99", true);
  459. INVALIDATE(s, "100", "", "maximum", "",
  460. "{ \"maximum\": {"
  461. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  462. " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100"
  463. "}}");
  464. INVALIDATE(s, "101", "", "maximum", "",
  465. "{ \"maximum\": {"
  466. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  467. " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 101"
  468. "}}");
  469. }
  470. TEST(SchemaValidator, Integer_Range64Boundary) {
  471. Document sd;
  472. sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775807,\"maximum\":9223372036854775806}");
  473. SchemaDocument s(sd);
  474. INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
  475. "{ \"minimum\": {"
  476. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  477. " \"expected\": -9223372036854775807, \"actual\": -9223372036854775808"
  478. "}}");
  479. VALIDATE(s, "-9223372036854775807", true);
  480. VALIDATE(s, "-2147483648", true); // int min
  481. VALIDATE(s, "0", true);
  482. VALIDATE(s, "2147483647", true); // int max
  483. VALIDATE(s, "2147483648", true); // unsigned first
  484. VALIDATE(s, "4294967295", true); // unsigned max
  485. VALIDATE(s, "9223372036854775806", true);
  486. INVALIDATE(s, "9223372036854775807", "", "maximum", "",
  487. "{ \"maximum\": {"
  488. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  489. " \"expected\": 9223372036854775806, \"actual\": 9223372036854775807"
  490. "}}");
  491. INVALIDATE(s, "18446744073709551615", "", "maximum", "",
  492. "{ \"maximum\": {"
  493. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  494. " \"expected\": 9223372036854775806, \"actual\": 18446744073709551615"
  495. "}}"); // uint64_t max
  496. }
  497. TEST(SchemaValidator, Integer_RangeU64Boundary) {
  498. Document sd;
  499. sd.Parse("{\"type\":\"integer\",\"minimum\":9223372036854775808,\"maximum\":18446744073709551614}");
  500. SchemaDocument s(sd);
  501. INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
  502. "{ \"minimum\": {"
  503. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  504. " \"expected\": 9223372036854775808, \"actual\": -9223372036854775808"
  505. "}}");
  506. INVALIDATE(s, "9223372036854775807", "", "minimum", "",
  507. "{ \"minimum\": {"
  508. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  509. " \"expected\": 9223372036854775808, \"actual\": 9223372036854775807"
  510. "}}");
  511. INVALIDATE(s, "-2147483648", "", "minimum", "",
  512. "{ \"minimum\": {"
  513. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  514. " \"expected\": 9223372036854775808, \"actual\": -2147483648"
  515. "}}"); // int min
  516. INVALIDATE(s, "0", "", "minimum", "",
  517. "{ \"minimum\": {"
  518. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  519. " \"expected\": 9223372036854775808, \"actual\": 0"
  520. "}}");
  521. INVALIDATE(s, "2147483647", "", "minimum", "",
  522. "{ \"minimum\": {"
  523. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  524. " \"expected\": 9223372036854775808, \"actual\": 2147483647"
  525. "}}"); // int max
  526. INVALIDATE(s, "2147483648", "", "minimum", "",
  527. "{ \"minimum\": {"
  528. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  529. " \"expected\": 9223372036854775808, \"actual\": 2147483648"
  530. "}}"); // unsigned first
  531. INVALIDATE(s, "4294967295", "", "minimum", "",
  532. "{ \"minimum\": {"
  533. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  534. " \"expected\": 9223372036854775808, \"actual\": 4294967295"
  535. "}}"); // unsigned max
  536. VALIDATE(s, "9223372036854775808", true);
  537. VALIDATE(s, "18446744073709551614", true);
  538. INVALIDATE(s, "18446744073709551615", "", "maximum", "",
  539. "{ \"maximum\": {"
  540. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  541. " \"expected\": 18446744073709551614, \"actual\": 18446744073709551615"
  542. "}}");
  543. }
  544. TEST(SchemaValidator, Integer_Range64BoundaryExclusive) {
  545. Document sd;
  546. sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775808,\"maximum\":18446744073709551615,\"exclusiveMinimum\":true,\"exclusiveMaximum\":true}");
  547. SchemaDocument s(sd);
  548. INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
  549. "{ \"minimum\": {"
  550. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  551. " \"expected\": -9223372036854775808, \"exclusiveMinimum\": true, "
  552. " \"actual\": -9223372036854775808"
  553. "}}");
  554. VALIDATE(s, "-9223372036854775807", true);
  555. VALIDATE(s, "18446744073709551614", true);
  556. INVALIDATE(s, "18446744073709551615", "", "maximum", "",
  557. "{ \"maximum\": {"
  558. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  559. " \"expected\": 18446744073709551615, \"exclusiveMaximum\": true, "
  560. " \"actual\": 18446744073709551615"
  561. "}}");
  562. }
  563. TEST(SchemaValidator, Integer_MultipleOf) {
  564. Document sd;
  565. sd.Parse("{\"type\":\"integer\",\"multipleOf\":10}");
  566. SchemaDocument s(sd);
  567. VALIDATE(s, "0", true);
  568. VALIDATE(s, "10", true);
  569. VALIDATE(s, "-10", true);
  570. VALIDATE(s, "20", true);
  571. INVALIDATE(s, "23", "", "multipleOf", "",
  572. "{ \"multipleOf\": {"
  573. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  574. " \"expected\": 10, \"actual\": 23"
  575. "}}");
  576. INVALIDATE(s, "-23", "", "multipleOf", "",
  577. "{ \"multipleOf\": {"
  578. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  579. " \"expected\": 10, \"actual\": -23"
  580. "}}");
  581. }
  582. TEST(SchemaValidator, Integer_MultipleOf64Boundary) {
  583. Document sd;
  584. sd.Parse("{\"type\":\"integer\",\"multipleOf\":18446744073709551615}");
  585. SchemaDocument s(sd);
  586. VALIDATE(s, "0", true);
  587. VALIDATE(s, "18446744073709551615", true);
  588. INVALIDATE(s, "18446744073709551614", "", "multipleOf", "",
  589. "{ \"multipleOf\": {"
  590. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  591. " \"expected\": 18446744073709551615, \"actual\": 18446744073709551614"
  592. "}}");
  593. }
  594. TEST(SchemaValidator, Number_Range) {
  595. Document sd;
  596. sd.Parse("{\"type\":\"number\",\"minimum\":0,\"maximum\":100,\"exclusiveMaximum\":true}");
  597. SchemaDocument s(sd);
  598. INVALIDATE(s, "-1", "", "minimum", "",
  599. "{ \"minimum\": {"
  600. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  601. " \"expected\": 0, \"actual\": -1"
  602. "}}");
  603. VALIDATE(s, "0", true);
  604. VALIDATE(s, "0.1", true);
  605. VALIDATE(s, "10", true);
  606. VALIDATE(s, "99", true);
  607. VALIDATE(s, "99.9", true);
  608. INVALIDATE(s, "100", "", "maximum", "",
  609. "{ \"maximum\": {"
  610. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  611. " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100"
  612. "}}");
  613. INVALIDATE(s, "100.0", "", "maximum", "",
  614. "{ \"maximum\": {"
  615. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  616. " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100.0"
  617. "}}");
  618. INVALIDATE(s, "101.5", "", "maximum", "",
  619. "{ \"maximum\": {"
  620. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  621. " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 101.5"
  622. "}}");
  623. }
  624. TEST(SchemaValidator, Number_RangeInt) {
  625. Document sd;
  626. sd.Parse("{\"type\":\"number\",\"minimum\":-100,\"maximum\":-1,\"exclusiveMaximum\":true}");
  627. SchemaDocument s(sd);
  628. INVALIDATE(s, "-101", "", "minimum", "",
  629. "{ \"minimum\": {"
  630. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  631. " \"expected\": -100, \"actual\": -101"
  632. "}}");
  633. INVALIDATE(s, "-100.1", "", "minimum", "",
  634. "{ \"minimum\": {"
  635. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  636. " \"expected\": -100, \"actual\": -100.1"
  637. "}}");
  638. VALIDATE(s, "-100", true);
  639. VALIDATE(s, "-2", true);
  640. INVALIDATE(s, "-1", "", "maximum", "",
  641. "{ \"maximum\": {"
  642. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  643. " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": -1"
  644. "}}");
  645. INVALIDATE(s, "-0.9", "", "maximum", "",
  646. "{ \"maximum\": {"
  647. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  648. " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": -0.9"
  649. "}}");
  650. INVALIDATE(s, "0", "", "maximum", "",
  651. "{ \"maximum\": {"
  652. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  653. " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 0"
  654. "}}");
  655. INVALIDATE(s, "2147483647", "", "maximum", "",
  656. "{ \"maximum\": {"
  657. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  658. " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 2147483647"
  659. "}}"); // int max
  660. INVALIDATE(s, "2147483648", "", "maximum", "",
  661. "{ \"maximum\": {"
  662. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  663. " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 2147483648"
  664. "}}"); // unsigned first
  665. INVALIDATE(s, "4294967295", "", "maximum", "",
  666. "{ \"maximum\": {"
  667. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  668. " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 4294967295"
  669. "}}"); // unsigned max
  670. INVALIDATE(s, "9223372036854775808", "", "maximum", "",
  671. "{ \"maximum\": {"
  672. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  673. " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 9223372036854775808"
  674. "}}");
  675. INVALIDATE(s, "18446744073709551614", "", "maximum", "",
  676. "{ \"maximum\": {"
  677. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  678. " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614"
  679. "}}");
  680. INVALIDATE(s, "18446744073709551615", "", "maximum", "",
  681. "{ \"maximum\": {"
  682. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  683. " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615"
  684. "}}");
  685. }
  686. TEST(SchemaValidator, Number_RangeDouble) {
  687. Document sd;
  688. sd.Parse("{\"type\":\"number\",\"minimum\":0.1,\"maximum\":100.1,\"exclusiveMaximum\":true}");
  689. SchemaDocument s(sd);
  690. INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
  691. "{ \"minimum\": {"
  692. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  693. " \"expected\": 0.1, \"actual\": -9223372036854775808"
  694. "}}");
  695. INVALIDATE(s, "-2147483648", "", "minimum", "",
  696. "{ \"minimum\": {"
  697. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  698. " \"expected\": 0.1, \"actual\": -2147483648"
  699. "}}"); // int min
  700. INVALIDATE(s, "-1", "", "minimum", "",
  701. "{ \"minimum\": {"
  702. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  703. " \"expected\": 0.1, \"actual\": -1"
  704. "}}");
  705. VALIDATE(s, "0.1", true);
  706. VALIDATE(s, "10", true);
  707. VALIDATE(s, "99", true);
  708. VALIDATE(s, "100", true);
  709. INVALIDATE(s, "101", "", "maximum", "",
  710. "{ \"maximum\": {"
  711. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  712. " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 101"
  713. "}}");
  714. INVALIDATE(s, "101.5", "", "maximum", "",
  715. "{ \"maximum\": {"
  716. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  717. " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 101.5"
  718. "}}");
  719. INVALIDATE(s, "18446744073709551614", "", "maximum", "",
  720. "{ \"maximum\": {"
  721. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  722. " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614"
  723. "}}");
  724. INVALIDATE(s, "18446744073709551615", "", "maximum", "",
  725. "{ \"maximum\": {"
  726. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  727. " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615"
  728. "}}");
  729. INVALIDATE(s, "2147483647", "", "maximum", "",
  730. "{ \"maximum\": {"
  731. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  732. " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 2147483647"
  733. "}}"); // int max
  734. INVALIDATE(s, "2147483648", "", "maximum", "",
  735. "{ \"maximum\": {"
  736. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  737. " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 2147483648"
  738. "}}"); // unsigned first
  739. INVALIDATE(s, "4294967295", "", "maximum", "",
  740. "{ \"maximum\": {"
  741. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  742. " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 4294967295"
  743. "}}"); // unsigned max
  744. INVALIDATE(s, "9223372036854775808", "", "maximum", "",
  745. "{ \"maximum\": {"
  746. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  747. " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 9223372036854775808"
  748. "}}");
  749. INVALIDATE(s, "18446744073709551614", "", "maximum", "",
  750. "{ \"maximum\": {"
  751. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  752. " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614"
  753. "}}");
  754. INVALIDATE(s, "18446744073709551615", "", "maximum", "",
  755. "{ \"maximum\": {"
  756. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  757. " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615"
  758. "}}");
  759. }
  760. TEST(SchemaValidator, Number_RangeDoubleU64Boundary) {
  761. Document sd;
  762. sd.Parse("{\"type\":\"number\",\"minimum\":9223372036854775808.0,\"maximum\":18446744073709550000.0}");
  763. SchemaDocument s(sd);
  764. INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
  765. "{ \"minimum\": {"
  766. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  767. " \"expected\": 9223372036854775808.0, \"actual\": -9223372036854775808"
  768. "}}");
  769. INVALIDATE(s, "-2147483648", "", "minimum", "",
  770. "{ \"minimum\": {"
  771. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  772. " \"expected\": 9223372036854775808.0, \"actual\": -2147483648"
  773. "}}"); // int min
  774. INVALIDATE(s, "0", "", "minimum", "",
  775. "{ \"minimum\": {"
  776. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  777. " \"expected\": 9223372036854775808.0, \"actual\": 0"
  778. "}}");
  779. INVALIDATE(s, "2147483647", "", "minimum", "",
  780. "{ \"minimum\": {"
  781. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  782. " \"expected\": 9223372036854775808.0, \"actual\": 2147483647"
  783. "}}"); // int max
  784. INVALIDATE(s, "2147483648", "", "minimum", "",
  785. "{ \"minimum\": {"
  786. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  787. " \"expected\": 9223372036854775808.0, \"actual\": 2147483648"
  788. "}}"); // unsigned first
  789. INVALIDATE(s, "4294967295", "", "minimum", "",
  790. "{ \"minimum\": {"
  791. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  792. " \"expected\": 9223372036854775808.0, \"actual\": 4294967295"
  793. "}}"); // unsigned max
  794. VALIDATE(s, "9223372036854775808", true);
  795. VALIDATE(s, "18446744073709540000", true);
  796. INVALIDATE(s, "18446744073709551615", "", "maximum", "",
  797. "{ \"maximum\": {"
  798. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  799. " \"expected\": 18446744073709550000.0, \"actual\": 18446744073709551615"
  800. "}}");
  801. }
  802. TEST(SchemaValidator, Number_MultipleOf) {
  803. Document sd;
  804. sd.Parse("{\"type\":\"number\",\"multipleOf\":10.0}");
  805. SchemaDocument s(sd);
  806. VALIDATE(s, "0", true);
  807. VALIDATE(s, "10", true);
  808. VALIDATE(s, "-10", true);
  809. VALIDATE(s, "20", true);
  810. INVALIDATE(s, "23", "", "multipleOf", "",
  811. "{ \"multipleOf\": {"
  812. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  813. " \"expected\": 10.0, \"actual\": 23"
  814. "}}");
  815. INVALIDATE(s, "-2147483648", "", "multipleOf", "",
  816. "{ \"multipleOf\": {"
  817. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  818. " \"expected\": 10.0, \"actual\": -2147483648"
  819. "}}"); // int min
  820. VALIDATE(s, "-2147483640", true);
  821. INVALIDATE(s, "2147483647", "", "multipleOf", "",
  822. "{ \"multipleOf\": {"
  823. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  824. " \"expected\": 10.0, \"actual\": 2147483647"
  825. "}}"); // int max
  826. INVALIDATE(s, "2147483648", "", "multipleOf", "",
  827. "{ \"multipleOf\": {"
  828. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  829. " \"expected\": 10.0, \"actual\": 2147483648"
  830. "}}"); // unsigned first
  831. VALIDATE(s, "2147483650", true);
  832. INVALIDATE(s, "4294967295", "", "multipleOf", "",
  833. "{ \"multipleOf\": {"
  834. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  835. " \"expected\": 10.0, \"actual\": 4294967295"
  836. "}}"); // unsigned max
  837. VALIDATE(s, "4294967300", true);
  838. }
  839. TEST(SchemaValidator, Number_MultipleOfOne) {
  840. Document sd;
  841. sd.Parse("{\"type\":\"number\",\"multipleOf\":1}");
  842. SchemaDocument s(sd);
  843. VALIDATE(s, "42", true);
  844. VALIDATE(s, "42.0", true);
  845. INVALIDATE(s, "3.1415926", "", "multipleOf", "",
  846. "{ \"multipleOf\": {"
  847. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  848. " \"expected\": 1, \"actual\": 3.1415926"
  849. "}}");
  850. }
  851. TEST(SchemaValidator, Object) {
  852. Document sd;
  853. sd.Parse("{\"type\":\"object\"}");
  854. SchemaDocument s(sd);
  855. VALIDATE(s, "{\"key\":\"value\",\"another_key\":\"another_value\"}", true);
  856. VALIDATE(s, "{\"Sun\":1.9891e30,\"Jupiter\":1.8986e27,\"Saturn\":5.6846e26,\"Neptune\":10.243e25,\"Uranus\":8.6810e25,\"Earth\":5.9736e24,\"Venus\":4.8685e24,\"Mars\":6.4185e23,\"Mercury\":3.3022e23,\"Moon\":7.349e22,\"Pluto\":1.25e22}", true);
  857. INVALIDATE(s, "[\"An\", \"array\", \"not\", \"an\", \"object\"]", "", "type", "",
  858. "{ \"type\": {"
  859. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  860. " \"expected\": [\"object\"], \"actual\": \"array\""
  861. "}}");
  862. INVALIDATE(s, "\"Not an object\"", "", "type", "",
  863. "{ \"type\": {"
  864. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  865. " \"expected\": [\"object\"], \"actual\": \"string\""
  866. "}}");
  867. }
  868. TEST(SchemaValidator, Object_Properties) {
  869. Document sd;
  870. sd.Parse(
  871. "{"
  872. " \"type\": \"object\","
  873. " \"properties\" : {"
  874. " \"number\": { \"type\": \"number\" },"
  875. " \"street_name\" : { \"type\": \"string\" },"
  876. " \"street_type\" : { \"type\": \"string\", \"enum\" : [\"Street\", \"Avenue\", \"Boulevard\"] }"
  877. " }"
  878. "}");
  879. SchemaDocument s(sd);
  880. VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
  881. INVALIDATE(s, "{ \"number\": \"1600\", \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", "/properties/number", "type", "/number",
  882. "{ \"type\": {"
  883. " \"instanceRef\": \"#/number\", \"schemaRef\": \"#/properties/number\","
  884. " \"expected\": [\"number\"], \"actual\": \"string\""
  885. "}}");
  886. INVALIDATE(s, "{ \"number\": \"One\", \"street_name\": \"Microsoft\", \"street_type\": \"Way\" }",
  887. "/properties/number", "type", "/number",
  888. "{ \"type\": {"
  889. " \"instanceRef\": \"#/number\", \"schemaRef\": \"#/properties/number\","
  890. " \"expected\": [\"number\"], \"actual\": \"string\""
  891. "}}"); // fail fast
  892. VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\" }", true);
  893. VALIDATE(s, "{}", true);
  894. VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", true);
  895. }
  896. TEST(SchemaValidator, Object_AdditionalPropertiesBoolean) {
  897. Document sd;
  898. sd.Parse(
  899. "{"
  900. " \"type\": \"object\","
  901. " \"properties\" : {"
  902. " \"number\": { \"type\": \"number\" },"
  903. " \"street_name\" : { \"type\": \"string\" },"
  904. " \"street_type\" : { \"type\": \"string\","
  905. " \"enum\" : [\"Street\", \"Avenue\", \"Boulevard\"]"
  906. " }"
  907. " },"
  908. " \"additionalProperties\": false"
  909. "}");
  910. SchemaDocument s(sd);
  911. VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
  912. INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", "", "additionalProperties", "/direction",
  913. "{ \"additionalProperties\": {"
  914. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  915. " \"disallowed\": \"direction\""
  916. "}}");
  917. }
  918. TEST(SchemaValidator, Object_AdditionalPropertiesObject) {
  919. Document sd;
  920. sd.Parse(
  921. "{"
  922. " \"type\": \"object\","
  923. " \"properties\" : {"
  924. " \"number\": { \"type\": \"number\" },"
  925. " \"street_name\" : { \"type\": \"string\" },"
  926. " \"street_type\" : { \"type\": \"string\","
  927. " \"enum\" : [\"Street\", \"Avenue\", \"Boulevard\"]"
  928. " }"
  929. " },"
  930. " \"additionalProperties\": { \"type\": \"string\" }"
  931. "}");
  932. SchemaDocument s(sd);
  933. VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
  934. VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", true);
  935. INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"office_number\": 201 }", "/additionalProperties", "type", "/office_number",
  936. "{ \"type\": {"
  937. " \"instanceRef\": \"#/office_number\", \"schemaRef\": \"#/additionalProperties\","
  938. " \"expected\": [\"string\"], \"actual\": \"integer\""
  939. "}}");
  940. }
  941. TEST(SchemaValidator, Object_Required) {
  942. Document sd;
  943. sd.Parse(
  944. "{"
  945. " \"type\": \"object\","
  946. " \"properties\" : {"
  947. " \"name\": { \"type\": \"string\" },"
  948. " \"email\" : { \"type\": \"string\" },"
  949. " \"address\" : { \"type\": \"string\" },"
  950. " \"telephone\" : { \"type\": \"string\" }"
  951. " },"
  952. " \"required\":[\"name\", \"email\"]"
  953. "}");
  954. SchemaDocument s(sd);
  955. VALIDATE(s, "{ \"name\": \"William Shakespeare\", \"email\" : \"bill@stratford-upon-avon.co.uk\" }", true);
  956. VALIDATE(s, "{ \"name\": \"William Shakespeare\", \"email\" : \"bill@stratford-upon-avon.co.uk\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\", \"authorship\" : \"in question\"}", true);
  957. INVALIDATE(s, "{ \"name\": \"William Shakespeare\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\" }", "", "required", "",
  958. "{ \"required\": {"
  959. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  960. " \"missing\": [\"email\"]"
  961. "}}");
  962. INVALIDATE(s, "{}", "", "required", "",
  963. "{ \"required\": {"
  964. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  965. " \"missing\": [\"name\", \"email\"]"
  966. "}}");
  967. }
  968. TEST(SchemaValidator, Object_Required_PassWithDefault) {
  969. Document sd;
  970. sd.Parse(
  971. "{"
  972. " \"type\": \"object\","
  973. " \"properties\" : {"
  974. " \"name\": { \"type\": \"string\", \"default\": \"William Shakespeare\" },"
  975. " \"email\" : { \"type\": \"string\", \"default\": \"\" },"
  976. " \"address\" : { \"type\": \"string\" },"
  977. " \"telephone\" : { \"type\": \"string\" }"
  978. " },"
  979. " \"required\":[\"name\", \"email\"]"
  980. "}");
  981. SchemaDocument s(sd);
  982. VALIDATE(s, "{ \"email\" : \"bill@stratford-upon-avon.co.uk\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\", \"authorship\" : \"in question\"}", true);
  983. INVALIDATE(s, "{ \"name\": \"William Shakespeare\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\" }", "", "required", "",
  984. "{ \"required\": {"
  985. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  986. " \"missing\": [\"email\"]"
  987. "}}");
  988. INVALIDATE(s, "{}", "", "required", "",
  989. "{ \"required\": {"
  990. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  991. " \"missing\": [\"email\"]"
  992. "}}");
  993. }
  994. TEST(SchemaValidator, Object_PropertiesRange) {
  995. Document sd;
  996. sd.Parse("{\"type\":\"object\", \"minProperties\":2, \"maxProperties\":3}");
  997. SchemaDocument s(sd);
  998. INVALIDATE(s, "{}", "", "minProperties", "",
  999. "{ \"minProperties\": {"
  1000. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1001. " \"expected\": 2, \"actual\": 0"
  1002. "}}");
  1003. INVALIDATE(s, "{\"a\":0}", "", "minProperties", "",
  1004. "{ \"minProperties\": {"
  1005. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1006. " \"expected\": 2, \"actual\": 1"
  1007. "}}");
  1008. VALIDATE(s, "{\"a\":0,\"b\":1}", true);
  1009. VALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2}", true);
  1010. INVALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2,\"d\":3}", "", "maxProperties", "",
  1011. "{ \"maxProperties\": {"
  1012. " \"instanceRef\": \"#\", \"schemaRef\": \"#\", "
  1013. " \"expected\": 3, \"actual\": 4"
  1014. "}}");
  1015. }
  1016. TEST(SchemaValidator, Object_PropertyDependencies) {
  1017. Document sd;
  1018. sd.Parse(
  1019. "{"
  1020. " \"type\": \"object\","
  1021. " \"properties\": {"
  1022. " \"name\": { \"type\": \"string\" },"
  1023. " \"credit_card\": { \"type\": \"number\" },"
  1024. " \"cvv_code\": { \"type\": \"number\" },"
  1025. " \"billing_address\": { \"type\": \"string\" }"
  1026. " },"
  1027. " \"required\": [\"name\"],"
  1028. " \"dependencies\": {"
  1029. " \"credit_card\": [\"cvv_code\", \"billing_address\"]"
  1030. " }"
  1031. "}");
  1032. SchemaDocument s(sd);
  1033. VALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555, \"cvv_code\": 777, "
  1034. "\"billing_address\": \"555 Debtor's Lane\" }", true);
  1035. INVALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555 }", "", "dependencies", "",
  1036. "{ \"dependencies\": {"
  1037. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1038. " \"errors\": {\"credit_card\": [\"cvv_code\", \"billing_address\"]}"
  1039. "}}");
  1040. VALIDATE(s, "{ \"name\": \"John Doe\"}", true);
  1041. VALIDATE(s, "{ \"name\": \"John Doe\", \"cvv_code\": 777, \"billing_address\": \"555 Debtor's Lane\" }", true);
  1042. }
  1043. TEST(SchemaValidator, Object_SchemaDependencies) {
  1044. Document sd;
  1045. sd.Parse(
  1046. "{"
  1047. " \"type\": \"object\","
  1048. " \"properties\" : {"
  1049. " \"name\": { \"type\": \"string\" },"
  1050. " \"credit_card\" : { \"type\": \"number\" }"
  1051. " },"
  1052. " \"required\" : [\"name\"],"
  1053. " \"dependencies\" : {"
  1054. " \"credit_card\": {"
  1055. " \"properties\": {"
  1056. " \"billing_address\": { \"type\": \"string\" }"
  1057. " },"
  1058. " \"required\" : [\"billing_address\"]"
  1059. " }"
  1060. " }"
  1061. "}");
  1062. SchemaDocument s(sd);
  1063. VALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555,\"billing_address\" : \"555 Debtor's Lane\"}", true);
  1064. INVALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555 }", "", "dependencies", "",
  1065. "{ \"dependencies\": {"
  1066. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1067. " \"errors\": {"
  1068. " \"credit_card\": {"
  1069. " \"required\": {"
  1070. " \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/credit_card\","
  1071. " \"missing\": [\"billing_address\"]"
  1072. " } } }"
  1073. "}}");
  1074. VALIDATE(s, "{\"name\": \"John Doe\", \"billing_address\" : \"555 Debtor's Lane\"}", true);
  1075. }
  1076. #if RAPIDJSON_SCHEMA_HAS_REGEX
  1077. TEST(SchemaValidator, Object_PatternProperties) {
  1078. Document sd;
  1079. sd.Parse(
  1080. "{"
  1081. " \"type\": \"object\","
  1082. " \"patternProperties\": {"
  1083. " \"^S_\": { \"type\": \"string\" },"
  1084. " \"^I_\": { \"type\": \"integer\" }"
  1085. " }"
  1086. "}");
  1087. SchemaDocument s(sd);
  1088. VALIDATE(s, "{ \"S_25\": \"This is a string\" }", true);
  1089. VALIDATE(s, "{ \"I_0\": 42 }", true);
  1090. INVALIDATE(s, "{ \"S_0\": 42 }", "", "patternProperties", "/S_0",
  1091. "{ \"type\": {"
  1092. " \"instanceRef\": \"#/S_0\", \"schemaRef\": \"#/patternProperties/%5ES_\","
  1093. " \"expected\": [\"string\"], \"actual\": \"integer\""
  1094. "}}");
  1095. INVALIDATE(s, "{ \"I_42\": \"This is a string\" }", "", "patternProperties", "/I_42",
  1096. "{ \"type\": {"
  1097. " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/patternProperties/%5EI_\","
  1098. " \"expected\": [\"integer\"], \"actual\": \"string\""
  1099. "}}");
  1100. VALIDATE(s, "{ \"keyword\": \"value\" }", true);
  1101. }
  1102. TEST(SchemaValidator, Object_PattternProperties_ErrorConflict) {
  1103. Document sd;
  1104. sd.Parse(
  1105. "{"
  1106. " \"type\": \"object\","
  1107. " \"patternProperties\": {"
  1108. " \"^I_\": { \"multipleOf\": 5 },"
  1109. " \"30$\": { \"multipleOf\": 6 }"
  1110. " }"
  1111. "}");
  1112. SchemaDocument s(sd);
  1113. VALIDATE(s, "{ \"I_30\": 30 }", true);
  1114. INVALIDATE(s, "{ \"I_30\": 7 }", "", "patternProperties", "/I_30",
  1115. "{ \"multipleOf\": ["
  1116. " {"
  1117. " \"instanceRef\": \"#/I_30\", \"schemaRef\": \"#/patternProperties/%5EI_\","
  1118. " \"expected\": 5, \"actual\": 7"
  1119. " }, {"
  1120. " \"instanceRef\": \"#/I_30\", \"schemaRef\": \"#/patternProperties/30%24\","
  1121. " \"expected\": 6, \"actual\": 7"
  1122. " }"
  1123. "]}");
  1124. }
  1125. TEST(SchemaValidator, Object_Properties_PatternProperties) {
  1126. Document sd;
  1127. sd.Parse(
  1128. "{"
  1129. " \"type\": \"object\","
  1130. " \"properties\": {"
  1131. " \"I_42\": { \"type\": \"integer\", \"minimum\": 73 }"
  1132. " },"
  1133. " \"patternProperties\": {"
  1134. " \"^I_\": { \"type\": \"integer\", \"multipleOf\": 6 }"
  1135. " }"
  1136. "}");
  1137. SchemaDocument s(sd);
  1138. VALIDATE(s, "{ \"I_6\": 6 }", true);
  1139. VALIDATE(s, "{ \"I_42\": 78 }", true);
  1140. INVALIDATE(s, "{ \"I_42\": 42 }", "", "patternProperties", "/I_42",
  1141. "{ \"minimum\": {"
  1142. " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/properties/I_42\","
  1143. " \"expected\": 73, \"actual\": 42"
  1144. "}}");
  1145. INVALIDATE(s, "{ \"I_42\": 7 }", "", "patternProperties", "/I_42",
  1146. "{ \"minimum\": {"
  1147. " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/properties/I_42\","
  1148. " \"expected\": 73, \"actual\": 7"
  1149. " },"
  1150. " \"multipleOf\": {"
  1151. " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/patternProperties/%5EI_\","
  1152. " \"expected\": 6, \"actual\": 7"
  1153. " }"
  1154. "}");
  1155. }
  1156. TEST(SchemaValidator, Object_PatternProperties_AdditionalProperties) {
  1157. Document sd;
  1158. sd.Parse(
  1159. "{"
  1160. " \"type\": \"object\","
  1161. " \"properties\": {"
  1162. " \"builtin\": { \"type\": \"number\" }"
  1163. " },"
  1164. " \"patternProperties\": {"
  1165. " \"^S_\": { \"type\": \"string\" },"
  1166. " \"^I_\": { \"type\": \"integer\" }"
  1167. " },"
  1168. " \"additionalProperties\": { \"type\": \"string\" }"
  1169. "}");
  1170. SchemaDocument s(sd);
  1171. VALIDATE(s, "{ \"builtin\": 42 }", true);
  1172. VALIDATE(s, "{ \"keyword\": \"value\" }", true);
  1173. INVALIDATE(s, "{ \"keyword\": 42 }", "/additionalProperties", "type", "/keyword",
  1174. "{ \"type\": {"
  1175. " \"instanceRef\": \"#/keyword\", \"schemaRef\": \"#/additionalProperties\","
  1176. " \"expected\": [\"string\"], \"actual\": \"integer\""
  1177. "}}");
  1178. }
  1179. #endif
  1180. TEST(SchemaValidator, Array) {
  1181. Document sd;
  1182. sd.Parse("{\"type\":\"array\"}");
  1183. SchemaDocument s(sd);
  1184. VALIDATE(s, "[1, 2, 3, 4, 5]", true);
  1185. VALIDATE(s, "[3, \"different\", { \"types\" : \"of values\" }]", true);
  1186. INVALIDATE(s, "{\"Not\": \"an array\"}", "", "type", "",
  1187. "{ \"type\": {"
  1188. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1189. " \"expected\": [\"array\"], \"actual\": \"object\""
  1190. "}}");
  1191. }
  1192. TEST(SchemaValidator, Array_ItemsList) {
  1193. Document sd;
  1194. sd.Parse(
  1195. "{"
  1196. " \"type\": \"array\","
  1197. " \"items\" : {"
  1198. " \"type\": \"number\""
  1199. " }"
  1200. "}");
  1201. SchemaDocument s(sd);
  1202. VALIDATE(s, "[1, 2, 3, 4, 5]", true);
  1203. INVALIDATE(s, "[1, 2, \"3\", 4, 5]", "/items", "type", "/2",
  1204. "{ \"type\": {"
  1205. " \"instanceRef\": \"#/2\", \"schemaRef\": \"#/items\","
  1206. " \"expected\": [\"number\"], \"actual\": \"string\""
  1207. "}}");
  1208. VALIDATE(s, "[]", true);
  1209. }
  1210. TEST(SchemaValidator, Array_ItemsTuple) {
  1211. Document sd;
  1212. sd.Parse(
  1213. "{"
  1214. " \"type\": \"array\","
  1215. " \"items\": ["
  1216. " {"
  1217. " \"type\": \"number\""
  1218. " },"
  1219. " {"
  1220. " \"type\": \"string\""
  1221. " },"
  1222. " {"
  1223. " \"type\": \"string\","
  1224. " \"enum\": [\"Street\", \"Avenue\", \"Boulevard\"]"
  1225. " },"
  1226. " {"
  1227. " \"type\": \"string\","
  1228. " \"enum\": [\"NW\", \"NE\", \"SW\", \"SE\"]"
  1229. " }"
  1230. " ]"
  1231. "}");
  1232. SchemaDocument s(sd);
  1233. VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true);
  1234. INVALIDATE(s, "[24, \"Sussex\", \"Drive\"]", "/items/2", "enum", "/2",
  1235. "{ \"enum\": { \"instanceRef\": \"#/2\", \"schemaRef\": \"#/items/2\" }}");
  1236. INVALIDATE(s, "[\"Palais de l'Elysee\"]", "/items/0", "type", "/0",
  1237. "{ \"type\": {"
  1238. " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items/0\","
  1239. " \"expected\": [\"number\"], \"actual\": \"string\""
  1240. "}}");
  1241. INVALIDATE(s, "[\"Twenty-four\", \"Sussex\", \"Drive\"]", "/items/0", "type", "/0",
  1242. "{ \"type\": {"
  1243. " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items/0\","
  1244. " \"expected\": [\"number\"], \"actual\": \"string\""
  1245. "}}"); // fail fast
  1246. VALIDATE(s, "[10, \"Downing\", \"Street\"]", true);
  1247. VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", true);
  1248. }
  1249. TEST(SchemaValidator, Array_AdditionalItmes) {
  1250. Document sd;
  1251. sd.Parse(
  1252. "{"
  1253. " \"type\": \"array\","
  1254. " \"items\": ["
  1255. " {"
  1256. " \"type\": \"number\""
  1257. " },"
  1258. " {"
  1259. " \"type\": \"string\""
  1260. " },"
  1261. " {"
  1262. " \"type\": \"string\","
  1263. " \"enum\": [\"Street\", \"Avenue\", \"Boulevard\"]"
  1264. " },"
  1265. " {"
  1266. " \"type\": \"string\","
  1267. " \"enum\": [\"NW\", \"NE\", \"SW\", \"SE\"]"
  1268. " }"
  1269. " ],"
  1270. " \"additionalItems\": false"
  1271. "}");
  1272. SchemaDocument s(sd);
  1273. VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true);
  1274. VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\"]", true);
  1275. INVALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", "", "items", "/4",
  1276. "{ \"additionalItems\": {"
  1277. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1278. " \"disallowed\": 4"
  1279. "}}");
  1280. }
  1281. TEST(SchemaValidator, Array_ItemsRange) {
  1282. Document sd;
  1283. sd.Parse("{\"type\": \"array\",\"minItems\": 2,\"maxItems\" : 3}");
  1284. SchemaDocument s(sd);
  1285. INVALIDATE(s, "[]", "", "minItems", "",
  1286. "{ \"minItems\": {"
  1287. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1288. " \"expected\": 2, \"actual\": 0"
  1289. "}}");
  1290. INVALIDATE(s, "[1]", "", "minItems", "",
  1291. "{ \"minItems\": {"
  1292. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1293. " \"expected\": 2, \"actual\": 1"
  1294. "}}");
  1295. VALIDATE(s, "[1, 2]", true);
  1296. VALIDATE(s, "[1, 2, 3]", true);
  1297. INVALIDATE(s, "[1, 2, 3, 4]", "", "maxItems", "",
  1298. "{ \"maxItems\": {"
  1299. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1300. " \"expected\": 3, \"actual\": 4"
  1301. "}}");
  1302. }
  1303. TEST(SchemaValidator, Array_UniqueItems) {
  1304. Document sd;
  1305. sd.Parse("{\"type\": \"array\", \"uniqueItems\": true}");
  1306. SchemaDocument s(sd);
  1307. VALIDATE(s, "[1, 2, 3, 4, 5]", true);
  1308. INVALIDATE(s, "[1, 2, 3, 3, 4]", "", "uniqueItems", "/3",
  1309. "{ \"uniqueItems\": {"
  1310. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1311. " \"duplicates\": [2, 3]"
  1312. "}}");
  1313. INVALIDATE(s, "[1, 2, 3, 3, 3]", "", "uniqueItems", "/3",
  1314. "{ \"uniqueItems\": {"
  1315. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1316. " \"duplicates\": [2, 3]"
  1317. "}}"); // fail fast
  1318. VALIDATE(s, "[]", true);
  1319. }
  1320. TEST(SchemaValidator, Boolean) {
  1321. Document sd;
  1322. sd.Parse("{\"type\":\"boolean\"}");
  1323. SchemaDocument s(sd);
  1324. VALIDATE(s, "true", true);
  1325. VALIDATE(s, "false", true);
  1326. INVALIDATE(s, "\"true\"", "", "type", "",
  1327. "{ \"type\": {"
  1328. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1329. " \"expected\": [\"boolean\"], \"actual\": \"string\""
  1330. "}}");
  1331. INVALIDATE(s, "0", "", "type", "",
  1332. "{ \"type\": {"
  1333. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1334. " \"expected\": [\"boolean\"], \"actual\": \"integer\""
  1335. "}}");
  1336. }
  1337. TEST(SchemaValidator, Null) {
  1338. Document sd;
  1339. sd.Parse("{\"type\":\"null\"}");
  1340. SchemaDocument s(sd);
  1341. VALIDATE(s, "null", true);
  1342. INVALIDATE(s, "false", "", "type", "",
  1343. "{ \"type\": {"
  1344. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1345. " \"expected\": [\"null\"], \"actual\": \"boolean\""
  1346. "}}");
  1347. INVALIDATE(s, "0", "", "type", "",
  1348. "{ \"type\": {"
  1349. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1350. " \"expected\": [\"null\"], \"actual\": \"integer\""
  1351. "}}");
  1352. INVALIDATE(s, "\"\"", "", "type", "",
  1353. "{ \"type\": {"
  1354. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1355. " \"expected\": [\"null\"], \"actual\": \"string\""
  1356. "}}");
  1357. }
  1358. // Additional tests
  1359. TEST(SchemaValidator, ObjectInArray) {
  1360. Document sd;
  1361. sd.Parse("{\"type\":\"array\", \"items\": { \"type\":\"string\" }}");
  1362. SchemaDocument s(sd);
  1363. VALIDATE(s, "[\"a\"]", true);
  1364. INVALIDATE(s, "[1]", "/items", "type", "/0",
  1365. "{ \"type\": {"
  1366. " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items\","
  1367. " \"expected\": [\"string\"], \"actual\": \"integer\""
  1368. "}}");
  1369. INVALIDATE(s, "[{}]", "/items", "type", "/0",
  1370. "{ \"type\": {"
  1371. " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items\","
  1372. " \"expected\": [\"string\"], \"actual\": \"object\""
  1373. "}}");
  1374. }
  1375. TEST(SchemaValidator, MultiTypeInObject) {
  1376. Document sd;
  1377. sd.Parse(
  1378. "{"
  1379. " \"type\":\"object\","
  1380. " \"properties\": {"
  1381. " \"tel\" : {"
  1382. " \"type\":[\"integer\", \"string\"]"
  1383. " }"
  1384. " }"
  1385. "}");
  1386. SchemaDocument s(sd);
  1387. VALIDATE(s, "{ \"tel\": 999 }", true);
  1388. VALIDATE(s, "{ \"tel\": \"123-456\" }", true);
  1389. INVALIDATE(s, "{ \"tel\": true }", "/properties/tel", "type", "/tel",
  1390. "{ \"type\": {"
  1391. " \"instanceRef\": \"#/tel\", \"schemaRef\": \"#/properties/tel\","
  1392. " \"expected\": [\"string\", \"integer\"], \"actual\": \"boolean\""
  1393. "}}");
  1394. }
  1395. TEST(SchemaValidator, MultiTypeWithObject) {
  1396. Document sd;
  1397. sd.Parse(
  1398. "{"
  1399. " \"type\": [\"object\",\"string\"],"
  1400. " \"properties\": {"
  1401. " \"tel\" : {"
  1402. " \"type\": \"integer\""
  1403. " }"
  1404. " }"
  1405. "}");
  1406. SchemaDocument s(sd);
  1407. VALIDATE(s, "\"Hello\"", true);
  1408. VALIDATE(s, "{ \"tel\": 999 }", true);
  1409. INVALIDATE(s, "{ \"tel\": \"fail\" }", "/properties/tel", "type", "/tel",
  1410. "{ \"type\": {"
  1411. " \"instanceRef\": \"#/tel\", \"schemaRef\": \"#/properties/tel\","
  1412. " \"expected\": [\"integer\"], \"actual\": \"string\""
  1413. "}}");
  1414. }
  1415. TEST(SchemaValidator, AllOf_Nested) {
  1416. Document sd;
  1417. sd.Parse(
  1418. "{"
  1419. " \"allOf\": ["
  1420. " { \"type\": \"string\", \"minLength\": 2 },"
  1421. " { \"type\": \"string\", \"maxLength\": 5 },"
  1422. " { \"allOf\": [ { \"enum\" : [\"ok\", \"okay\", \"OK\", \"o\"] }, { \"enum\" : [\"ok\", \"OK\", \"o\"]} ] }"
  1423. " ]"
  1424. "}");
  1425. SchemaDocument s(sd);
  1426. VALIDATE(s, "\"ok\"", true);
  1427. VALIDATE(s, "\"OK\"", true);
  1428. INVALIDATE(s, "\"okay\"", "", "allOf", "",
  1429. "{ \"enum\": {"
  1430. " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\""
  1431. "}}");
  1432. INVALIDATE(s, "\"o\"", "", "allOf", "",
  1433. "{ \"minLength\": {"
  1434. " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\","
  1435. " \"expected\": 2, \"actual\": \"o\""
  1436. "}}");
  1437. INVALIDATE(s, "\"n\"", "", "allOf", "",
  1438. "{ \"minLength\": {"
  1439. " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\","
  1440. " \"expected\": 2, \"actual\": \"n\""
  1441. " },"
  1442. " \"enum\": ["
  1443. " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"},"
  1444. " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}"
  1445. " ]"
  1446. "}")
  1447. INVALIDATE(s, "\"too long\"", "", "allOf", "",
  1448. "{ \"maxLength\": {"
  1449. " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\","
  1450. " \"expected\": 5, \"actual\": \"too long\""
  1451. " },"
  1452. " \"enum\": ["
  1453. " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"},"
  1454. " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}"
  1455. " ]"
  1456. "}");
  1457. INVALIDATE(s, "123", "", "allOf", "",
  1458. "{ \"type\": ["
  1459. " { \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\","
  1460. " \"expected\": [\"string\"], \"actual\": \"integer\""
  1461. " },"
  1462. " { \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\","
  1463. " \"expected\": [\"string\"], \"actual\": \"integer\""
  1464. " }"
  1465. " ],"
  1466. " \"enum\": ["
  1467. " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"},"
  1468. " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}"
  1469. " ]"
  1470. "}");
  1471. }
  1472. TEST(SchemaValidator, EscapedPointer) {
  1473. Document sd;
  1474. sd.Parse(
  1475. "{"
  1476. " \"type\": \"object\","
  1477. " \"properties\": {"
  1478. " \"~/\": { \"type\": \"number\" }"
  1479. " }"
  1480. "}");
  1481. SchemaDocument s(sd);
  1482. INVALIDATE(s, "{\"~/\":true}", "/properties/~0~1", "type", "/~0~1",
  1483. "{ \"type\": {"
  1484. " \"instanceRef\": \"#/~0~1\", \"schemaRef\": \"#/properties/~0~1\","
  1485. " \"expected\": [\"number\"], \"actual\": \"boolean\""
  1486. "}}");
  1487. }
  1488. template <typename Allocator>
  1489. static char* ReadFile(const char* filename, Allocator& allocator) {
  1490. const char *paths[] = {
  1491. "",
  1492. "bin/",
  1493. "../bin/",
  1494. "../../bin/",
  1495. "../../../bin/"
  1496. };
  1497. char buffer[1024];
  1498. FILE *fp = 0;
  1499. for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
  1500. sprintf(buffer, "%s%s", paths[i], filename);
  1501. fp = fopen(buffer, "rb");
  1502. if (fp)
  1503. break;
  1504. }
  1505. if (!fp)
  1506. return 0;
  1507. fseek(fp, 0, SEEK_END);
  1508. size_t length = static_cast<size_t>(ftell(fp));
  1509. fseek(fp, 0, SEEK_SET);
  1510. char* json = reinterpret_cast<char*>(allocator.Malloc(length + 1));
  1511. size_t readLength = fread(json, 1, length, fp);
  1512. json[readLength] = '\0';
  1513. fclose(fp);
  1514. return json;
  1515. }
  1516. TEST(SchemaValidator, ValidateMetaSchema) {
  1517. CrtAllocator allocator;
  1518. char* json = ReadFile("draft-04/schema", allocator);
  1519. Document d;
  1520. d.Parse(json);
  1521. ASSERT_FALSE(d.HasParseError());
  1522. SchemaDocument sd(d);
  1523. SchemaValidator validator(sd);
  1524. if (!d.Accept(validator)) {
  1525. StringBuffer sb;
  1526. validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
  1527. printf("Invalid schema: %s\n", sb.GetString());
  1528. printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
  1529. sb.Clear();
  1530. validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
  1531. printf("Invalid document: %s\n", sb.GetString());
  1532. sb.Clear();
  1533. Writer<StringBuffer> w(sb);
  1534. validator.GetError().Accept(w);
  1535. printf("Validation error: %s\n", sb.GetString());
  1536. ADD_FAILURE();
  1537. }
  1538. CrtAllocator::Free(json);
  1539. }
  1540. TEST(SchemaValidator, ValidateMetaSchema_UTF16) {
  1541. typedef GenericDocument<UTF16<> > D;
  1542. typedef GenericSchemaDocument<D::ValueType> SD;
  1543. typedef GenericSchemaValidator<SD> SV;
  1544. CrtAllocator allocator;
  1545. char* json = ReadFile("draft-04/schema", allocator);
  1546. D d;
  1547. StringStream ss(json);
  1548. d.ParseStream<0, UTF8<> >(ss);
  1549. ASSERT_FALSE(d.HasParseError());
  1550. SD sd(d);
  1551. SV validator(sd);
  1552. if (!d.Accept(validator)) {
  1553. GenericStringBuffer<UTF16<> > sb;
  1554. validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
  1555. wprintf(L"Invalid schema: %ls\n", sb.GetString());
  1556. wprintf(L"Invalid keyword: %ls\n", validator.GetInvalidSchemaKeyword());
  1557. sb.Clear();
  1558. validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
  1559. wprintf(L"Invalid document: %ls\n", sb.GetString());
  1560. sb.Clear();
  1561. Writer<GenericStringBuffer<UTF16<> >, UTF16<> > w(sb);
  1562. validator.GetError().Accept(w);
  1563. printf("Validation error: %ls\n", sb.GetString());
  1564. ADD_FAILURE();
  1565. }
  1566. CrtAllocator::Free(json);
  1567. }
  1568. template <typename SchemaDocumentType = SchemaDocument>
  1569. class RemoteSchemaDocumentProvider : public IGenericRemoteSchemaDocumentProvider<SchemaDocumentType> {
  1570. public:
  1571. RemoteSchemaDocumentProvider() :
  1572. documentAllocator_(documentBuffer_, sizeof(documentBuffer_)),
  1573. schemaAllocator_(schemaBuffer_, sizeof(schemaBuffer_))
  1574. {
  1575. const char* filenames[kCount] = {
  1576. "jsonschema/remotes/integer.json",
  1577. "jsonschema/remotes/subSchemas.json",
  1578. "jsonschema/remotes/folder/folderInteger.json",
  1579. "draft-04/schema"
  1580. };
  1581. const char* uris[kCount] = {
  1582. "http://localhost:1234/integer.json",
  1583. "http://localhost:1234/subSchemas.json",
  1584. "http://localhost:1234/folder/folderInteger.json",
  1585. "http://json-schema.org/draft-04/schema"
  1586. };
  1587. for (size_t i = 0; i < kCount; i++) {
  1588. sd_[i] = 0;
  1589. char jsonBuffer[8192];
  1590. MemoryPoolAllocator<> jsonAllocator(jsonBuffer, sizeof(jsonBuffer));
  1591. char* json = ReadFile(filenames[i], jsonAllocator);
  1592. if (!json) {
  1593. printf("json remote file %s not found", filenames[i]);
  1594. ADD_FAILURE();
  1595. }
  1596. else {
  1597. char stackBuffer[4096];
  1598. MemoryPoolAllocator<> stackAllocator(stackBuffer, sizeof(stackBuffer));
  1599. DocumentType d(&documentAllocator_, 1024, &stackAllocator);
  1600. d.Parse(json);
  1601. sd_[i] = new SchemaDocumentType(d, uris[i], static_cast<SizeType>(strlen(uris[i])), 0, &schemaAllocator_);
  1602. MemoryPoolAllocator<>::Free(json);
  1603. }
  1604. };
  1605. }
  1606. ~RemoteSchemaDocumentProvider() {
  1607. for (size_t i = 0; i < kCount; i++)
  1608. delete sd_[i];
  1609. }
  1610. virtual const SchemaDocumentType* GetRemoteDocument(const char* uri, SizeType length) {
  1611. for (size_t i = 0; i < kCount; i++)
  1612. if (typename SchemaDocumentType::URIType(uri, length) == sd_[i]->GetURI())
  1613. return sd_[i];
  1614. return 0;
  1615. }
  1616. private:
  1617. typedef GenericDocument<typename SchemaDocumentType::EncodingType, MemoryPoolAllocator<>, MemoryPoolAllocator<> > DocumentType;
  1618. RemoteSchemaDocumentProvider(const RemoteSchemaDocumentProvider&);
  1619. RemoteSchemaDocumentProvider& operator=(const RemoteSchemaDocumentProvider&);
  1620. static const size_t kCount = 4;
  1621. SchemaDocumentType* sd_[kCount];
  1622. typename DocumentType::AllocatorType documentAllocator_;
  1623. typename SchemaDocumentType::AllocatorType schemaAllocator_;
  1624. char documentBuffer_[16384];
  1625. char schemaBuffer_[128u * 1024];
  1626. };
  1627. TEST(SchemaValidator, TestSuite) {
  1628. const char* filenames[] = {
  1629. "additionalItems.json",
  1630. "additionalProperties.json",
  1631. "allOf.json",
  1632. "anyOf.json",
  1633. "default.json",
  1634. "definitions.json",
  1635. "dependencies.json",
  1636. "enum.json",
  1637. "items.json",
  1638. "maximum.json",
  1639. "maxItems.json",
  1640. "maxLength.json",
  1641. "maxProperties.json",
  1642. "minimum.json",
  1643. "minItems.json",
  1644. "minLength.json",
  1645. "minProperties.json",
  1646. "multipleOf.json",
  1647. "not.json",
  1648. "oneOf.json",
  1649. "pattern.json",
  1650. "patternProperties.json",
  1651. "properties.json",
  1652. "ref.json",
  1653. "refRemote.json",
  1654. "required.json",
  1655. "type.json",
  1656. "uniqueItems.json"
  1657. };
  1658. const char* onlyRunDescription = 0;
  1659. //const char* onlyRunDescription = "a string is a string";
  1660. unsigned testCount = 0;
  1661. unsigned passCount = 0;
  1662. typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
  1663. RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
  1664. char jsonBuffer[65536];
  1665. char documentBuffer[65536];
  1666. char documentStackBuffer[65536];
  1667. char schemaBuffer[65536];
  1668. char validatorBuffer[65536];
  1669. MemoryPoolAllocator<> jsonAllocator(jsonBuffer, sizeof(jsonBuffer));
  1670. MemoryPoolAllocator<> documentAllocator(documentBuffer, sizeof(documentBuffer));
  1671. MemoryPoolAllocator<> documentStackAllocator(documentStackBuffer, sizeof(documentStackBuffer));
  1672. MemoryPoolAllocator<> schemaAllocator(schemaBuffer, sizeof(schemaBuffer));
  1673. MemoryPoolAllocator<> validatorAllocator(validatorBuffer, sizeof(validatorBuffer));
  1674. for (size_t i = 0; i < sizeof(filenames) / sizeof(filenames[0]); i++) {
  1675. char filename[FILENAME_MAX];
  1676. sprintf(filename, "jsonschema/tests/draft4/%s", filenames[i]);
  1677. char* json = ReadFile(filename, jsonAllocator);
  1678. if (!json) {
  1679. printf("json test suite file %s not found", filename);
  1680. ADD_FAILURE();
  1681. }
  1682. else {
  1683. GenericDocument<UTF8<>, MemoryPoolAllocator<>, MemoryPoolAllocator<> > d(&documentAllocator, 1024, &documentStackAllocator);
  1684. d.Parse(json);
  1685. if (d.HasParseError()) {
  1686. printf("json test suite file %s has parse error", filename);
  1687. ADD_FAILURE();
  1688. }
  1689. else {
  1690. for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) {
  1691. {
  1692. SchemaDocumentType schema((*schemaItr)["schema"], filenames[i], static_cast<SizeType>(strlen(filenames[i])), &provider, &schemaAllocator);
  1693. GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > validator(schema, &validatorAllocator);
  1694. const char* description1 = (*schemaItr)["description"].GetString();
  1695. const Value& tests = (*schemaItr)["tests"];
  1696. for (Value::ConstValueIterator testItr = tests.Begin(); testItr != tests.End(); ++testItr) {
  1697. const char* description2 = (*testItr)["description"].GetString();
  1698. if (!onlyRunDescription || strcmp(description2, onlyRunDescription) == 0) {
  1699. const Value& data = (*testItr)["data"];
  1700. bool expected = (*testItr)["valid"].GetBool();
  1701. testCount++;
  1702. validator.Reset();
  1703. bool actual = data.Accept(validator);
  1704. if (expected != actual)
  1705. printf("Fail: %30s \"%s\" \"%s\"\n", filename, description1, description2);
  1706. else
  1707. passCount++;
  1708. }
  1709. }
  1710. //printf("%zu %zu %zu\n", documentAllocator.Size(), schemaAllocator.Size(), validatorAllocator.Size());
  1711. }
  1712. schemaAllocator.Clear();
  1713. validatorAllocator.Clear();
  1714. }
  1715. }
  1716. }
  1717. documentAllocator.Clear();
  1718. MemoryPoolAllocator<>::Free(json);
  1719. jsonAllocator.Clear();
  1720. }
  1721. printf("%d / %d passed (%2d%%)\n", passCount, testCount, passCount * 100 / testCount);
  1722. // if (passCount != testCount)
  1723. // ADD_FAILURE();
  1724. }
  1725. TEST(SchemaValidatingReader, Simple) {
  1726. Document sd;
  1727. sd.Parse("{ \"type\": \"string\", \"enum\" : [\"red\", \"amber\", \"green\"] }");
  1728. SchemaDocument s(sd);
  1729. Document d;
  1730. StringStream ss("\"red\"");
  1731. SchemaValidatingReader<kParseDefaultFlags, StringStream, UTF8<> > reader(ss, s);
  1732. d.Populate(reader);
  1733. EXPECT_TRUE(reader.GetParseResult());
  1734. EXPECT_TRUE(reader.IsValid());
  1735. EXPECT_TRUE(d.IsString());
  1736. EXPECT_STREQ("red", d.GetString());
  1737. }
  1738. TEST(SchemaValidatingReader, Invalid) {
  1739. Document sd;
  1740. sd.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
  1741. SchemaDocument s(sd);
  1742. Document d;
  1743. StringStream ss("\"ABCD\"");
  1744. SchemaValidatingReader<kParseDefaultFlags, StringStream, UTF8<> > reader(ss, s);
  1745. d.Populate(reader);
  1746. EXPECT_FALSE(reader.GetParseResult());
  1747. EXPECT_FALSE(reader.IsValid());
  1748. EXPECT_EQ(kParseErrorTermination, reader.GetParseResult().Code());
  1749. EXPECT_STREQ("maxLength", reader.GetInvalidSchemaKeyword());
  1750. EXPECT_TRUE(reader.GetInvalidSchemaPointer() == SchemaDocument::PointerType(""));
  1751. EXPECT_TRUE(reader.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
  1752. EXPECT_TRUE(d.IsNull());
  1753. Document e;
  1754. e.Parse(
  1755. "{ \"maxLength\": {"
  1756. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1757. " \"expected\": 3, \"actual\": \"ABCD\""
  1758. "}}");
  1759. if (e != reader.GetError()) {
  1760. ADD_FAILURE();
  1761. }
  1762. }
  1763. TEST(SchemaValidatingWriter, Simple) {
  1764. Document sd;
  1765. sd.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
  1766. SchemaDocument s(sd);
  1767. Document d;
  1768. StringBuffer sb;
  1769. Writer<StringBuffer> writer(sb);
  1770. GenericSchemaValidator<SchemaDocument, Writer<StringBuffer> > validator(s, writer);
  1771. d.Parse("\"red\"");
  1772. EXPECT_TRUE(d.Accept(validator));
  1773. EXPECT_TRUE(validator.IsValid());
  1774. EXPECT_STREQ("\"red\"", sb.GetString());
  1775. sb.Clear();
  1776. validator.Reset();
  1777. d.Parse("\"ABCD\"");
  1778. EXPECT_FALSE(d.Accept(validator));
  1779. EXPECT_FALSE(validator.IsValid());
  1780. EXPECT_TRUE(validator.GetInvalidSchemaPointer() == SchemaDocument::PointerType(""));
  1781. EXPECT_TRUE(validator.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
  1782. Document e;
  1783. e.Parse(
  1784. "{ \"maxLength\": {"
  1785. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1786. " \"expected\": 3, \"actual\": \"ABCD\""
  1787. "}}");
  1788. EXPECT_EQ(e, validator.GetError());
  1789. }
  1790. TEST(Schema, Issue848) {
  1791. rapidjson::Document d;
  1792. rapidjson::SchemaDocument s(d);
  1793. rapidjson::GenericSchemaValidator<rapidjson::SchemaDocument, rapidjson::Document> v(s);
  1794. }
  1795. #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
  1796. static SchemaDocument ReturnSchemaDocument() {
  1797. Document sd;
  1798. sd.Parse("{ \"type\": [\"number\", \"string\"] }");
  1799. SchemaDocument s(sd);
  1800. return s;
  1801. }
  1802. TEST(Schema, Issue552) {
  1803. SchemaDocument s = ReturnSchemaDocument();
  1804. VALIDATE(s, "42", true);
  1805. VALIDATE(s, "\"Life, the universe, and everything\"", true);
  1806. INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "",
  1807. "{ \"type\": {"
  1808. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1809. " \"expected\": [\"string\", \"number\"], \"actual\": \"array\""
  1810. "}}");
  1811. }
  1812. #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
  1813. TEST(SchemaValidator, Issue608) {
  1814. Document sd;
  1815. sd.Parse("{\"required\": [\"a\", \"b\"] }");
  1816. SchemaDocument s(sd);
  1817. VALIDATE(s, "{\"a\" : null, \"b\": null}", true);
  1818. INVALIDATE(s, "{\"a\" : null, \"a\" : null}", "", "required", "",
  1819. "{ \"required\": {"
  1820. " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
  1821. " \"missing\": [\"b\"]"
  1822. "}}");
  1823. }
  1824. // Fail to resolve $ref in allOf causes crash in SchemaValidator::StartObject()
  1825. TEST(SchemaValidator, Issue728_AllOfRef) {
  1826. Document sd;
  1827. sd.Parse("{\"allOf\": [{\"$ref\": \"#/abc\"}]}");
  1828. SchemaDocument s(sd);
  1829. VALIDATE(s, "{\"key1\": \"abc\", \"key2\": \"def\"}", true);
  1830. }
  1831. TEST(SchemaValidator, Issue825) {
  1832. Document sd;
  1833. sd.Parse("{\"type\": \"object\", \"additionalProperties\": false, \"patternProperties\": {\"^i\": { \"type\": \"string\" } } }");
  1834. SchemaDocument s(sd);
  1835. VALIDATE(s, "{ \"item\": \"hello\" }", true);
  1836. }
  1837. TEST(SchemaValidator, Issue1017_allOfHandler) {
  1838. Document sd;
  1839. sd.Parse("{\"allOf\": [{\"type\": \"object\",\"properties\": {\"cyanArray2\": {\"type\": \"array\",\"items\": { \"type\": \"string\" }}}},{\"type\": \"object\",\"properties\": {\"blackArray\": {\"type\": \"array\",\"items\": { \"type\": \"string\" }}},\"required\": [ \"blackArray\" ]}]}");
  1840. SchemaDocument s(sd);
  1841. StringBuffer sb;
  1842. Writer<StringBuffer> writer(sb);
  1843. GenericSchemaValidator<SchemaDocument, Writer<StringBuffer> > validator(s, writer);
  1844. EXPECT_TRUE(validator.StartObject());
  1845. EXPECT_TRUE(validator.Key("cyanArray2", 10, false));
  1846. EXPECT_TRUE(validator.StartArray());
  1847. EXPECT_TRUE(validator.EndArray(0));
  1848. EXPECT_TRUE(validator.Key("blackArray", 10, false));
  1849. EXPECT_TRUE(validator.StartArray());
  1850. EXPECT_TRUE(validator.EndArray(0));
  1851. EXPECT_TRUE(validator.EndObject(0));
  1852. EXPECT_TRUE(validator.IsValid());
  1853. EXPECT_STREQ("{\"cyanArray2\":[],\"blackArray\":[]}", sb.GetString());
  1854. }
  1855. TEST(SchemaValidator, Ref_remote) {
  1856. typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
  1857. RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
  1858. Document sd;
  1859. sd.Parse("{\"$ref\": \"http://localhost:1234/subSchemas.json#/integer\"}");
  1860. SchemaDocumentType s(sd, 0, 0, &provider);
  1861. typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
  1862. typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
  1863. INVALIDATE_(s, "null", "/integer", "type", "",
  1864. "{ \"type\": {"
  1865. " \"instanceRef\": \"#\","
  1866. " \"schemaRef\": \"http://localhost:1234/subSchemas.json#/integer\","
  1867. " \"expected\": [\"integer\"], \"actual\": \"null\""
  1868. "}}",
  1869. SchemaValidatorType, PointerType);
  1870. }
  1871. TEST(SchemaValidator, Ref_remote_issue1210) {
  1872. class SchemaDocumentProvider : public IRemoteSchemaDocumentProvider {
  1873. SchemaDocument** collection;
  1874. SchemaDocumentProvider(const SchemaDocumentProvider&);
  1875. SchemaDocumentProvider& operator=(const SchemaDocumentProvider&);
  1876. public:
  1877. SchemaDocumentProvider(SchemaDocument** collection) : collection(collection) { }
  1878. virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) {
  1879. int i = 0;
  1880. while (collection[i] && SchemaDocument::URIType(uri, length) != collection[i]->GetURI()) ++i;
  1881. return collection[i];
  1882. }
  1883. };
  1884. SchemaDocument* collection[] = { 0, 0, 0 };
  1885. SchemaDocumentProvider provider(collection);
  1886. Document x, y, z;
  1887. x.Parse("{\"properties\":{\"country\":{\"$ref\":\"y.json#/definitions/country_remote\"}},\"type\":\"object\"}");
  1888. y.Parse("{\"definitions\":{\"country_remote\":{\"$ref\":\"z.json#/definitions/country_list\"}}}");
  1889. z.Parse("{\"definitions\":{\"country_list\":{\"enum\":[\"US\"]}}}");
  1890. SchemaDocument sz(z, "z.json", 6, &provider);
  1891. collection[0] = &sz;
  1892. SchemaDocument sy(y, "y.json", 6, &provider);
  1893. collection[1] = &sy;
  1894. SchemaDocument sx(x, "x.json", 6, &provider);
  1895. VALIDATE(sx, "{\"country\":\"UK\"}", false);
  1896. VALIDATE(sx, "{\"country\":\"US\"}", true);
  1897. }
  1898. #if defined(_MSC_VER) || defined(__clang__)
  1899. RAPIDJSON_DIAG_POP
  1900. #endif