// // Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Official repository: https://github.com/vinniefalco/json // // Test that header file is self-contained. #include #include #include "fail_parser.hpp" #include "throw_parser.hpp" #include "parse-vectors.hpp" namespace boost { namespace json { class basic_parser_test : public beast::unit_test::suite { public: void parse_grind( string_view input, error_code ex) { if(input.size() > 100) return; // iterate each split point if(input.size() > 0) { for(std::size_t i = 0; i < input.size() - 1; ++i) { BEAST_EXPECT(i < 10000); // test exceptions for(std::size_t j = 1;;++j) { if(! BEAST_EXPECT(j < 10000)) break; error_code ec; throw_parser p(j); try { p.write_some( input.data(), i, ec); if(! ec) p.write(input.data() + i, input.size() - i, ec); if(ec) BEAST_EXPECTS( ec == ex, std::string(input) + " : " + ec.message()); break; } catch(test_exception const&) { continue; } catch(...) { BEAST_FAIL(); } } // test errors for(std::size_t j = 1;;++j) { if(! BEAST_EXPECT(j < 10000)) break; error_code ec; fail_parser p(j); { p.write_some(input.data(), i, ec); if(ec == error::test_failure) continue; } if(! ec) { p.write_some(input.data() + i, input.size() - i, ec); if(ec == error::test_failure) continue; } if(! ec) { p.write_eof(ec); if(ec == error::test_failure) continue; } if(ec) BEAST_EXPECTS( ec == ex, std::string(input) + " : " + ec.message()); break; } } } #if 0 std::size_t n = 1; for(; n < 10000; ++n) { error_code ec; fail_parser p{n}; p.write( input.data(), input.size(), ec); if(ec != error::test_failure) { BEAST_EXPECTS( ec == ex, std::string(input) + " : " + ec.message()); break; } } BEAST_EXPECT(n < 10000); #endif } void good(string_view s) { #if 0 error_code ec; for(std::size_t i = 0; i < s.size() - 1; ++i) { // write_some with 1 buffer { fail_parser p; auto used = p.write_some(s.data(), i, ec); BEAST_EXPECT(used == i); BEAST_EXPECT(! p.is_done()); if(! BEAST_EXPECTS(! ec, ec.message())) continue; used = p.write_some( s.data() + i, s.size() - i, ec); BEAST_EXPECT(used == s.size() - i); if(! BEAST_EXPECTS(! ec, ec.message())) continue; p.write(nullptr, 0, ec); BEAST_EXPECTS(! ec, ec.message()); BEAST_EXPECT(p.is_done()); } // write with 1 buffer { fail_parser p; auto used = p.write(s.data(), s.size(), ec); BEAST_EXPECT(used = s.size()); BEAST_EXPECTS(! ec, ec.message()); } } #else parse_grind(s, error_code{}); #endif } void bad(string_view s) { error_code ec; fail_parser p; auto const used = p.write_some( s.data(), s.size(), ec); if(! ec) { if(p.is_done()) { if(BEAST_EXPECT(used != s.size())) return; } else { p.write_eof(ec); if(BEAST_EXPECT(ec)) return; } } else { pass(); return; } log << "fail: \"" << s << "\"\n"; } void testObject() { good("{}"); good("{ }"); good("{ \t }"); good("{ \"x\" : null }"); good("{ \"x\" : {} }"); good("{ \"x\" : { \"y\" : null } }"); bad ("{"); bad ("{{}}"); } void testArray() { good("[]"); good("[ ]"); good("[ \t ]"); good("[ \"\" ]"); good("[ \" \" ]"); good("[ \"x\" ]"); good("[ \"x\", \"y\" ]"); bad ("["); bad ("[ \"x\", ]"); } void testString() { good("\"" "x" "\""); good("\"" "xy" "\""); good("\"" "x y" "\""); bad ("\"" "\t" "\""); } void testNumber() { good("0"); good("0.0"); good("0.10"); good("0.01"); good("1"); good("10"); good("1.5"); good("10.5"); good("10.25"); good("10.25e0"); good("1e1"); good("1e10"); good("1e+0"); good("1e+1"); good("0e+10"); good("0e-0"); good("0e-1"); good("0e-10"); good("1E+1"); good("-0"); good("-1"); good("-1e1"); bad (""); bad ("-"); bad ("00"); bad ("00."); bad ("00.0"); bad ("1a"); bad ("."); bad ("1."); bad ("1+"); bad ("0.0+"); bad ("0.0e+"); bad ("0.0e-"); bad ("0.0e0-"); bad ("0.0e"); } void testBoolean() { good("true"); good(" true"); good("true "); good("\ttrue"); good("true\t"); good("\r\n\t true\r\n\t "); bad ("TRUE"); bad ("tRUE"); bad ("trUE"); bad ("truE"); bad ("truex"); bad ("tru"); bad ("tr"); bad ("t"); good("false"); good(" false"); good("false "); good("\tfalse"); good("false\t"); good("\r\n\t false\r\n\t "); bad ("FALSE"); bad ("fALSE"); bad ("faLSE"); bad ("falSE"); bad ("falsE"); bad ("falsex"); bad ("fals"); bad ("fal"); bad ("fa"); bad ("f"); } void testNull() { good("null"); good(" null"); good("null "); good("\tnull"); good("null\t"); good("\r\n\t null\r\n\t "); bad ("NULL"); bad ("nULL"); bad ("nuLL"); bad ("nulL"); bad ("nullx"); bad ("nul"); bad ("nu"); bad ("n"); } void testParseVectors() { parse_vectors pv; std::size_t fail = 0; std::size_t info = 0; auto const tot = pv.size(); for(auto const& v : pv) { error_code ec; fail_parser p; p.write( v.text.data(), v.text.size(), ec); if(v.result == 'i') { auto const s = ec ? "reject" : "accept"; ++info; log << "'" << v.result << "' " << v.name << " " << s << "\n"; parse_grind(v.text, ec); continue; } char result; result = ec ? 'n' : 'y'; if(result != v.result) { if(v.result == 'i') ++info; else ++fail; log << "'" << v.result << "' " << v.name; if(ec) log << " " << ec.message() << "\n"; else log << "\n"; } else { parse_grind(v.text, ec); } } if(fail > 0) log << fail << "/" << tot << " parse vector failures, " << info << " informational.\n"; } void run() override { log << "sizeof(basic_parser) == " << sizeof(basic_parser) << "\n"; testParseVectors(); testObject(); testArray(); testString(); testNumber(); testBoolean(); testNull(); } }; BEAST_DEFINE_TESTSUITE(boost,json,basic_parser); } // json } // boost