json/test/serializer.cpp
2020-08-27 13:48:26 -07:00

520 lines
13 KiB
C++

//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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/cppalliance/json
//
// Test that header file is self-contained.
#include <boost/json/serializer.hpp>
#include <boost/json/parse.hpp>
#include <boost/json/to_string.hpp>
#include <iostream>
#include "parse-vectors.hpp"
#include "test.hpp"
#include "test_suite.hpp"
namespace boost {
namespace json {
class serializer_test
{
public:
::test_suite::log_type log;
void
grind_one(
string_view s,
value const& jv,
string_view name = {})
{
{
error_code ec;
auto const s1 = to_string(jv);
auto const jv2 = parse(s1, ec);
if(! BOOST_TEST(equal(jv, jv2)))
{
if(name.empty())
log <<
" " << s << "\n"
" " << s1 <<
std::endl;
else
log << name << ":\n"
" " << s << "\n"
" " << s1 <<
std::endl;
}
}
// large buffer
{
error_code ec;
serializer sr(jv);
string js;
js.reserve(4096);
js.grow(sr.read(
js.data(), js.capacity()));
auto const s1 = to_string(jv);
auto const jv2 = parse(s1, ec);
BOOST_TEST(equal(jv, jv2));
}
}
void
grind(
string_view s0,
value const& jv,
string_view name = {})
{
grind_one(s0, jv, name);
auto const s1 =
to_string(jv);
for(std::size_t i = 1;
i < s1.size(); ++i)
{
serializer sr(jv);
string s2;
s2.reserve(s1.size());
s2.grow(sr.read(
s2.data(), i));
auto const dump =
[&]
{
if(name.empty())
log <<
" " << s0 << "\n"
" " << s1 << "\n"
" " << s2 << std::endl;
else
log << name << ":\n"
" " << s0 << "\n"
" " << s1 << "\n"
" " << s2 << std::endl;
};
if(! BOOST_TEST(
s2.size() == i))
{
dump();
break;
}
s2.grow(sr.read(
s2.data() + i,
s1.size() - i));
if(! BOOST_TEST(
s2.size() == s1.size()))
{
dump();
break;
}
if(! BOOST_TEST(s2 == s1))
{
dump();
break;
}
}
}
//------------------------------------------------------
void
testNull()
{
check("null");
}
void
testBoolean()
{
check("true");
check("false");
}
void
testString()
{
check("\"\"");
check("\"x\"");
check("\"xyz\"");
check("\"x z\"");
// escapes
check("\"\\\"\""); // double quote
check("\"\\\\\""); // backslash
check("\"\\b\""); // backspace
check("\"\\f\""); // formfeed
check("\"\\n\""); // newline
check("\"\\r\""); // carriage return
check("\"\\t\""); // horizontal tab
// control characters
check("\"\\u0000\"");
check("\"\\u0001\"");
check("\"\\u0002\"");
check("\"\\u0003\"");
check("\"\\u0004\"");
check("\"\\u0005\"");
check("\"\\u0006\"");
check("\"\\u0007\"");
check("\"\\u0008\"");
check("\"\\u0009\"");
check("\"\\u000a\"");
check("\"\\u000b\"");
check("\"\\u000c\"");
check("\"\\u000d\"");
check("\"\\u000e\"");
check("\"\\u000f\"");
check("\"\\u0010\"");
check("\"\\u0011\"");
check("\"\\u0012\"");
check("\"\\u0013\"");
check("\"\\u0014\"");
check("\"\\u0015\"");
check("\"\\u0016\"");
check("\"\\u0017\"");
check("\"\\u0018\"");
check("\"\\u0019\"");
check("\"\\u0020\"");
check("\"\\u0021\"");
}
void
testNumber()
{
// VFALCO These don't perfectly round-trip,
// because the representations are not exact.
// The test needs to do a better job of comparison.
check("-999999999999999999999");
check("-100000000000000000009");
check("-10000000000000000000");
//check("-9223372036854775809");
check("-9223372036854775808");
check("-9223372036854775807");
check("-999999999999999999");
check("-99999999999999999");
check("-9999999999999999");
check("-999999999999999");
check("-99999999999999");
check("-9999999999999");
check("-999999999999");
check("-99999999999");
check("-9999999999");
check("-999999999");
check("-99999999");
check("-9999999");
check("-999999");
check("-99999");
check("-9999");
check("-999");
check("-99");
check("-9");
check("-0");
check("-0.0");
check( "0");
check( "9");
check( "99");
check( "999");
check( "9999");
check( "99999");
check( "999999");
check( "9999999");
check( "99999999");
check( "999999999");
check( "9999999999");
check( "99999999999");
check( "999999999999");
check( "9999999999999");
check( "99999999999999");
check( "999999999999999");
check( "9999999999999999");
check( "99999999999999999");
check( "999999999999999999");
check( "9223372036854775807");
check( "9223372036854775808");
check( "9999999999999999999");
check( "18446744073709551615");
//check( "18446744073709551616");
check( "99999999999999999999");
check( "999999999999999999999");
check( "1000000000000000000000");
check( "9999999999999999999999");
check( "99999999999999999999999");
//check("-0.9999999999999999999999");
check("-0.9999999999999999");
//check("-0.9007199254740991");
//check("-0.999999999999999");
//check("-0.99999999999999");
//check("-0.9999999999999");
//check("-0.999999999999");
//check("-0.99999999999");
//check("-0.9999999999");
//check("-0.999999999");
//check("-0.99999999");
//check("-0.9999999");
//check("-0.999999");
//check("-0.99999");
//check("-0.9999");
//check("-0.8125");
//check("-0.999");
//check("-0.99");
check("-1.0");
check("-0.9");
check("-0.0");
check( "0.0");
check( "0.9");
//check( "0.99");
//check( "0.999");
//check( "0.8125");
//check( "0.9999");
//check( "0.99999");
//check( "0.999999");
//check( "0.9999999");
//check( "0.99999999");
//check( "0.999999999");
//check( "0.9999999999");
//check( "0.99999999999");
//check( "0.999999999999");
//check( "0.9999999999999");
//check( "0.99999999999999");
//check( "0.999999999999999");
//check( "0.9007199254740991");
check( "0.9999999999999999");
//check( "0.9999999999999999999999");
//check( "0.999999999999999999999999999");
check("-1e308");
check("-1e-308");
//check("-9999e300");
//check("-999e100");
//check("-99e10");
check("-9e1");
check( "9e1");
//check( "99e10");
//check( "999e100");
//check( "9999e300");
check( "999999999999999999.0");
check( "999999999999999999999.0");
check( "999999999999999999999e5");
check( "999999999999999999999.0e5");
check("-1e-1");
check("-1e0");
check("-1e1");
check( "0e0");
check( "1e0");
check( "1e10");
}
void
testArray()
{
check("[]");
check("[[]]");
check("[[],[],[]]");
check("[[[[[[[[[[]]]]]]]]]]");
check("[{}]");
check("[{},{}]");
check("[1,2,3,4,5]");
check("[true,false,null]");
}
void
testObject()
{
check("{}");
check("{\"x\":1}");
check("{\"x\":[]}");
check("{\"x\":1,\"y\":null}");
}
//------------------------------------------------------
void
testMembers()
{
value jv;
// serializer()
{
serializer sr;
}
// serializer(value)
{
serializer sr(jv);
}
// is_done()
{
serializer sr(jv);
BOOST_TEST(! sr.is_done());
}
// read()
{
{
serializer sr(jv);
char buf[1024];
auto n = sr.read(
buf, sizeof(buf));
BOOST_TEST(sr.is_done());
BOOST_TEST(string_view(
buf, n) == "null");
}
{
char buf[32];
serializer sr;
BOOST_TEST_THROWS(
sr.read(buf, sizeof(buf)),
std::logic_error);
}
}
}
void
check(
string_view s,
string_view name = {})
{
try
{
auto const jv = parse(s);
grind(s, jv, name);
}
catch(std::exception const&)
{
BOOST_TEST_FAIL();
}
}
void
testVectors()
{
#if 0
check(
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");
#endif
parse_vectors const pv;
for(auto const e : pv)
{
if(e.result != 'y')
continue;
// skip these failures for now
if(
e.name == "number" ||
e.name == "number_real_exponent" ||
e.name == "number_real_fraction_exponent" ||
e.name == "number_simple_real" ||
e.name == "object_extreme_numbers" ||
e.name == "pass01"
)
continue;
check(e.text, e.name);
}
}
std::string
to_ostream(value const& jv)
{
std::stringstream ss;
ss << jv;
return ss.str();
}
void
testOstream()
{
for(string_view js : {
#if 0
"{\"1\":{},\"2\":[],\"3\":\"x\",\"4\":1,"
"\"5\":-1,\"6\":144.0,\"7\":false,\"8\":null}",
#endif
"[1,2,3,4,5]"
})
{
error_code ec;
auto const jv1 = parse(js, ec);
if(! BOOST_TEST(! ec))
return;
auto const jv2 =
parse(to_ostream(jv1), ec);
if(! BOOST_TEST(! ec))
return;
if(! BOOST_TEST(equal(jv1, jv2)))
log <<
" " << js << "\n"
" " << jv1 << "\n"
" " << jv2 <<
std::endl;
}
}
void
testNumberRoundTrips()
{
BOOST_TEST(std::signbit(parse("-0.0").as_double()));
BOOST_TEST(to_string(value(-0.0)) == "-0E0");
//BOOST_TEST(parse("-0.0").as_double() == -0);
//BOOST_TEST(parse("-0").as_int64() == 0);
//BOOST_TEST(to_string(parse("0.0")) == "0");
//BOOST_TEST(to_string(parse("-0.0")) == "-0.0");
// VFALCO Peter is unsure what this should do
//BOOST_TEST(to_string(parse("-0")) == "-0");
}
void
run()
{
testNull();
testBoolean();
testString();
testNumber();
testArray();
testObject();
testMembers();
testVectors();
testOstream();
testNumberRoundTrips();
}
};
TEST_SUITE(serializer_test, "boost.json.serializer");
} // json
} // boost