2
0
mirror of https://github.com/boostorg/json.git synced 2026-01-24 18:02:22 +00:00

basic_parser improvement

This commit is contained in:
Vinnie Falco
2019-11-10 07:20:17 -08:00
parent c09a326cec
commit 7dc4bdff50
11 changed files with 644 additions and 514 deletions

View File

@@ -11,6 +11,7 @@
#include <boost/json/basic_parser.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <string>
#include "test.hpp"
#include "parse-vectors.hpp"
@@ -22,22 +23,10 @@ class basic_parser_test : public beast::unit_test::suite
{
public:
void
grind(string_view s, bool good)
split_grind(
string_view s,
error_code ex = {})
{
error_code ex;
{
fail_parser p;
p.write(
s.data(),
s.size(),
ex);
if(good)
BEAST_EXPECTS(
! ex, ex.message());
else
BEAST_EXPECT(!!ex);
}
// make sure all split inputs
// produce the same result.
for(std::size_t i = 1;
@@ -47,19 +36,50 @@ public:
break;
error_code ec;
fail_parser p;
p.write_some(s.data(), i, ec);
if(ec == ex)
continue;
if(! BEAST_EXPECTS(
! ec, ec.message()))
auto const n =
p.write_some(s.data(), i, ec);
if(ec)
{
BEAST_EXPECTS(ec == ex,
ec.message());
continue;
}
p.write(
s.data() + i,
s.size() - i, ec);
s.data() + n,
s.size() - n, ec);
if(! BEAST_EXPECTS(ec == ex,
ec.message()))
log << "should be " << ex.message() << std::endl;
}
}
void
fail_grind(
string_view s,
error_code ex = {})
{
// exercise all error paths
for(std::size_t j = 1;;++j)
{
if(! BEAST_EXPECT(j < 100000))
break;
error_code ec;
fail_parser p(j);
p.write(
s.data(), s.size(), ec);
if(ec == error::test_failure)
continue;
BEAST_EXPECTS(ec == ex,
ec.message());
break;
}
}
void
throw_grind(
string_view s,
error_code ex = {})
{
// exercise all exception paths
for(std::size_t j = 1;;++j)
{
@@ -86,22 +106,34 @@ public:
e.what() << std::endl;
}
}
}
// exercise all error paths
for(std::size_t j = 1;;++j)
void
grind(string_view s, bool good)
{
error_code ex;
{
if(! BEAST_EXPECT(j < 100000))
break;
error_code ec;
fail_parser p(j);
fail_parser p;
p.write(
s.data(), s.size(), ec);
if(ec == error::test_failure)
continue;
BEAST_EXPECTS(ec == ex,
ec.message());
break;
s.data(),
s.size(),
ex);
if(good)
{
if(! BEAST_EXPECTS(
! ex, ex.message()))
return;
}
else
{
if(! BEAST_EXPECT(ex))
return;
}
}
split_grind(s, ex);
throw_grind(s, ex);
fail_grind(s, ex);
}
void
@@ -122,12 +154,40 @@ public:
good("{}");
good("{ }");
good("{ \t }");
good("{\"x\":null}");
good("{ \"x\":null}");
good("{\"x\" :null}");
good("{\"x\": null}");
good("{\"x\":null }");
good("{ \"x\" : null }");
good("{ \"x\" : {} }");
good("{ \"x\" : [] }");
good("{ \"x\" : { \"y\" : null } }");
good("{ \"x\" : [{}] }");
good("{ \"x\":1, \"y\":null}");
good("{\"x\":1,\"y\":2,\"z\":3}");
good(" {\"x\":1,\"y\":2,\"z\":3}");
good("{\"x\":1,\"y\":2,\"z\":3} ");
good(" {\"x\":1,\"y\":2,\"z\":3} ");
good("{ \"x\":1,\"y\":2,\"z\":3}");
good("{\"x\" :1,\"y\":2,\"z\":3}");
good("{\"x\":1 ,\"y\":2,\"z\":3}");
good("{\"x\":1,\"y\" :2,\"z\":3}");
good("{\"x\":1,\"y\": 2,\"z\":3}");
good("{\"x\":1,\"y\":2 ,\"z\":3}");
good("{\"x\":1,\"y\":2, \"z\":3}");
good("{\"x\":1,\"y\":2, \"z\" :3}");
good("{\"x\":1,\"y\":2, \"z\": 3}");
good("{\"x\":1,\"y\":2, \"z\":3 }");
good(" \t { \"x\" \n : 1, \"y\" :2, \"z\" : 3} \n");
good("[{\"x\":[{\"y\":null}]}]");
bad ("{");
bad (" {");
bad (" {}}");
bad ("{{}}");
bad ("{[]}");
}
void
@@ -140,7 +200,23 @@ public:
good("[ \" \" ]");
good("[ \"x\" ]");
good("[ \"x\", \"y\" ]");
good("[1,2,3]");
good(" [1,2,3]");
good("[1,2,3] ");
good(" [1,2,3] ");
good("[1,2,3]");
good("[ 1,2,3]");
good("[1 ,2,3]");
good("[1, 2,3]");
good("[1,2 ,3]");
good("[1,2, 3]");
good("[1,2,3 ]");
good(" [ 1 , 2 \t\n , \n3]");
bad ("[");
bad (" [");
bad (" []]");
bad ("[{]");
bad ("[ \"x\", ]");
}
@@ -152,37 +228,14 @@ public:
good("\"" "x y" "\"");
bad ("\"" "\t" "\"");
// control after escape
bad ("\"\\\\\n\"");
}
void
testNumber()
{
#if 0
auto const test =
[]( string_view s,
decltype(ieee_decimal::mantissa) m,
decltype(ieee_decimal::exponent) e,
bool sign)
{
auto const dec = parse_ieee_decimal(s);
BEAST_EXPECTS(dec.mantissa == m, "mantissa=" + std::to_string(dec.mantissa));
BEAST_EXPECTS(dec.exponent == e, "exponent=" + std::to_string(dec.exponent));
BEAST_EXPECTS(dec.sign == sign, "sign=" + std::to_string(sign));
};
test(" 0", 0, 0, false);
test(" 1e2", 1, 2, false);
test(" 1E2", 1, 2, false);
test("-1E2", 1, 2, true);
test("-1E-2", 1, -2, true);
test(" 9223372036854775807", 9223372036854775807, 0, false);
test("-9223372036854775807", 9223372036854775807, 0, true);
test(" 18446744073709551615", 18446744073709551615ULL, 0, false);
test("-18446744073709551615", 18446744073709551615ULL, 0, true);
test("1.0", 10, -1, false);
#endif
good("0");
good("0.0");
good("0.10");
@@ -206,6 +259,14 @@ public:
good("-1");
good("-1e1");
good("1.1e309");
good( "9223372036854775807");
good( "-9223372036854775807");
good( "18446744073709551615");
good( "-18446744073709551615");
good( "[9223372036854775807]");
good( "[-9223372036854775807]");
good( "[18446744073709551615]");
good("[-18446744073709551615]");
bad ("");
bad ("-");
@@ -281,6 +342,149 @@ public:
bad ("n");
}
void
testParser()
{
auto const check =
[]( string_view s,
bool is_done)
{
fail_parser p;
error_code ec;
p.write_some(
s.data(), s.size(),
ec);
if(! BEAST_EXPECTS(! ec,
ec.message()))
return;
BEAST_EXPECT(is_done ==
p.is_done());
};
// is_done()
check("{}", false);
check("{} ", false);
check("{}x", true);
check("{} x", true);
check("[]", false);
check("[] ", false);
check("[]x", true);
check("[] x", true);
check("\"a\"", false);
check("\"a\" ", false);
check("\"a\"x", true);
check("\"a\" x", true);
check("0", false);
check("0 ", false);
check("0x", true);
check("0 x", true);
check("00", true);
check("0.", false);
check("0.0", false);
check("0.0 ", false);
check("0.0 x", true);
check("true", false);
check("true ", false);
check("truex", true);
check("true x", true);
check("false", false);
check("false ", false);
check("falsex", true);
check("false x", true);
check("null", false);
check("null ", false);
check("nullx", true);
check("null x", true);
// depth(), max_depth(), is_done()
{
{
error_code ec;
fail_parser p;
BEAST_EXPECT(
p.depth() == 0);
BEAST_EXPECT(
p.max_depth() > 0);
p.max_depth(1);
p.write("[{}]", 4, ec);
BEAST_EXPECTS(
ec == error::too_deep,
ec.message());
BEAST_EXPECT(! p.is_done());
}
{
error_code ec;
fail_parser p;
BEAST_EXPECT(
p.max_depth() > 0);
p.max_depth(1);
p.write_some("[", 1, ec);
BEAST_EXPECT(p.depth() == 1);
if(BEAST_EXPECTS(! ec,
ec.message()))
{
p.write_some("{", 1, ec);
BEAST_EXPECTS(
ec == error::too_deep,
ec.message());
}
BEAST_EXPECT(! p.is_done());
ec = {};
p.write_some("{}", 2, ec);
BEAST_EXPECT(ec);
p.reset();
p.write("{}", 2, ec);
BEAST_EXPECTS(! ec, ec.message());
BEAST_EXPECT(p.is_done());
}
}
// maybe_flush
{
// VFALCO This must be equal to the size
// of the temp buffer used in write_some.
//
int constexpr BUFFER_SIZE = 2048;
{
for(auto esc :
{ "\\\"", "\\\\", "\\/", "\\b",
"\\f", "\\n", "\\r", "\\t", "\\u0000" })
{
std::string big;
big = "\\\"" + std::string(BUFFER_SIZE-4, '*') + esc;
std::string s;
s = "{\"" + big + "\":\"" + big + "\"}";
fail_grind(s);
}
}
{
std::string big;
big = "\\\"" +
std::string(BUFFER_SIZE + 1, '*');
std::string s;
s = "{\"" + big + "\":\"" + big + "\"}";
fail_grind(s);
}
}
// no input
{
error_code ec;
fail_parser p;
p.write_eof(ec);
BEAST_EXPECT(ec);
}
}
void
testParseVectors()
{
@@ -319,7 +523,7 @@ public:
testNumber();
testBoolean();
testNull();
testParser();
testParseVectors();
}
};