1 #include <string>
2 #include <vector>
3 #include <unistd.h>
4
5 #include "simdjson.h"
6 #include "test_macros.h"
7
8 namespace document_tests {
issue938()9 bool issue938() {
10 std::vector<std::string> json_strings{"[true,false]", "[1,2,3,null]",
11 R"({"yay":"json!"})"};
12 simdjson::dom::parser parser1;
13 for (simdjson::padded_string str : json_strings) {
14 simdjson::dom::element element;
15 ASSERT_SUCCESS( parser1.parse(str).get(element) );
16 std::cout << element << std::endl;
17 }
18 std::vector<std::string> file_paths{
19 ADVERSARIAL_JSON, FLATADVERSARIAL_JSON, DEMO_JSON,
20 TWITTER_TIMELINE_JSON, REPEAT_JSON, SMALLDEMO_JSON,
21 TRUENULL_JSON};
22 for (auto path : file_paths) {
23 simdjson::dom::parser parser2;
24 simdjson::dom::element element;
25 std::cout << "file: " << path << std::endl;
26 ASSERT_SUCCESS( parser2.load(path).get(element) );
27 std::cout << element.type() << std::endl;
28 }
29 simdjson::dom::parser parser3;
30 for (auto path : file_paths) {
31 simdjson::dom::element element;
32 std::cout << "file: " << path << std::endl;
33 ASSERT_SUCCESS( parser3.load(path).get(element) );
34 std::cout << element.type() << std::endl;
35 }
36 return true;
37 }
38
39 // adversarial example that once triggered overruns, see https://github.com/simdjson/simdjson/issues/345
bad_example()40 bool bad_example() {
41 std::cout << __func__ << std::endl;
42 simdjson::padded_string badjson = "[7,7,7,7,6,7,7,7,6,7,7,6,[7,7,7,7,6,7,7,7,6,7,7,6,7,7,7,7,7,7,6"_padded;
43 simdjson::dom::parser parser;
44 ASSERT_ERROR( parser.parse(badjson), simdjson::TAPE_ERROR );
45 return true;
46 }
count_array_example()47 bool count_array_example() {
48 std::cout << __func__ << std::endl;
49 simdjson::padded_string smalljson = "[1,2,3]"_padded;
50 simdjson::dom::parser parser;
51 simdjson::dom::array array;
52 ASSERT_SUCCESS( parser.parse(smalljson).get(array) );
53 ASSERT_EQUAL( array.size(), 3 );
54 return true;
55 }
count_object_example()56 bool count_object_example() {
57 std::cout << __func__ << std::endl;
58 simdjson::padded_string smalljson = "{\"1\":1,\"2\":1,\"3\":1}"_padded;
59 simdjson::dom::parser parser;
60 simdjson::dom::object object;
61 ASSERT_SUCCESS( parser.parse(smalljson).get(object) );
62 ASSERT_EQUAL( object.size(), 3 );
63 return true;
64 }
padded_with_open_bracket()65 bool padded_with_open_bracket() {
66 std::cout << __func__ << std::endl;
67 simdjson::dom::parser parser;
68 // This is an invalid document padded with open braces.
69 ASSERT_ERROR( parser.parse("[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[", 2, false), simdjson::TAPE_ERROR);
70 // This is a valid document padded with open braces.
71 ASSERT_SUCCESS( parser.parse("[][[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[", 2, false) );
72 return true;
73 }
74 // returns true if successful
stable_test()75 bool stable_test() {
76 std::cout << __func__ << std::endl;
77 simdjson::padded_string json = "{"
78 "\"Image\":{"
79 "\"Width\":800,"
80 "\"Height\":600,"
81 "\"Title\":\"View from 15th Floor\","
82 "\"Thumbnail\":{"
83 "\"Url\":\"http://www.example.com/image/481989943\","
84 "\"Height\":125,"
85 "\"Width\":100"
86 "},"
87 "\"Animated\":false,"
88 "\"IDs\":[116,943.3,234,38793]"
89 "}"
90 "}"_padded;
91 simdjson::dom::parser parser;
92 std::ostringstream myStream;
93 #if SIMDJSON_EXCEPTIONS
94 myStream << parser.parse(json);
95 #else
96 simdjson::dom::element doc;
97 simdjson_unused auto error = parser.parse(json).get(doc);
98 myStream << doc;
99 #endif
100 std::string newjson = myStream.str();
101 if(static_cast<std::string>(json) != newjson) {
102 std::cout << "serialized json differs!" << std::endl;
103 std::cout << static_cast<std::string>(json) << std::endl;
104 std::cout << newjson << std::endl;
105 }
106 return newjson == static_cast<std::string>(json);
107 }
108 // returns true if successful
skyprophet_test()109 bool skyprophet_test() {
110 std::cout << "Running " << __func__ << std::endl;
111 const size_t n_records = 100;
112 std::vector<std::string> data;
113 std::vector<char> buf(1024);
114 for (size_t i = 0; i < n_records; ++i) {
115 size_t n = snprintf(buf.data(), buf.size(),
116 "{\"id\": %zu, \"name\": \"name%zu\", \"gender\": \"%s\", "
117 "\"school\": {\"id\": %zu, \"name\": \"school%zu\"}}",
118 i, i, (i % 2) ? "male" : "female", i % 10, i % 10);
119 if (n >= buf.size()) { abort(); }
120 data.emplace_back(std::string(buf.data(), n));
121 }
122 for (size_t i = 0; i < n_records; ++i) {
123 size_t n = snprintf(buf.data(), buf.size(), "{\"counter\": %f, \"array\": [%s]}", static_cast<double>(i) * 3.1416,
124 (i % 2) ? "true" : "false");
125 if (n >= buf.size()) { abort(); }
126 data.emplace_back(std::string(buf.data(), n));
127 }
128 for (size_t i = 0; i < n_records; ++i) {
129 size_t n = snprintf(buf.data(), buf.size(), "{\"number\": %e}", static_cast<double>(i) * 10000.31321321);
130 if (n >= buf.size()) { abort(); }
131 data.emplace_back(std::string(buf.data(), n));
132 }
133 data.emplace_back(std::string("true"));
134 data.emplace_back(std::string("false"));
135 data.emplace_back(std::string("null"));
136 data.emplace_back(std::string("0.1"));
137 size_t maxsize = 0;
138 for (auto &s : data) {
139 if (maxsize < s.size())
140 maxsize = s.size();
141 }
142 simdjson::dom::parser parser;
143 size_t counter = 0;
144 for (auto &rec : data) {
145 if ((counter % 10000) == 0) {
146 printf(".");
147 fflush(NULL);
148 }
149 counter++;
150 auto error = parser.parse(rec.c_str(), rec.length()).error();
151 if (error != simdjson::error_code::SUCCESS) {
152 printf("Something is wrong in skyprophet_test: %s.\n", rec.c_str());
153 printf("Parsing failed. Error is %s\n", simdjson::error_message(error));
154 return false;
155 }
156 error = parser.parse(rec.c_str(), rec.length()).error();
157 if (error != simdjson::error_code::SUCCESS) {
158 printf("Something is wrong in skyprophet_test: %s.\n", rec.c_str());
159 printf("Parsing failed. Error is %s\n", simdjson::error_message(error));
160 return false;
161 }
162 }
163 printf("\n");
164 return true;
165 }
lots_of_brackets()166 bool lots_of_brackets() {
167 std::string input;
168 for(size_t i = 0; i < 200; i++) {
169 input += "[";
170 }
171 for(size_t i = 0; i < 200; i++) {
172 input += "]";
173 }
174 simdjson::dom::parser parser;
175 auto error = parser.parse(input).error();
176 if (error) { std::cerr << "Error: " << simdjson::error_message(error) << std::endl; return false; }
177 return true;
178 }
run()179 bool run() {
180 return issue938() &&
181 padded_with_open_bracket() &&
182 bad_example() &&
183 count_array_example() &&
184 count_object_example() &&
185 stable_test() &&
186 skyprophet_test() &&
187 lots_of_brackets();
188 }
189 }
190
191
192
193
main(int argc,char * argv[])194 int main(int argc, char *argv[]) {
195 std::cout << std::unitbuf;
196 int c;
197 while ((c = getopt(argc, argv, "a:")) != -1) {
198 switch (c) {
199 case 'a': {
200 const simdjson::implementation *impl = simdjson::available_implementations[optarg];
201 if (!impl) {
202 fprintf(stderr, "Unsupported architecture value -a %s\n", optarg);
203 return EXIT_FAILURE;
204 }
205 if(!impl->supported_by_runtime_system()) {
206 fprintf(stderr, "The selected implementation does not match your current CPU: -a %s\n", optarg);
207 return EXIT_FAILURE;
208 }
209 simdjson::active_implementation = impl;
210 break;
211 }
212 default:
213 fprintf(stderr, "Unexpected argument %c\n", c);
214 return EXIT_FAILURE;
215 }
216 }
217
218 // this is put here deliberately to check that the documentation is correct (README),
219 // should this fail to compile, you should update the documentation:
220 if (simdjson::active_implementation->name() == "unsupported") {
221 printf("unsupported CPU\n");
222 }
223 // We want to know what we are testing.
224 std::cout << "Running tests against this implementation: " << simdjson::active_implementation->name();
225 std::cout << " (" << simdjson::active_implementation->description() << ")" << std::endl;
226 std::cout << "------------------------------------------------------------" << std::endl;
227
228 std::cout << "Running document tests." << std::endl;
229 if (document_tests::run()) {
230 std::cout << "document tests are ok." << std::endl;
231 return EXIT_SUCCESS;
232 } else {
233 return EXIT_FAILURE;
234 }
235 }