mirror of
https://github.com/boostorg/json.git
synced 2025-05-12 14:11:40 +00:00
403 lines
9.6 KiB
C++
403 lines
9.6 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 "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
|