schematest.cpp 75 KB

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