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 }