1 #include "perftest.h"
2
3 #if TEST_RAPIDJSON
4
5 #include "rapidjson/schema.h"
6 #include <ctime>
7 #include <string>
8 #include <vector>
9
10 #define ARRAY_SIZE(a) sizeof(a) / sizeof(a[0])
11
12 using namespace rapidjson;
13
14 template <typename Allocator>
ReadFile(const char * filename,Allocator & allocator)15 static char* ReadFile(const char* filename, Allocator& allocator) {
16 const char *paths[] = {
17 "",
18 "bin/",
19 "../bin/",
20 "../../bin/",
21 "../../../bin/"
22 };
23 char buffer[1024];
24 FILE *fp = 0;
25 for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
26 sprintf(buffer, "%s%s", paths[i], filename);
27 fp = fopen(buffer, "rb");
28 if (fp)
29 break;
30 }
31
32 if (!fp)
33 return 0;
34
35 fseek(fp, 0, SEEK_END);
36 size_t length = static_cast<size_t>(ftell(fp));
37 fseek(fp, 0, SEEK_SET);
38 char* json = reinterpret_cast<char*>(allocator.Malloc(length + 1));
39 size_t readLength = fread(json, 1, length, fp);
40 json[readLength] = '\0';
41 fclose(fp);
42 return json;
43 }
44
45 class Schema : public PerfTest {
46 public:
Schema()47 Schema() {}
48
SetUp()49 virtual void SetUp() {
50 PerfTest::SetUp();
51
52 const char* filenames[] = {
53 "additionalItems.json",
54 "additionalProperties.json",
55 "allOf.json",
56 "anyOf.json",
57 "default.json",
58 "definitions.json",
59 "dependencies.json",
60 "enum.json",
61 "items.json",
62 "maximum.json",
63 "maxItems.json",
64 "maxLength.json",
65 "maxProperties.json",
66 "minimum.json",
67 "minItems.json",
68 "minLength.json",
69 "minProperties.json",
70 "multipleOf.json",
71 "not.json",
72 "oneOf.json",
73 "pattern.json",
74 "patternProperties.json",
75 "properties.json",
76 "ref.json",
77 "refRemote.json",
78 "required.json",
79 "type.json",
80 "uniqueItems.json"
81 };
82
83 char jsonBuffer[65536];
84 MemoryPoolAllocator<> jsonAllocator(jsonBuffer, sizeof(jsonBuffer));
85
86 for (size_t i = 0; i < ARRAY_SIZE(filenames); i++) {
87 char filename[FILENAME_MAX];
88 sprintf(filename, "jsonschema/tests/draft4/%s", filenames[i]);
89 char* json = ReadFile(filename, jsonAllocator);
90 if (!json) {
91 printf("json test suite file %s not found", filename);
92 return;
93 }
94
95 Document d;
96 d.Parse(json);
97 if (d.HasParseError()) {
98 printf("json test suite file %s has parse error", filename);
99 return;
100 }
101
102 for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) {
103 std::string schemaDescription = (*schemaItr)["description"].GetString();
104 if (IsExcludeTestSuite(schemaDescription))
105 continue;
106
107 TestSuite* ts = new TestSuite;
108 ts->schema = new SchemaDocument((*schemaItr)["schema"]);
109
110 const Value& tests = (*schemaItr)["tests"];
111 for (Value::ConstValueIterator testItr = tests.Begin(); testItr != tests.End(); ++testItr) {
112 if (IsExcludeTest(schemaDescription + ", " + (*testItr)["description"].GetString()))
113 continue;
114
115 Document* d2 = new Document;
116 d2->CopyFrom((*testItr)["data"], d2->GetAllocator());
117 ts->tests.push_back(d2);
118 }
119 testSuites.push_back(ts);
120 }
121 }
122 }
123
TearDown()124 virtual void TearDown() {
125 PerfTest::TearDown();
126 for (TestSuiteList::const_iterator itr = testSuites.begin(); itr != testSuites.end(); ++itr)
127 delete *itr;
128 testSuites.clear();
129 }
130
131 private:
132 // Using the same exclusion in https://github.com/json-schema/JSON-Schema-Test-Suite
IsExcludeTestSuite(const std::string & description)133 static bool IsExcludeTestSuite(const std::string& description) {
134 const char* excludeTestSuites[] = {
135 //lost failing these tests
136 "remote ref",
137 "remote ref, containing refs itself",
138 "fragment within remote ref",
139 "ref within remote ref",
140 "change resolution scope",
141 // these below were added to get jsck in the benchmarks)
142 "uniqueItems validation",
143 "valid definition",
144 "invalid definition"
145 };
146
147 for (size_t i = 0; i < ARRAY_SIZE(excludeTestSuites); i++)
148 if (excludeTestSuites[i] == description)
149 return true;
150 return false;
151 }
152
153 // Using the same exclusion in https://github.com/json-schema/JSON-Schema-Test-Suite
IsExcludeTest(const std::string & description)154 static bool IsExcludeTest(const std::string& description) {
155 const char* excludeTests[] = {
156 //lots of validators fail these
157 "invalid definition, invalid definition schema",
158 "maxLength validation, two supplementary Unicode code points is long enough",
159 "minLength validation, one supplementary Unicode code point is not long enough",
160 //this is to get tv4 in the benchmarks
161 "heterogeneous enum validation, something else is invalid"
162 };
163
164 for (size_t i = 0; i < ARRAY_SIZE(excludeTests); i++)
165 if (excludeTests[i] == description)
166 return true;
167 return false;
168 }
169
170 Schema(const Schema&);
171 Schema& operator=(const Schema&);
172
173 protected:
174 typedef std::vector<Document*> DocumentList;
175
176 struct TestSuite {
TestSuiteSchema::TestSuite177 TestSuite() : schema() {}
~TestSuiteSchema::TestSuite178 ~TestSuite() {
179 delete schema;
180 for (DocumentList::iterator itr = tests.begin(); itr != tests.end(); ++itr)
181 delete *itr;
182 }
183 SchemaDocument* schema;
184 DocumentList tests;
185 };
186
187 typedef std::vector<TestSuite* > TestSuiteList;
188 TestSuiteList testSuites;
189 };
190
TEST_F(Schema,TestSuite)191 TEST_F(Schema, TestSuite) {
192 char validatorBuffer[65536];
193 MemoryPoolAllocator<> validatorAllocator(validatorBuffer, sizeof(validatorBuffer));
194
195 const int trialCount = 100000;
196 int testCount = 0;
197 clock_t start = clock();
198 for (int i = 0; i < trialCount; i++) {
199 for (TestSuiteList::const_iterator itr = testSuites.begin(); itr != testSuites.end(); ++itr) {
200 const TestSuite& ts = **itr;
201 GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > validator(*ts.schema, &validatorAllocator);
202 for (DocumentList::const_iterator testItr = ts.tests.begin(); testItr != ts.tests.end(); ++testItr) {
203 validator.Reset();
204 (*testItr)->Accept(validator);
205 testCount++;
206 }
207 validatorAllocator.Clear();
208 }
209 }
210 clock_t end = clock();
211 double duration = double(end - start) / CLOCKS_PER_SEC;
212 printf("%d trials in %f s -> %f trials per sec\n", trialCount, duration, trialCount / duration);
213 printf("%d tests per trial\n", testCount / trialCount);
214 }
215
216 #endif
217