schematest.cpp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157
  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("1.5", "1.5", true);
  48. TEST_HASHER("1", "1.0", true);
  49. TEST_HASHER("1", "-1", false);
  50. TEST_HASHER("0.0", "-0.0", false);
  51. TEST_HASHER("1", "true", false);
  52. TEST_HASHER("0", "false", false);
  53. TEST_HASHER("0", "null", false);
  54. TEST_HASHER("\"\"", "\"\"", true);
  55. TEST_HASHER("\"\"", "\"\\u0000\"", false);
  56. TEST_HASHER("\"Hello\"", "\"Hello\"", true);
  57. TEST_HASHER("\"Hello\"", "\"World\"", false);
  58. TEST_HASHER("\"Hello\"", "null", false);
  59. TEST_HASHER("\"Hello\\u0000\"", "\"Hello\"", false);
  60. TEST_HASHER("\"\"", "null", false);
  61. TEST_HASHER("\"\"", "true", false);
  62. TEST_HASHER("\"\"", "false", false);
  63. TEST_HASHER("[]", "[ ]", true);
  64. TEST_HASHER("[1, true, false]", "[1, true, false]", true);
  65. TEST_HASHER("[1, true, false]", "[1, true]", false);
  66. TEST_HASHER("[1, 2]", "[2, 1]", false);
  67. TEST_HASHER("[[1], 2]", "[[1, 2]]", false);
  68. TEST_HASHER("[1, 2]", "[1, [2]]", false);
  69. TEST_HASHER("[]", "null", false);
  70. TEST_HASHER("[]", "true", false);
  71. TEST_HASHER("[]", "false", false);
  72. TEST_HASHER("[]", "0", false);
  73. TEST_HASHER("[]", "0.0", false);
  74. TEST_HASHER("[]", "\"\"", false);
  75. TEST_HASHER("{}", "{ }", true);
  76. TEST_HASHER("{\"a\":1}", "{\"a\":1}", true);
  77. TEST_HASHER("{\"a\":1}", "{\"b\":1}", false);
  78. TEST_HASHER("{\"a\":1}", "{\"a\":2}", false);
  79. TEST_HASHER("{\"a\":1, \"b\":2}", "{\"b\":2, \"a\":1}", true); // Member order insensitive
  80. TEST_HASHER("{}", "null", false);
  81. TEST_HASHER("{}", "false", false);
  82. TEST_HASHER("{}", "true", false);
  83. TEST_HASHER("{}", "0", false);
  84. TEST_HASHER("{}", "0.0", false);
  85. TEST_HASHER("{}", "\"\"", false);
  86. }
  87. // Test cases following http://spacetelescope.github.io/understanding-json-schema
  88. #define VALIDATE(schema, json, expected) \
  89. {\
  90. SchemaValidator validator(schema);\
  91. Document d;\
  92. /*printf("\n%s\n", json);*/\
  93. d.Parse(json);\
  94. EXPECT_FALSE(d.HasParseError());\
  95. EXPECT_TRUE(expected == d.Accept(validator));\
  96. EXPECT_TRUE(expected == validator.IsValid());\
  97. if (expected && !validator.IsValid()) {\
  98. StringBuffer sb;\
  99. validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);\
  100. printf("Invalid schema: %s\n", sb.GetString());\
  101. printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());\
  102. sb.Clear();\
  103. validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);\
  104. printf("Invalid document: %s\n", sb.GetString());\
  105. }\
  106. }
  107. #define INVALIDATE(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer) \
  108. {\
  109. SchemaValidator validator(schema);\
  110. Document d;\
  111. /*printf("\n%s\n", json);*/\
  112. d.Parse(json);\
  113. EXPECT_FALSE(d.HasParseError());\
  114. EXPECT_FALSE(d.Accept(validator));\
  115. EXPECT_FALSE(validator.IsValid());\
  116. if (validator.GetInvalidSchemaPointer() != Pointer(invalidSchemaPointer)) {\
  117. StringBuffer sb;\
  118. validator.GetInvalidSchemaPointer().Stringify(sb);\
  119. printf("GetInvalidSchemaPointer() Expected: %s Actual: %s\n", invalidSchemaPointer, sb.GetString());\
  120. ADD_FAILURE();\
  121. }\
  122. ASSERT_TRUE(validator.GetInvalidSchemaKeyword() != 0);\
  123. if (strcmp(validator.GetInvalidSchemaKeyword(), invalidSchemaKeyword) != 0) {\
  124. printf("GetInvalidSchemaKeyword() Expected: %s Actual %s\n", invalidSchemaKeyword, validator.GetInvalidSchemaKeyword());\
  125. ADD_FAILURE();\
  126. }\
  127. if (validator.GetInvalidDocumentPointer() != Pointer(invalidDocumentPointer)) {\
  128. StringBuffer sb;\
  129. validator.GetInvalidDocumentPointer().Stringify(sb);\
  130. printf("GetInvalidDocumentPointer() Expected: %s Actual: %s\n", invalidDocumentPointer, sb.GetString());\
  131. ADD_FAILURE();\
  132. }\
  133. }
  134. TEST(SchemaValidator, Typeless) {
  135. Document sd;
  136. sd.Parse("{}");
  137. SchemaDocument s(sd);
  138. VALIDATE(s, "42", true);
  139. VALIDATE(s, "\"I'm a string\"", true);
  140. VALIDATE(s, "{ \"an\": [ \"arbitrarily\", \"nested\" ], \"data\": \"structure\" }", true);
  141. }
  142. TEST(SchemaValidator, MultiType) {
  143. Document sd;
  144. sd.Parse("{ \"type\": [\"number\", \"string\"] }");
  145. SchemaDocument s(sd);
  146. VALIDATE(s, "42", true);
  147. VALIDATE(s, "\"Life, the universe, and everything\"", true);
  148. INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "");
  149. }
  150. TEST(SchemaValidator, Enum_Typed) {
  151. Document sd;
  152. sd.Parse("{ \"type\": \"string\", \"enum\" : [\"red\", \"amber\", \"green\"] }");
  153. SchemaDocument s(sd);
  154. VALIDATE(s, "\"red\"", true);
  155. INVALIDATE(s, "\"blue\"", "", "enum", "");
  156. }
  157. TEST(SchemaValidator, Enum_Typless) {
  158. Document sd;
  159. sd.Parse("{ \"enum\": [\"red\", \"amber\", \"green\", null, 42] }");
  160. SchemaDocument s(sd);
  161. VALIDATE(s, "\"red\"", true);
  162. VALIDATE(s, "null", true);
  163. VALIDATE(s, "42", true);
  164. INVALIDATE(s, "0", "", "enum", "");
  165. }
  166. TEST(SchemaValidator, Enum_InvalidType) {
  167. Document sd;
  168. sd.Parse("{ \"type\": \"string\", \"enum\": [\"red\", \"amber\", \"green\", null] }");
  169. SchemaDocument s(sd);
  170. VALIDATE(s, "\"red\"", true);
  171. INVALIDATE(s, "null", "", "type", "");
  172. }
  173. TEST(SchemaValidator, AllOf) {
  174. {
  175. Document sd;
  176. sd.Parse("{\"allOf\": [{ \"type\": \"string\" }, { \"type\": \"string\", \"maxLength\": 5 }]}");
  177. SchemaDocument s(sd);
  178. VALIDATE(s, "\"ok\"", true);
  179. INVALIDATE(s, "\"too long\"", "", "allOf", "");
  180. }
  181. {
  182. Document sd;
  183. sd.Parse("{\"allOf\": [{ \"type\": \"string\" }, { \"type\": \"number\" } ] }");
  184. SchemaDocument s(sd);
  185. VALIDATE(s, "\"No way\"", false);
  186. INVALIDATE(s, "-1", "", "allOf", "");
  187. }
  188. }
  189. TEST(SchemaValidator, AnyOf) {
  190. Document sd;
  191. sd.Parse("{\"anyOf\": [{ \"type\": \"string\" }, { \"type\": \"number\" } ] }");
  192. SchemaDocument s(sd);
  193. VALIDATE(s, "\"Yes\"", true);
  194. VALIDATE(s, "42", true);
  195. INVALIDATE(s, "{ \"Not a\": \"string or number\" }", "", "anyOf", "");
  196. }
  197. TEST(SchemaValidator, OneOf) {
  198. Document sd;
  199. sd.Parse("{\"oneOf\": [{ \"type\": \"number\", \"multipleOf\": 5 }, { \"type\": \"number\", \"multipleOf\": 3 } ] }");
  200. SchemaDocument s(sd);
  201. VALIDATE(s, "10", true);
  202. VALIDATE(s, "9", true);
  203. INVALIDATE(s, "2", "", "oneOf", "");
  204. INVALIDATE(s, "15", "", "oneOf", "");
  205. }
  206. TEST(SchemaValidator, Not) {
  207. Document sd;
  208. sd.Parse("{\"not\":{ \"type\": \"string\"}}");
  209. SchemaDocument s(sd);
  210. VALIDATE(s, "42", true);
  211. VALIDATE(s, "{ \"key\": \"value\" }", true);
  212. INVALIDATE(s, "\"I am a string\"", "", "not", "");
  213. }
  214. TEST(SchemaValidator, Ref) {
  215. Document sd;
  216. sd.Parse(
  217. "{"
  218. " \"$schema\": \"http://json-schema.org/draft-04/schema#\","
  219. ""
  220. " \"definitions\": {"
  221. " \"address\": {"
  222. " \"type\": \"object\","
  223. " \"properties\": {"
  224. " \"street_address\": { \"type\": \"string\" },"
  225. " \"city\": { \"type\": \"string\" },"
  226. " \"state\": { \"type\": \"string\" }"
  227. " },"
  228. " \"required\": [\"street_address\", \"city\", \"state\"]"
  229. " }"
  230. " },"
  231. " \"type\": \"object\","
  232. " \"properties\": {"
  233. " \"billing_address\": { \"$ref\": \"#/definitions/address\" },"
  234. " \"shipping_address\": { \"$ref\": \"#/definitions/address\" }"
  235. " }"
  236. "}");
  237. SchemaDocument s(sd);
  238. 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);
  239. }
  240. TEST(SchemaValidator, Ref_AllOf) {
  241. Document sd;
  242. sd.Parse(
  243. "{"
  244. " \"$schema\": \"http://json-schema.org/draft-04/schema#\","
  245. ""
  246. " \"definitions\": {"
  247. " \"address\": {"
  248. " \"type\": \"object\","
  249. " \"properties\": {"
  250. " \"street_address\": { \"type\": \"string\" },"
  251. " \"city\": { \"type\": \"string\" },"
  252. " \"state\": { \"type\": \"string\" }"
  253. " },"
  254. " \"required\": [\"street_address\", \"city\", \"state\"]"
  255. " }"
  256. " },"
  257. " \"type\": \"object\","
  258. " \"properties\": {"
  259. " \"billing_address\": { \"$ref\": \"#/definitions/address\" },"
  260. " \"shipping_address\": {"
  261. " \"allOf\": ["
  262. " { \"$ref\": \"#/definitions/address\" },"
  263. " { \"properties\":"
  264. " { \"type\": { \"enum\": [ \"residential\", \"business\" ] } },"
  265. " \"required\": [\"type\"]"
  266. " }"
  267. " ]"
  268. " }"
  269. " }"
  270. "}");
  271. SchemaDocument s(sd);
  272. INVALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\"} }", "/properties/shipping_address", "allOf", "/shipping_address");
  273. VALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\", \"type\": \"business\"} }", true);
  274. }
  275. TEST(SchemaValidator, String) {
  276. Document sd;
  277. sd.Parse("{\"type\":\"string\"}");
  278. SchemaDocument s(sd);
  279. VALIDATE(s, "\"I'm a string\"", true);
  280. INVALIDATE(s, "42", "", "type", "");
  281. }
  282. TEST(SchemaValidator, String_LengthRange) {
  283. Document sd;
  284. sd.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
  285. SchemaDocument s(sd);
  286. INVALIDATE(s, "\"A\"", "", "minLength", "");
  287. VALIDATE(s, "\"AB\"", true);
  288. VALIDATE(s, "\"ABC\"", true);
  289. INVALIDATE(s, "\"ABCD\"", "", "maxLength", "");
  290. }
  291. #if RAPIDJSON_SCHEMA_HAS_REGEX
  292. TEST(SchemaValidator, String_Pattern) {
  293. Document sd;
  294. sd.Parse("{\"type\":\"string\",\"pattern\":\"^(\\\\([0-9]{3}\\\\))?[0-9]{3}-[0-9]{4}$\"}");
  295. SchemaDocument s(sd);
  296. VALIDATE(s, "\"555-1212\"", true);
  297. VALIDATE(s, "\"(888)555-1212\"", true);
  298. INVALIDATE(s, "\"(888)555-1212 ext. 532\"", "", "pattern", "");
  299. INVALIDATE(s, "\"(800)FLOWERS\"", "", "pattern", "");
  300. }
  301. #endif
  302. TEST(SchemaValidator, Integer) {
  303. Document sd;
  304. sd.Parse("{\"type\":\"integer\"}");
  305. SchemaDocument s(sd);
  306. VALIDATE(s, "42", true);
  307. VALIDATE(s, "-1", true);
  308. INVALIDATE(s, "3.1415926", "", "type", "");
  309. INVALIDATE(s, "\"42\"", "", "type", "");
  310. }
  311. TEST(SchemaValidator, Integer_Range) {
  312. Document sd;
  313. sd.Parse("{\"type\":\"integer\",\"minimum\":0,\"maximum\":100,\"exclusiveMaximum\":true}");
  314. SchemaDocument s(sd);
  315. INVALIDATE(s, "-1", "", "minimum", "");
  316. VALIDATE(s, "0", true);
  317. VALIDATE(s, "10", true);
  318. VALIDATE(s, "99", true);
  319. INVALIDATE(s, "100", "", "maximum", "");
  320. INVALIDATE(s, "101", "", "maximum", "");
  321. }
  322. TEST(SchemaValidator, Integer_Range64Boundary) {
  323. Document sd;
  324. sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775807,\"maximum\":18446744073709551614}");
  325. SchemaDocument s(sd);
  326. INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
  327. VALIDATE(s, "-9223372036854775807", true);
  328. VALIDATE(s, "18446744073709551614", true);
  329. INVALIDATE(s, "18446744073709551615", "", "maximum", "");
  330. }
  331. TEST(SchemaValidator, Integer_Range64BoundaryExclusive) {
  332. Document sd;
  333. sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775808,\"maximum\":18446744073709551615,\"exclusiveMinimum\":true,\"exclusiveMaximum\":true}");
  334. SchemaDocument s(sd);
  335. INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
  336. VALIDATE(s, "-9223372036854775807", true);
  337. VALIDATE(s, "18446744073709551614", true);
  338. INVALIDATE(s, "18446744073709551615", "", "maximum", "");
  339. }
  340. TEST(SchemaValidator, Integer_MultipleOf) {
  341. Document sd;
  342. sd.Parse("{\"type\":\"integer\",\"multipleOf\":10}");
  343. SchemaDocument s(sd);
  344. VALIDATE(s, "0", true);
  345. VALIDATE(s, "10", true);
  346. VALIDATE(s, "-10", true);
  347. VALIDATE(s, "20", true);
  348. INVALIDATE(s, "23", "", "multipleOf", "");
  349. INVALIDATE(s, "-23", "", "multipleOf", "");
  350. }
  351. TEST(SchemaValidator, Integer_MultipleOf64Boundary) {
  352. Document sd;
  353. sd.Parse("{\"type\":\"integer\",\"multipleOf\":18446744073709551615}");
  354. SchemaDocument s(sd);
  355. VALIDATE(s, "0", true);
  356. VALIDATE(s, "18446744073709551615", true);
  357. INVALIDATE(s, "18446744073709551614", "", "multipleOf", "");
  358. }
  359. TEST(SchemaValidator, Number_Range) {
  360. Document sd;
  361. sd.Parse("{\"type\":\"number\",\"minimum\":0,\"maximum\":100,\"exclusiveMaximum\":true}");
  362. SchemaDocument s(sd);
  363. INVALIDATE(s, "-1", "", "minimum", "");
  364. VALIDATE(s, "0", true);
  365. VALIDATE(s, "10", true);
  366. VALIDATE(s, "99", true);
  367. INVALIDATE(s, "100", "", "maximum", "");
  368. INVALIDATE(s, "101", "", "maximum", "");
  369. }
  370. TEST(SchemaValidator, Number_MultipleOf) {
  371. Document sd;
  372. sd.Parse("{\"type\":\"number\",\"multipleOf\":10.0}");
  373. SchemaDocument s(sd);
  374. VALIDATE(s, "0", true);
  375. VALIDATE(s, "10", true);
  376. VALIDATE(s, "-10", true);
  377. VALIDATE(s, "20", true);
  378. INVALIDATE(s, "23", "", "multipleOf", "");
  379. }
  380. TEST(SchemaValidator, Number_MultipleOfOne) {
  381. Document sd;
  382. sd.Parse("{\"type\":\"number\",\"multipleOf\":1}");
  383. SchemaDocument s(sd);
  384. VALIDATE(s, "42", true);
  385. VALIDATE(s, "42.0", true);
  386. INVALIDATE(s, "3.1415926", "", "multipleOf", "");
  387. }
  388. TEST(SchemaValidator, Object) {
  389. Document sd;
  390. sd.Parse("{\"type\":\"object\"}");
  391. SchemaDocument s(sd);
  392. VALIDATE(s, "{\"key\":\"value\",\"another_key\":\"another_value\"}", true);
  393. 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);
  394. INVALIDATE(s, "[\"An\", \"array\", \"not\", \"an\", \"object\"]", "", "type", "");
  395. INVALIDATE(s, "\"Not an object\"", "", "type", "");
  396. }
  397. TEST(SchemaValidator, Object_Properties) {
  398. Document sd;
  399. sd.Parse(
  400. "{"
  401. " \"type\": \"object\","
  402. " \"properties\" : {"
  403. " \"number\": { \"type\": \"number\" },"
  404. " \"street_name\" : { \"type\": \"string\" },"
  405. " \"street_type\" : { \"type\": \"string\", \"enum\" : [\"Street\", \"Avenue\", \"Boulevard\"] }"
  406. " }"
  407. "}");
  408. SchemaDocument s(sd);
  409. VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
  410. INVALIDATE(s, "{ \"number\": \"1600\", \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", "/properties/number", "type", "/number");
  411. VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\" }", true);
  412. VALIDATE(s, "{}", true);
  413. VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", true);
  414. }
  415. TEST(SchemaValidator, Object_AdditionalPropertiesBoolean) {
  416. Document sd;
  417. sd.Parse(
  418. "{"
  419. " \"type\": \"object\","
  420. " \"properties\" : {"
  421. " \"number\": { \"type\": \"number\" },"
  422. " \"street_name\" : { \"type\": \"string\" },"
  423. " \"street_type\" : { \"type\": \"string\","
  424. " \"enum\" : [\"Street\", \"Avenue\", \"Boulevard\"]"
  425. " }"
  426. " },"
  427. " \"additionalProperties\": false"
  428. "}");
  429. SchemaDocument s(sd);
  430. VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
  431. INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", "", "additionalProperties", "/direction");
  432. }
  433. TEST(SchemaValidator, Object_AdditionalPropertiesObject) {
  434. Document sd;
  435. sd.Parse(
  436. "{"
  437. " \"type\": \"object\","
  438. " \"properties\" : {"
  439. " \"number\": { \"type\": \"number\" },"
  440. " \"street_name\" : { \"type\": \"string\" },"
  441. " \"street_type\" : { \"type\": \"string\","
  442. " \"enum\" : [\"Street\", \"Avenue\", \"Boulevard\"]"
  443. " }"
  444. " },"
  445. " \"additionalProperties\": { \"type\": \"string\" }"
  446. "}");
  447. SchemaDocument s(sd);
  448. VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
  449. VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", true);
  450. INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"office_number\": 201 }", "/additionalProperties", "type", "/office_number");
  451. }
  452. TEST(SchemaValidator, Object_Required) {
  453. Document sd;
  454. sd.Parse(
  455. "{"
  456. " \"type\": \"object\","
  457. " \"properties\" : {"
  458. " \"name\": { \"type\": \"string\" },"
  459. " \"email\" : { \"type\": \"string\" },"
  460. " \"address\" : { \"type\": \"string\" },"
  461. " \"telephone\" : { \"type\": \"string\" }"
  462. " },"
  463. " \"required\":[\"name\", \"email\"]"
  464. "}");
  465. SchemaDocument s(sd);
  466. VALIDATE(s, "{ \"name\": \"William Shakespeare\", \"email\" : \"bill@stratford-upon-avon.co.uk\" }", true);
  467. VALIDATE(s, "{ \"name\": \"William Shakespeare\", \"email\" : \"bill@stratford-upon-avon.co.uk\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\", \"authorship\" : \"in question\"}", true);
  468. INVALIDATE(s, "{ \"name\": \"William Shakespeare\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\" }", "", "required", "");
  469. }
  470. TEST(SchemaValidator, Object_PropertiesRange) {
  471. Document sd;
  472. sd.Parse("{\"type\":\"object\", \"minProperties\":2, \"maxProperties\":3}");
  473. SchemaDocument s(sd);
  474. INVALIDATE(s, "{}", "", "minProperties", "");
  475. INVALIDATE(s, "{\"a\":0}", "", "minProperties", "");
  476. VALIDATE(s, "{\"a\":0,\"b\":1}", true);
  477. VALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2}", true);
  478. INVALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2,\"d\":3}", "", "maxProperties", "");
  479. }
  480. TEST(SchemaValidator, Object_PropertyDependencies) {
  481. Document sd;
  482. sd.Parse(
  483. "{"
  484. " \"type\": \"object\","
  485. " \"properties\": {"
  486. " \"name\": { \"type\": \"string\" },"
  487. " \"credit_card\": { \"type\": \"number\" },"
  488. " \"billing_address\": { \"type\": \"string\" }"
  489. " },"
  490. " \"required\": [\"name\"],"
  491. " \"dependencies\": {"
  492. " \"credit_card\": [\"billing_address\"]"
  493. " }"
  494. "}");
  495. SchemaDocument s(sd);
  496. VALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555, \"billing_address\": \"555 Debtor's Lane\" }", true);
  497. INVALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555 }", "", "dependencies", "");
  498. VALIDATE(s, "{ \"name\": \"John Doe\"}", true);
  499. VALIDATE(s, "{ \"name\": \"John Doe\", \"billing_address\": \"555 Debtor's Lane\" }", true);
  500. }
  501. TEST(SchemaValidator, Object_SchemaDependencies) {
  502. Document sd;
  503. sd.Parse(
  504. "{"
  505. " \"type\": \"object\","
  506. " \"properties\" : {"
  507. " \"name\": { \"type\": \"string\" },"
  508. " \"credit_card\" : { \"type\": \"number\" }"
  509. " },"
  510. " \"required\" : [\"name\"],"
  511. " \"dependencies\" : {"
  512. " \"credit_card\": {"
  513. " \"properties\": {"
  514. " \"billing_address\": { \"type\": \"string\" }"
  515. " },"
  516. " \"required\" : [\"billing_address\"]"
  517. " }"
  518. " }"
  519. "}");
  520. SchemaDocument s(sd);
  521. VALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555,\"billing_address\" : \"555 Debtor's Lane\"}", true);
  522. INVALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555 }", "", "dependencies", "");
  523. VALIDATE(s, "{\"name\": \"John Doe\", \"billing_address\" : \"555 Debtor's Lane\"}", true);
  524. }
  525. #if RAPIDJSON_SCHEMA_HAS_REGEX
  526. TEST(SchemaValidator, Object_PatternProperties) {
  527. Document sd;
  528. sd.Parse(
  529. "{"
  530. " \"type\": \"object\","
  531. " \"patternProperties\": {"
  532. " \"^S_\": { \"type\": \"string\" },"
  533. " \"^I_\": { \"type\": \"integer\" }"
  534. " }"
  535. "}");
  536. SchemaDocument s(sd);
  537. VALIDATE(s, "{ \"S_25\": \"This is a string\" }", true);
  538. VALIDATE(s, "{ \"I_0\": 42 }", true);
  539. INVALIDATE(s, "{ \"S_0\": 42 }", "", "patternProperties", "/S_0");
  540. INVALIDATE(s, "{ \"I_42\": \"This is a string\" }", "", "patternProperties", "/I_42");
  541. VALIDATE(s, "{ \"keyword\": \"value\" }", true);
  542. }
  543. TEST(SchemaValidator, Object_PatternProperties_AdditionalProperties) {
  544. Document sd;
  545. sd.Parse(
  546. "{"
  547. " \"type\": \"object\","
  548. " \"properties\": {"
  549. " \"builtin\": { \"type\": \"number\" }"
  550. " },"
  551. " \"patternProperties\": {"
  552. " \"^S_\": { \"type\": \"string\" },"
  553. " \"^I_\": { \"type\": \"integer\" }"
  554. " },"
  555. " \"additionalProperties\": { \"type\": \"string\" }"
  556. "}");
  557. SchemaDocument s(sd);
  558. VALIDATE(s, "{ \"builtin\": 42 }", true);
  559. VALIDATE(s, "{ \"keyword\": \"value\" }", true);
  560. INVALIDATE(s, "{ \"keyword\": 42 }", "/additionalProperties", "type", "/keyword");
  561. }
  562. #endif
  563. TEST(SchemaValidator, Array) {
  564. Document sd;
  565. sd.Parse("{\"type\":\"array\"}");
  566. SchemaDocument s(sd);
  567. VALIDATE(s, "[1, 2, 3, 4, 5]", true);
  568. VALIDATE(s, "[3, \"different\", { \"types\" : \"of values\" }]", true);
  569. INVALIDATE(s, "{\"Not\": \"an array\"}", "", "type", "");
  570. }
  571. TEST(SchemaValidator, Array_ItemsList) {
  572. Document sd;
  573. sd.Parse(
  574. "{"
  575. " \"type\": \"array\","
  576. " \"items\" : {"
  577. " \"type\": \"number\""
  578. " }"
  579. "}");
  580. SchemaDocument s(sd);
  581. VALIDATE(s, "[1, 2, 3, 4, 5]", true);
  582. INVALIDATE(s, "[1, 2, \"3\", 4, 5]", "/items", "type", "/2");
  583. VALIDATE(s, "[]", true);
  584. }
  585. TEST(SchemaValidator, Array_ItemsTuple) {
  586. Document sd;
  587. sd.Parse(
  588. "{"
  589. " \"type\": \"array\","
  590. " \"items\": ["
  591. " {"
  592. " \"type\": \"number\""
  593. " },"
  594. " {"
  595. " \"type\": \"string\""
  596. " },"
  597. " {"
  598. " \"type\": \"string\","
  599. " \"enum\": [\"Street\", \"Avenue\", \"Boulevard\"]"
  600. " },"
  601. " {"
  602. " \"type\": \"string\","
  603. " \"enum\": [\"NW\", \"NE\", \"SW\", \"SE\"]"
  604. " }"
  605. " ]"
  606. "}");
  607. SchemaDocument s(sd);
  608. VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true);
  609. INVALIDATE(s, "[24, \"Sussex\", \"Drive\"]", "/items/2", "enum", "/2");
  610. INVALIDATE(s, "[\"Palais de l'Elysee\"]", "/items/0", "type", "/0");
  611. VALIDATE(s, "[10, \"Downing\", \"Street\"]", true);
  612. VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", true);
  613. }
  614. TEST(SchemaValidator, Array_AdditionalItmes) {
  615. Document sd;
  616. sd.Parse(
  617. "{"
  618. " \"type\": \"array\","
  619. " \"items\": ["
  620. " {"
  621. " \"type\": \"number\""
  622. " },"
  623. " {"
  624. " \"type\": \"string\""
  625. " },"
  626. " {"
  627. " \"type\": \"string\","
  628. " \"enum\": [\"Street\", \"Avenue\", \"Boulevard\"]"
  629. " },"
  630. " {"
  631. " \"type\": \"string\","
  632. " \"enum\": [\"NW\", \"NE\", \"SW\", \"SE\"]"
  633. " }"
  634. " ],"
  635. " \"additionalItems\": false"
  636. "}");
  637. SchemaDocument s(sd);
  638. VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true);
  639. VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\"]", true);
  640. INVALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", "", "items", "/4");
  641. }
  642. TEST(SchemaValidator, Array_ItemsRange) {
  643. Document sd;
  644. sd.Parse("{\"type\": \"array\",\"minItems\": 2,\"maxItems\" : 3}");
  645. SchemaDocument s(sd);
  646. INVALIDATE(s, "[]", "", "minItems", "");
  647. INVALIDATE(s, "[1]", "", "minItems", "");
  648. VALIDATE(s, "[1, 2]", true);
  649. VALIDATE(s, "[1, 2, 3]", true);
  650. INVALIDATE(s, "[1, 2, 3, 4]", "", "maxItems", "");
  651. }
  652. TEST(SchemaValidator, Array_UniqueItems) {
  653. Document sd;
  654. sd.Parse("{\"type\": \"array\", \"uniqueItems\": true}");
  655. SchemaDocument s(sd);
  656. VALIDATE(s, "[1, 2, 3, 4, 5]", true);
  657. INVALIDATE(s, "[1, 2, 3, 3, 4]", "", "uniqueItems", "/3");
  658. VALIDATE(s, "[]", true);
  659. }
  660. TEST(SchemaValidator, Boolean) {
  661. Document sd;
  662. sd.Parse("{\"type\":\"boolean\"}");
  663. SchemaDocument s(sd);
  664. VALIDATE(s, "true", true);
  665. VALIDATE(s, "false", true);
  666. INVALIDATE(s, "\"true\"", "", "type", "");
  667. INVALIDATE(s, "0", "", "type", "");
  668. }
  669. TEST(SchemaValidator, Null) {
  670. Document sd;
  671. sd.Parse("{\"type\":\"null\"}");
  672. SchemaDocument s(sd);
  673. VALIDATE(s, "null", true);
  674. INVALIDATE(s, "false", "", "type", "");
  675. INVALIDATE(s, "0", "", "type", "");
  676. INVALIDATE(s, "\"\"", "", "type", "");
  677. }
  678. // Additional tests
  679. TEST(SchemaValidator, ObjectInArray) {
  680. Document sd;
  681. sd.Parse("{\"type\":\"array\", \"items\": { \"type\":\"string\" }}");
  682. SchemaDocument s(sd);
  683. VALIDATE(s, "[\"a\"]", true);
  684. INVALIDATE(s, "[1]", "/items", "type", "/0");
  685. INVALIDATE(s, "[{}]", "/items", "type", "/0");
  686. }
  687. TEST(SchemaValidator, MultiTypeInObject) {
  688. Document sd;
  689. sd.Parse(
  690. "{"
  691. " \"type\":\"object\","
  692. " \"properties\": {"
  693. " \"tel\" : {"
  694. " \"type\":[\"integer\", \"string\"]"
  695. " }"
  696. " }"
  697. "}");
  698. SchemaDocument s(sd);
  699. VALIDATE(s, "{ \"tel\": 999 }", true);
  700. VALIDATE(s, "{ \"tel\": \"123-456\" }", true);
  701. INVALIDATE(s, "{ \"tel\": true }", "/properties/tel", "type", "/tel");
  702. }
  703. TEST(SchemaValidator, MultiTypeWithObject) {
  704. Document sd;
  705. sd.Parse(
  706. "{"
  707. " \"type\": [\"object\",\"string\"],"
  708. " \"properties\": {"
  709. " \"tel\" : {"
  710. " \"type\": \"integer\""
  711. " }"
  712. " }"
  713. "}");
  714. SchemaDocument s(sd);
  715. VALIDATE(s, "\"Hello\"", true);
  716. VALIDATE(s, "{ \"tel\": 999 }", true);
  717. INVALIDATE(s, "{ \"tel\": \"fail\" }", "/properties/tel", "type", "/tel");
  718. }
  719. TEST(SchemaValidator, AllOf_Nested) {
  720. Document sd;
  721. sd.Parse(
  722. "{"
  723. " \"allOf\": ["
  724. " { \"type\": \"string\", \"minLength\": 2 },"
  725. " { \"type\": \"string\", \"maxLength\": 5 },"
  726. " { \"allOf\": [ { \"enum\" : [\"ok\", \"okay\", \"OK\", \"o\"] }, { \"enum\" : [\"ok\", \"OK\", \"o\"]} ] }"
  727. " ]"
  728. "}");
  729. SchemaDocument s(sd);
  730. VALIDATE(s, "\"ok\"", true);
  731. VALIDATE(s, "\"OK\"", true);
  732. INVALIDATE(s, "\"okay\"", "", "allOf", "");
  733. INVALIDATE(s, "\"o\"", "", "allOf", "");
  734. INVALIDATE(s, "\"n\"", "", "allOf", "");
  735. INVALIDATE(s, "\"too long\"", "", "allOf", "");
  736. INVALIDATE(s, "123", "", "allOf", "");
  737. }
  738. template <typename Allocator>
  739. static char* ReadFile(const char* filename, Allocator& allocator) {
  740. const char *paths[] = {
  741. "",
  742. "bin/",
  743. "../bin/",
  744. "../../bin/",
  745. "../../../bin/"
  746. };
  747. char buffer[1024];
  748. FILE *fp = 0;
  749. for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
  750. sprintf(buffer, "%s%s", paths[i], filename);
  751. fp = fopen(buffer, "rb");
  752. if (fp)
  753. break;
  754. }
  755. if (!fp)
  756. return 0;
  757. fseek(fp, 0, SEEK_END);
  758. size_t length = static_cast<size_t>(ftell(fp));
  759. fseek(fp, 0, SEEK_SET);
  760. char* json = reinterpret_cast<char*>(allocator.Malloc(length + 1));
  761. size_t readLength = fread(json, 1, length, fp);
  762. json[readLength] = '\0';
  763. fclose(fp);
  764. return json;
  765. }
  766. TEST(SchemaValidator, ValidateMetaSchema) {
  767. CrtAllocator allocator;
  768. char* json = ReadFile("draft-04/schema", allocator);
  769. Document d;
  770. d.Parse(json);
  771. ASSERT_FALSE(d.HasParseError());
  772. SchemaDocument sd(d);
  773. SchemaValidator validator(sd);
  774. if (!d.Accept(validator)) {
  775. StringBuffer sb;
  776. validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
  777. printf("Invalid schema: %s\n", sb.GetString());
  778. printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
  779. sb.Clear();
  780. validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
  781. printf("Invalid document: %s\n", sb.GetString());
  782. ADD_FAILURE();
  783. }
  784. CrtAllocator::Free(json);
  785. }
  786. TEST(SchemaValidator, ValidateMetaSchema_UTF16) {
  787. typedef GenericDocument<UTF16<> > D;
  788. typedef GenericSchemaDocument<D::ValueType> SD;
  789. typedef GenericSchemaValidator<SD> SV;
  790. CrtAllocator allocator;
  791. char* json = ReadFile("draft-04/schema", allocator);
  792. D d;
  793. StringStream ss(json);
  794. d.ParseStream<0, UTF8<> >(ss);
  795. ASSERT_FALSE(d.HasParseError());
  796. SD sd(d);
  797. SV validator(sd);
  798. if (!d.Accept(validator)) {
  799. GenericStringBuffer<UTF16<> > sb;
  800. validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
  801. wprintf(L"Invalid schema: %ls\n", sb.GetString());
  802. wprintf(L"Invalid keyword: %ls\n", validator.GetInvalidSchemaKeyword());
  803. sb.Clear();
  804. validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
  805. wprintf(L"Invalid document: %ls\n", sb.GetString());
  806. ADD_FAILURE();
  807. }
  808. CrtAllocator::Free(json);
  809. }
  810. template <typename SchemaDocumentType = SchemaDocument>
  811. class RemoteSchemaDocumentProvider : public IGenericRemoteSchemaDocumentProvider<SchemaDocumentType> {
  812. public:
  813. RemoteSchemaDocumentProvider() :
  814. documentAllocator_(documentBuffer_, sizeof(documentBuffer_)),
  815. schemaAllocator_(schemaBuffer_, sizeof(schemaBuffer_))
  816. {
  817. const char* filenames[kCount] = {
  818. "jsonschema/remotes/integer.json",
  819. "jsonschema/remotes/subSchemas.json",
  820. "jsonschema/remotes/folder/folderInteger.json",
  821. "draft-04/schema"
  822. };
  823. for (size_t i = 0; i < kCount; i++) {
  824. sd_[i] = 0;
  825. char jsonBuffer[8192];
  826. MemoryPoolAllocator<> jsonAllocator(jsonBuffer, sizeof(jsonBuffer));
  827. char* json = ReadFile(filenames[i], jsonAllocator);
  828. if (!json) {
  829. printf("json remote file %s not found", filenames[i]);
  830. ADD_FAILURE();
  831. }
  832. else {
  833. char stackBuffer[4096];
  834. MemoryPoolAllocator<> stackAllocator(stackBuffer, sizeof(stackBuffer));
  835. DocumentType d(&documentAllocator_, 1024, &stackAllocator);
  836. d.Parse(json);
  837. sd_[i] = new SchemaDocumentType(d, 0, &schemaAllocator_);
  838. MemoryPoolAllocator<>::Free(json);
  839. }
  840. };
  841. }
  842. ~RemoteSchemaDocumentProvider() {
  843. for (size_t i = 0; i < kCount; i++)
  844. delete sd_[i];
  845. }
  846. virtual const SchemaDocumentType* GetRemoteDocument(const char* uri, SizeType length) {
  847. const char* uris[kCount] = {
  848. "http://localhost:1234/integer.json",
  849. "http://localhost:1234/subSchemas.json",
  850. "http://localhost:1234/folder/folderInteger.json",
  851. "http://json-schema.org/draft-04/schema"
  852. };
  853. for (size_t i = 0; i < kCount; i++)
  854. if (strncmp(uri, uris[i], length) == 0)
  855. return sd_[i];
  856. return 0;
  857. }
  858. private:
  859. typedef GenericDocument<typename SchemaDocumentType::EncodingType, MemoryPoolAllocator<>, MemoryPoolAllocator<> > DocumentType;
  860. RemoteSchemaDocumentProvider(const RemoteSchemaDocumentProvider&);
  861. RemoteSchemaDocumentProvider& operator=(const RemoteSchemaDocumentProvider&);
  862. static const size_t kCount = 4;
  863. SchemaDocumentType* sd_[kCount];
  864. typename DocumentType::AllocatorType documentAllocator_;
  865. typename SchemaDocumentType::AllocatorType schemaAllocator_;
  866. char documentBuffer_[16384];
  867. char schemaBuffer_[128 * 1024];
  868. };
  869. TEST(SchemaValidator, TestSuite) {
  870. const char* filenames[] = {
  871. "additionalItems.json",
  872. "additionalProperties.json",
  873. "allOf.json",
  874. "anyOf.json",
  875. "default.json",
  876. "definitions.json",
  877. "dependencies.json",
  878. "enum.json",
  879. "items.json",
  880. "maximum.json",
  881. "maxItems.json",
  882. "maxLength.json",
  883. "maxProperties.json",
  884. "minimum.json",
  885. "minItems.json",
  886. "minLength.json",
  887. "minProperties.json",
  888. "multipleOf.json",
  889. "not.json",
  890. "oneOf.json",
  891. "pattern.json",
  892. "patternProperties.json",
  893. "properties.json",
  894. "ref.json",
  895. "refRemote.json",
  896. "required.json",
  897. "type.json",
  898. "uniqueItems.json"
  899. };
  900. const char* onlyRunDescription = 0;
  901. //const char* onlyRunDescription = "a string is a string";
  902. unsigned testCount = 0;
  903. unsigned passCount = 0;
  904. typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
  905. RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
  906. char jsonBuffer[65536];
  907. char documentBuffer[65536];
  908. char documentStackBuffer[65536];
  909. char schemaBuffer[65536];
  910. char validatorBuffer[65536];
  911. MemoryPoolAllocator<> jsonAllocator(jsonBuffer, sizeof(jsonBuffer));
  912. MemoryPoolAllocator<> documentAllocator(documentBuffer, sizeof(documentBuffer));
  913. MemoryPoolAllocator<> documentStackAllocator(documentStackBuffer, sizeof(documentStackBuffer));
  914. MemoryPoolAllocator<> schemaAllocator(schemaBuffer, sizeof(schemaBuffer));
  915. MemoryPoolAllocator<> validatorAllocator(validatorBuffer, sizeof(validatorBuffer));
  916. for (size_t i = 0; i < sizeof(filenames) / sizeof(filenames[0]); i++) {
  917. char filename[FILENAME_MAX];
  918. sprintf(filename, "jsonschema/tests/draft4/%s", filenames[i]);
  919. char* json = ReadFile(filename, jsonAllocator);
  920. if (!json) {
  921. printf("json test suite file %s not found", filename);
  922. ADD_FAILURE();
  923. }
  924. else {
  925. GenericDocument<UTF8<>, MemoryPoolAllocator<>, MemoryPoolAllocator<> > d(&documentAllocator, 1024, &documentStackAllocator);
  926. d.Parse(json);
  927. if (d.HasParseError()) {
  928. printf("json test suite file %s has parse error", filename);
  929. ADD_FAILURE();
  930. }
  931. else {
  932. for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) {
  933. {
  934. SchemaDocumentType schema((*schemaItr)["schema"], &provider, &schemaAllocator);
  935. GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > validator(schema, &validatorAllocator);
  936. const char* description1 = (*schemaItr)["description"].GetString();
  937. const Value& tests = (*schemaItr)["tests"];
  938. for (Value::ConstValueIterator testItr = tests.Begin(); testItr != tests.End(); ++testItr) {
  939. const char* description2 = (*testItr)["description"].GetString();
  940. if (!onlyRunDescription || strcmp(description2, onlyRunDescription) == 0) {
  941. const Value& data = (*testItr)["data"];
  942. bool expected = (*testItr)["valid"].GetBool();
  943. testCount++;
  944. validator.Reset();
  945. bool actual = data.Accept(validator);
  946. if (expected != actual)
  947. printf("Fail: %30s \"%s\" \"%s\"\n", filename, description1, description2);
  948. else
  949. passCount++;
  950. }
  951. }
  952. //printf("%zu %zu %zu\n", documentAllocator.Size(), schemaAllocator.Size(), validatorAllocator.Size());
  953. }
  954. schemaAllocator.Clear();
  955. validatorAllocator.Clear();
  956. }
  957. }
  958. }
  959. documentAllocator.Clear();
  960. MemoryPoolAllocator<>::Free(json);
  961. jsonAllocator.Clear();
  962. }
  963. printf("%d / %d passed (%2d%%)\n", passCount, testCount, passCount * 100 / testCount);
  964. // if (passCount != testCount)
  965. // ADD_FAILURE();
  966. }
  967. TEST(SchemaValidatingReader, Simple) {
  968. Document sd;
  969. sd.Parse("{ \"type\": \"string\", \"enum\" : [\"red\", \"amber\", \"green\"] }");
  970. SchemaDocument s(sd);
  971. Document d;
  972. StringStream ss("\"red\"");
  973. SchemaValidatingReader<kParseDefaultFlags, StringStream, UTF8<> > reader(ss, s);
  974. d.Populate(reader);
  975. EXPECT_TRUE(reader.GetParseResult());
  976. EXPECT_TRUE(reader.IsValid());
  977. EXPECT_TRUE(d.IsString());
  978. EXPECT_STREQ("red", d.GetString());
  979. }
  980. TEST(SchemaValidatingReader, Invalid) {
  981. Document sd;
  982. sd.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
  983. SchemaDocument s(sd);
  984. Document d;
  985. StringStream ss("\"ABCD\"");
  986. SchemaValidatingReader<kParseDefaultFlags, StringStream, UTF8<> > reader(ss, s);
  987. d.Populate(reader);
  988. EXPECT_FALSE(reader.GetParseResult());
  989. EXPECT_FALSE(reader.IsValid());
  990. EXPECT_EQ(kParseErrorTermination, reader.GetParseResult().Code());
  991. EXPECT_STREQ("maxLength", reader.GetInvalidSchemaKeyword());
  992. EXPECT_TRUE(reader.GetInvalidSchemaPointer() == SchemaDocument::PointerType(""));
  993. EXPECT_TRUE(reader.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
  994. EXPECT_TRUE(d.IsNull());
  995. }
  996. TEST(SchemaValidatingWriter, Simple) {
  997. Document sd;
  998. sd.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
  999. SchemaDocument s(sd);
  1000. Document d;
  1001. StringBuffer sb;
  1002. Writer<StringBuffer> writer(sb);
  1003. GenericSchemaValidator<SchemaDocument, Writer<StringBuffer> > validator(s, writer);
  1004. d.Parse("\"red\"");
  1005. EXPECT_TRUE(d.Accept(validator));
  1006. EXPECT_TRUE(validator.IsValid());
  1007. EXPECT_STREQ("\"red\"", sb.GetString());
  1008. sb.Clear();
  1009. validator.Reset();
  1010. d.Parse("\"ABCD\"");
  1011. EXPECT_FALSE(d.Accept(validator));
  1012. EXPECT_FALSE(validator.IsValid());
  1013. EXPECT_TRUE(validator.GetInvalidSchemaPointer() == SchemaDocument::PointerType(""));
  1014. EXPECT_TRUE(validator.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
  1015. }
  1016. #ifdef __clang__
  1017. RAPIDJSON_DIAG_POP
  1018. #endif