json/test/basic_parser.cpp
2019-11-10 14:47:22 -08:00

331 lines
7.3 KiB
C++

//
// 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 <boost/json/basic_parser.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include "test.hpp"
#include "parse-vectors.hpp"
namespace boost {
namespace json {
class basic_parser_test : public beast::unit_test::suite
{
public:
void
grind(string_view s, bool good)
{
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;
i < s.size(); ++i)
{
if(! BEAST_EXPECT(i < 100000))
break;
error_code ec;
fail_parser p;
p.write_some(s.data(), i, ec);
if(ec == ex)
continue;
if(! BEAST_EXPECTS(
! ec, ec.message()))
continue;
p.write(
s.data() + i,
s.size() - i, ec);
BEAST_EXPECTS(ec == ex,
ec.message());
}
// exercise all exception paths
for(std::size_t j = 1;;++j)
{
if(! BEAST_EXPECT(j < 100000))
break;
error_code ec;
throw_parser p(j);
try
{
p.write(
s.data(), s.size(), ec);
BEAST_EXPECTS(ec == ex,
ec.message());
break;
}
catch(test_exception const&)
{
continue;
}
catch(std::exception const& e)
{
BEAST_FAIL();
log << " " <<
e.what() << std::endl;
}
}
// 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
good(string_view s)
{
grind(s, true);
}
void
bad(string_view s)
{
grind(s, false);
}
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()
{
#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");
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");
good("1.1e309");
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;
for(auto const& v : pv)
{
if(v.result == 'i')
{
error_code ec;
fail_parser p;
p.write(
v.text.data(),
v.text.size(),
ec);
grind(v.text,
ec ? false : true);
continue;
}
if(v.result == 'y')
grind(v.text, true);
else
grind(v.text, false);
}
}
void
run() override
{
log <<
"sizeof(basic_parser) == " <<
sizeof(basic_parser) << "\n";
testObject();
testArray();
testString();
testNumber();
testBoolean();
testNull();
testParseVectors();
}
};
BEAST_DEFINE_TESTSUITE(boost,json,basic_parser);
} // json
} // boost