json/test/parser.cpp
Vinnie Falco 68f3df0403 Tidy
2019-11-11 19:21:48 -08:00

358 lines
8.8 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/BeastLounge
//
// Test that header file is self-contained.
#include <boost/json/parser.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/json/parser.hpp>
#include <boost/json/serializer.hpp>
#include <sstream>
#include "parse-vectors.hpp"
#include "test.hpp"
namespace boost {
namespace json {
class parser_test : public beast::unit_test::suite
{
public:
value
from_string_test(
string_view s,
storage_ptr sp = {})
{
parser p;
error_code ec;
p.start(std::move(sp));
p.write(
s.data(),
s.size(),
ec);
BEAST_EXPECTS(! ec,
ec.message());
//log << " " << to_string_test(p.get()) << std::endl;
return p.release();
}
void
check_round_trip(
value const& jv1,
string_view s1)
{
auto const s2 =
//to_string_test(jv1); // use this if serializer is broken
to_string(jv1);
auto jv2 =
from_string_test(s2);
if(! BEAST_EXPECT(equal(jv1, jv2)))
log <<
" " << s1 << "\n" <<
" " << s2 << std::endl;
}
void
grind_one(string_view s)
{
auto const jv =
from_string_test(s);
check_round_trip(jv, s);
}
void
grind(string_view s)
{
grind_one(s);
fail_loop([&](storage_ptr const& sp)
{
auto const jv =
from_string_test(s, sp);
check_round_trip(jv, s);
});
if(s.size() > 1)
{
// Destroy the parser at every
// split point to check leaks.
for(std::size_t i = 1;
i < s.size(); ++i)
{
scoped_storage<
fail_storage> ss;
parser p;
error_code ec;
p.start(ss);
p.write(s.data(), i, ec);
}
}
}
void
legacyTests()
{
string_view in =
R"xx({
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
})xx"
;
parser p;
error_code ec;
p.start();
p.write(in.data(), in.size(), ec);
if(BEAST_EXPECTS(! ec, ec.message()))
{
BEAST_EXPECT(to_string_test(p.release()) ==
"{\"glossary\":{\"title\":\"example glossary\",\"GlossDiv\":"
"{\"title\":\"S\",\"GlossList\":{\"GlossEntry\":{\"ID\":\"SGML\","
"\"SortAs\":\"SGML\",\"GlossTerm\":\"Standard Generalized Markup "
"Language\",\"Acronym\":\"SGML\",\"Abbrev\":\"ISO 8879:1986\","
"\"GlossDef\":{\"para\":\"A meta-markup language, used to create "
"markup languages such as DocBook.\",\"GlossSeeAlso\":[\"GML\",\"XML\"]},"
"\"GlossSee\":\"markup\"}}}}}"
);
}
}
void
testObjects()
{
grind("{}");
grind("{\"\":[]}");
grind("{\"1\":[],\"2\":[]}");
grind(
"{\"1\":{\"2\":{}},\"3\":{\"4\":{},\"5\":{}},"
"\"6\":{\"7\":{},\"8\":{},\"9\":{}}}");
grind(
"{\"1\":{},\"2\":[],\"3\":\"x\",\"4\":1,"
"\"5\":-1,\"6\":1.0,\"7\":false,\"8\":null}");
// big strings
{
std::string const big(4000, '*');
{
std::string js;
js = "{\"" + big + "\":null}";
grind(js);
}
{
std::string js;
js = "{\"x\":\"" + big + "\"}";
grind(js);
}
{
std::string js;
js = "{\"" + big + "\":\"" + big + "\"}";
grind(js);
}
}
}
void
testArrays()
{
grind("[]");
grind("[[]]");
grind("[[],[]]");
grind("[[],[],[]]");
grind("[[[]],[[],[]],[[],[],[]]]");
grind("[{},[],\"x\",1,-1,1.0,true,null]");
}
void
testStrings()
{
grind("\"\"");
grind("\"x\"");
grind("\"\\\"\"");
grind("\"\\\\\"");
grind("\"\\/\"");
grind("\"\\b\"");
grind("\"\\f\"");
grind("\"\\n\"");
grind("\"\\r\"");
grind("\"\\t\"");
grind("\"\\u0000\"");
grind("\"xxxxxxxxxx\"");
grind("\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"");
grind("\""
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"\"");
// big string
{
std::string const big(4000, '*');
{
std::string js;
js = "\"" + big + "\"";
auto const N = js.size() / 2;
error_code ec;
parser p;
p.start();
p.write_some(js.data(), N, ec);
if(BEAST_EXPECTS(! ec,
ec.message()))
{
p.write(js.data() + N,
js.size() - N, ec);
if(BEAST_EXPECTS(! ec,
ec.message()))
check_round_trip(
p.release(), js);
}
}
}
}
void
testNumbers()
{
grind("-9223372036854775808"); // INT64_MIN
grind("-999999999999999999");
grind("-0");
grind( "0");
grind( "1");
grind( "999999999999999999");
grind( "9223372036854775807"); // INT64_MAX
grind( "9223372036854775808");
grind( "18446744073709551615"); // UINT64_MAX
grind("-1e-10");
grind( "1e-10");
grind( "1e+10");
grind( "1e+100");
}
void
testBool()
{
grind("true");
grind("false");
}
void
testNull()
{
grind("null");
}
void
testMembers()
{
// need start error
{
parser p;
error_code ec;
p.write("", 0, ec);
BEAST_EXPECTS(
ec == error::need_start,
ec.message());
}
}
//------------------------------------------------------
void
testFreeFunctions()
{
string_view const js =
"{\"1\":{},\"2\":[],\"3\":\"x\",\"4\":1,"
"\"5\":-1,\"6\":1.0,\"7\":false,\"8\":null}";
// parse(value)
{
{
check_round_trip(
parse(js),
js);
}
{
BEAST_THROWS(parse(
"{,"),
system_error);
}
}
// parse(value, storage_ptr)
{
check_round_trip(
parse(js, storage_ptr{}),
js);
}
// parse(value, error_code)
{
error_code ec;
auto jv = parse(js, ec);
BEAST_EXPECTS(! ec, ec.message());
check_round_trip(jv, js);
}
// parse(value, storage_ptr, error_code)
{
error_code ec;
auto jv = parse(js, storage_ptr{}, ec);
BEAST_EXPECTS(! ec, ec.message());
check_round_trip(jv, js);
}
}
void
run()
{
testObjects();
testArrays();
testStrings();
testNumbers();
testBool();
testNull();
testMembers();
testFreeFunctions();
// This still doesn't work..
//legacyTests();
}
};
BEAST_DEFINE_TESTSUITE(boost,json,parser);
} // json
} // boost