#include "gtest/gtest.h" #include "radixbug/bug.hh" #include "radixcore/json.hh" #include "radixcore/system.hh" using namespace radix; // JsonType& root() { return m_root; } // std::string last_error() // bool parse() // bool parse_from_stream(std::istream& in_stream) // bool parse_from_file(std::string fn) TEST(JSONParser, DISABLED_parse_from_file) { { JSONParser sunnyDay; std::string filename = to_native_path(dirname(__FILE__) + "/testfiles/wellformed.json"); // std::cout << "Test file: " << filename << std::endl; bool success = sunnyDay.parse_from_file(filename); EXPECT_TRUE(success); // not really an error just the null terminating at eof std::string errorMsg = sunnyDay.last_error(); EXPECT_EQ(" at line 14 column 2", errorMsg); Value root = sunnyDay.root(); Value rootObj = root["root object"]; EXPECT_EQ(Value::TYPE_OBJECT, rootObj.type()); EXPECT_EQ(Value::TYPE_BOOLEAN, rootObj["bool"].type()); EXPECT_TRUE(rootObj["bool"].to_bool()); // reads in as double, not int. // EXPECT_EQ(Value::TYPE_INTEGER, rootObj["int"].type()); EXPECT_EQ(1, rootObj["int"].to_int()); EXPECT_EQ(Value::TYPE_DOUBLE, rootObj["double"].type()); EXPECT_EQ(2.34, rootObj["double"].to_double()); EXPECT_EQ(Value::TYPE_STRING, rootObj["string"].type()); EXPECT_EQ("This is a string!", rootObj["string"].to_string()); EXPECT_EQ(Value::TYPE_ARRAY, rootObj["array"].type()); DataArray& array = rootObj["array"].as_array(); EXPECT_EQ("Array of JSON values.", array.at(0).to_string()); EXPECT_EQ(1, array.at(1).to_int()); EXPECT_EQ(2.34, array.at(2).to_double()); EXPECT_TRUE(array.at(3).to_bool()); } { JSONParser noFile; std::string filename = "wrong_path/file_doesn't_exist.json"; bool success = noFile.parse_from_file(filename); EXPECT_FALSE(success); std::string errorMsg = noFile.last_error(); EXPECT_EQ("could not open file at line 1 column 1", errorMsg); } } TEST(JSONParser, DISABLED_parse_from_stream) { // check code paths in JSONParser class { JSONParser jp; std::string errorMsg; // trailing junk std::stringstream ss("{}\r\nfoo"); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("unexpected trailing character(s) at line 2 column 1", errorMsg); // unclosed array with no child elements ss.str("["); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("no closing bracket ']' for array at line 1 column 2", errorMsg); // unclosed array with at least one child element ss.str("[ \"bar\""); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); std::string expected("invalid character '\0' in array at line 1 column 8", 49); EXPECT_EQ(expected, errorMsg); // trailing comma in array ss.str("[ \"baz\" , ]"); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("trailing comma in array at line 1 column 9", errorMsg); // lone '-' at end (considered as invalid number) ss.str("-"); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("invalid number (no digits after -) at line 1 column 2", errorMsg); // lone '-' followed by whitespace (considered as invalid number) ss.str("- "); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("invalid number (no digits) at line 1 column 2", errorMsg); // no digits after decimal ss.str("5."); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("invalid number (no digits after decimal) at line 1 column 3", errorMsg); // no digits after decimal ss.str("5. "); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("invalid number (no digits after decimal) at line 1 column 3", errorMsg); // no digits after 'e' in exponent at end ss.str("1.2e"); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("invalid number (no digits for exponent) at line 1 column 5", errorMsg); // no digits after 'e' in exponent at end ss.str("1.2e-"); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("invalid number (no digits for exponent) at line 1 column 6", errorMsg); // no digits after 'e' in exponent followed by whitespace ss.str("3.4E "); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("invalid number (no digits after decimal) at line 1 column 5", errorMsg); // invalid literal ss.str("foo"); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("invalid literal at line 1 column 1", errorMsg); // null literal ss.str("null"); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ(" at line 1 column 5", errorMsg); // unclosed object with no child elements ss.str("{"); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("no closing curly bracket '}' for object at line 1 column 2", errorMsg); // object child with bad key ss.str("{ \"bar"); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("string missing closing quote at line 1 column 7", errorMsg); // unclosed object with at least one child element ss.str("{ \"bar\" : 1"); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("invalid character in object at line 1 column 12", errorMsg); // trailing comma in object ss.str("{ \"baz\" : 1 , }"); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("trailing comma in object at line 1 column 13", errorMsg); // missing value in object ss.str("{ \"foo\" : }"); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("missing value in object at line 1 column 11", errorMsg); // missing ':' and value in object ss.str("{ \"foo\" }"); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("no ':' following key in object at line 1 column 9", errorMsg); // invalid escape sequence ss.str("\"\\"); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ( "incomplete unicode character escape sequence in string at line 1 " "column 3", errorMsg); // invalid escape sequence ss.str("\"\\q"); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("invalid escape sequence in string at line 1 column 3", errorMsg); // incomplete unicode escape sequence ss.str("\"\\u012"); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ( "incomplete unicode character escape sequence in string at line 1 " "column 7", errorMsg); // invalid unicode escape sequence ss.str("\"\\u012Q\""); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ( "invalid unicode character escape sequence in string at line 1 column " "7", errorMsg); // non-terminated string ss.str("\"bar"); EXPECT_FALSE(jp.parse_from_stream(ss)); errorMsg = jp.last_error(); EXPECT_EQ("string missing closing quote at line 1 column 5", errorMsg); } } bool parse_and_test(const std::string& file) { std::cout << "PARSE_AND_TEST(" << file << ")" << std::endl; Timer benchmark_timer; JSONParser parser; std::string filename = to_native_path(dirname(__FILE__) + "/testfiles/" + file); // std::cout << "Test file: " << filename << std::endl; bool benchmark = (file.substr(0, 4).compare("benc") == 0); if (benchmark) { benchmark_timer.start(); } bool success = parser.parse_from_file(filename); if (benchmark) benchmark_timer.stop(); bool return_success = false; // check if failure is expected if (file.substr(0, 4).compare("fail") == 0) { return_success = !success; } else { return_success = success; } // only show error if parse failed and it was supposed to succeed if (!success && !return_success) { // dump the json error std::cout << parser.last_error() << std::endl; } if (benchmark) { std::cout << "Benchmark(" << file << ") timing: " << (benchmark_timer.duration() / 1e9) << " seconds" << std::endl; } return return_success; } TEST(JSONParser, JSONCheckerFailures) { // EXPECT_TRUE(parse_and_test("fail01_EXCLUDE.json")); EXPECT_TRUE(parse_and_test("fail02.json")); EXPECT_TRUE(parse_and_test("fail03.json")); EXPECT_FALSE(parse_and_test("fail04.json")); EXPECT_TRUE(parse_and_test("fail05.json")); EXPECT_TRUE(parse_and_test("fail06.json")); EXPECT_TRUE(parse_and_test("fail07.json")); EXPECT_TRUE(parse_and_test("fail08.json")); EXPECT_FALSE(parse_and_test("fail09.json")); EXPECT_TRUE(parse_and_test("fail10.json")); EXPECT_TRUE(parse_and_test("fail11.json")); EXPECT_TRUE(parse_and_test("fail12.json")); EXPECT_TRUE(parse_and_test("fail13.json")); EXPECT_TRUE(parse_and_test("fail14.json")); EXPECT_TRUE(parse_and_test("fail15.json")); EXPECT_TRUE(parse_and_test("fail16.json")); EXPECT_TRUE(parse_and_test("fail17.json")); // EXPECT_TRUE(parse_and_test("fail18_EXCLUDE.json")); EXPECT_TRUE(parse_and_test("fail19.json")); EXPECT_TRUE(parse_and_test("fail20.json")); EXPECT_TRUE(parse_and_test("fail21.json")); EXPECT_TRUE(parse_and_test("fail22.json")); EXPECT_TRUE(parse_and_test("fail23.json")); EXPECT_TRUE(parse_and_test("fail24.json")); EXPECT_TRUE(parse_and_test("fail25.json")); EXPECT_TRUE(parse_and_test("fail26.json")); EXPECT_TRUE(parse_and_test("fail27.json")); EXPECT_TRUE(parse_and_test("fail28.json")); EXPECT_TRUE(parse_and_test("fail29.json")); EXPECT_TRUE(parse_and_test("fail30.json")); EXPECT_TRUE(parse_and_test("fail31.json")); EXPECT_TRUE(parse_and_test("fail32.json")); EXPECT_TRUE(parse_and_test("fail33.json")); } TEST(JSONParser, JSONCheckerPassing) { EXPECT_TRUE(parse_and_test("pass01.json")); EXPECT_TRUE(parse_and_test("pass02.json")); EXPECT_TRUE(parse_and_test("pass03.json")); // EXPECT_TRUE(parse_and_test("roundtrip01.json")); // EXPECT_TRUE(parse_and_test("roundtrip02.json")); // EXPECT_TRUE(parse_and_test("roundtrip03.json")); // EXPECT_TRUE(parse_and_test("roundtrip04.json")); // EXPECT_TRUE(parse_and_test("roundtrip05.json")); // EXPECT_TRUE(parse_and_test("roundtrip06.json")); // EXPECT_TRUE(parse_and_test("roundtrip07.json")); // EXPECT_TRUE(parse_and_test("roundtrip08.json")); // EXPECT_TRUE(parse_and_test("roundtrip09.json")); // EXPECT_TRUE(parse_and_test("roundtrip10.json")); // EXPECT_TRUE(parse_and_test("roundtrip11.json")); // EXPECT_TRUE(parse_and_test("roundtrip12.json")); // EXPECT_TRUE(parse_and_test("roundtrip13.json")); // EXPECT_TRUE(parse_and_test("roundtrip14.json")); // EXPECT_TRUE(parse_and_test("roundtrip15.json")); // EXPECT_TRUE(parse_and_test("roundtrip16.json")); // EXPECT_TRUE(parse_and_test("roundtrip17.json")); // EXPECT_TRUE(parse_and_test("roundtrip18.json")); // EXPECT_TRUE(parse_and_test("roundtrip19.json")); // EXPECT_TRUE(parse_and_test("roundtrip20.json")); // EXPECT_TRUE(parse_and_test("roundtrip21.json")); // EXPECT_TRUE(parse_and_test("roundtrip22.json")); // EXPECT_TRUE(parse_and_test("roundtrip23.json")); // EXPECT_TRUE(parse_and_test("roundtrip24.json")); // EXPECT_TRUE(parse_and_test("roundtrip25.json")); // EXPECT_TRUE(parse_and_test("roundtrip26.json")); // EXPECT_TRUE(parse_and_test("roundtrip27.json")); } TEST(JSONParser, JSONCheckerBenchmark) { EXPECT_TRUE(parse_and_test("benchmark_canada.json")); EXPECT_TRUE(parse_and_test("benchmark_citm_catalog.json")); EXPECT_TRUE(parse_and_test("benchmark_twitter.json")); }