boost/libs/json/test/limits.cpp
2021-10-05 21:37:46 +02:00

393 lines
11 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/boostorg/json
//
#include <boost/json/array.hpp>
#include <boost/json/object.hpp>
#include <boost/json/string.hpp>
#include <boost/json/value.hpp>
#include <boost/json/parse.hpp>
#include <boost/json/stream_parser.hpp>
#include <vector>
#include "test_suite.hpp"
#include "test.hpp"
BOOST_JSON_NS_BEGIN
/*
This translation unit exercises code paths
related to library limits such as max string
length.
*/
class limits_test
{
public:
void
testValue()
{
// object too large
{
std::initializer_list<std::pair<
string_view, value_ref>> init = {
{ "1", 1},{ "2", 2},{ "3", 3},{ "4", 4},{ "5", 5},
{ "6", 6},{ "7", 7},{ "8", 8},{ "9", 9},{"10",10},
{"11",11},{"12",12},{"13",13},{"14",14},{"15",15},
{"16",16},{"17",17},{"18",18},{"19",19},{"10",10},
{"21",21},{"22",22},{"23",23},{"24",24},{"25",25},
{"26",26},{"27",27},{"28",28},{"29",29},{"30",30},
{"31",31}};
BOOST_TEST(init.size() > object::max_size());
BOOST_TEST_THROWS(value{init}, std::length_error);
}
}
void
testObject()
{
// max_size()
{
BOOST_TEST_THROWS(
object(object::max_size()+1),
std::length_error);
}
// object(), max size
{
std::initializer_list<std::pair<
string_view, value_ref>> init = {
{ "1", 1},{ "2", 2},{ "3", 3},{ "4", 4},{ "5", 5},
{ "6", 6},{ "7", 7},{ "8", 8},{ "9", 9},{"10",10},
{"11",11},{"12",12},{"13",13},{"14",14},{"15",15},
{"16",16},{"17",17},{"18",18},{"19",19},{"10",10},
{"21",21},{"22",22},{"23",23},{"24",24},{"25",25},
{"26",26},{"27",27},{"28",28},{"29",29},{"30",30},
{"31",31}};
BOOST_TEST(init.size() > object::max_size());
BOOST_TEST_THROWS(
object(init),
std::length_error);
BOOST_TEST_THROWS(
object(init.begin(), init.end()),
std::length_error);
BOOST_TEST_THROWS(
object(
make_input_iterator(init.begin()),
make_input_iterator(init.end())),
std::length_error);
}
// reserve(), max size
{
object o;
BOOST_TEST_THROWS(
o.reserve(o.max_size() + 1),
std::length_error);
}
// insert(), max size
{
std::initializer_list<std::pair<
string_view, value_ref>> init = {
{ "1", 1},{ "2", 2},{ "3", 3},{ "4", 4},{ "5", 5},
{ "6", 6},{ "7", 7},{ "8", 8},{ "9", 9},{"10",10},
{"11",11},{"12",12},{"13",13},{"14",14},{"15",15},
{"16",16},{"17",17},{"18",18},{"19",19},{"10",10},
{"21",21},{"22",22},{"23",23},{"24",24},{"25",25},
{"26",26},{"27",27},{"28",28},{"29",29},{"30",30},
{"31",31}};
BOOST_TEST(init.size() > object::max_size());
object o;
BOOST_TEST_THROWS(
o.insert(init),
std::length_error);
BOOST_TEST_THROWS(
o.insert(init.begin(), init.end()),
std::length_error);
BOOST_TEST_THROWS(
o.insert(
make_input_iterator(init.begin()),
make_input_iterator(init.end())),
std::length_error);
}
// max key size
{
std::string const big(
string::max_size() + 1, '*');
BOOST_TEST_THROWS(
object({ {big, nullptr} }),
std::length_error);
}
// reserve
{
object obj;
BOOST_TEST_THROWS(
obj.reserve(object::max_size() + 1),
std::length_error);
}
}
void
testArray()
{
{
BOOST_TEST_THROWS(
array(
array::max_size()+1,
value(nullptr)),
std::length_error);
}
{
std::vector<int> v(
array::max_size()+1, 42);
BOOST_TEST_THROWS(
array(v.begin(), v.end()),
std::length_error);
}
{
std::vector<int> v(
array::max_size()+1, 42);
BOOST_TEST_THROWS(array(
make_input_iterator(v.begin()),
make_input_iterator(v.end())),
std::length_error);
}
{
array a;
BOOST_TEST_THROWS(
a.insert(a.begin(),
array::max_size() + 1,
nullptr),
std::length_error);
}
}
void
testString()
{
// strings
{
{
string s;
BOOST_TEST_THROWS(
(s.resize(s.max_size() + 1)),
std::length_error);
}
{
string s;
s.resize(100);
BOOST_TEST_THROWS(
(s.append(s.max_size() - 1, '*')),
std::length_error);
}
{
string s;
s.resize(s.max_size() - 5);
BOOST_TEST_THROWS(
(s.replace(0, 1, s.subview(0, 10))),
std::length_error);
}
{
string s;
s.resize(s.max_size() - 5);
BOOST_TEST_THROWS(
(s.replace(0, 1, 10, 'a')),
std::length_error);
}
{
string s;
s.resize(s.max_size() - 5);
BOOST_TEST_THROWS(
(s.insert(0, s.subview(0, 10))),
std::length_error);
}
#if 0
{
// VFALCO tsan doesn't like this
string s;
try
{
s.resize(s.max_size() - 1);
}
catch(std::exception const&)
{
}
}
#endif
}
// string in parser
{
stream_parser p;
std::string const big(
string::max_size() + 1, '*');
auto const js =
"\"" + big + "\":null";
error_code ec;
auto jv = parse(js, ec);
BOOST_TEST(ec == error::string_too_large);
}
// key in parser
{
stream_parser p;
std::string const big(
string::max_size() + 1, '*');
auto const js =
"{\"" + big + "\":null}";
error_code ec;
auto jv = parse(js, ec);
BOOST_TEST(ec == error::key_too_large);
}
}
void
testParser()
{
// string buffer flush
{
string_view s =
"\"\\na\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"
"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\"";
error_code ec;
auto jv = parse(s, ec);
BOOST_TEST(! ec);
}
// overflow in on_key_part
{
error_code ec;
std::string big;
big = "\\b";
big += std::string(
string::max_size()*2, '*');
auto const js =
"{\"" + big + "\":null}";
auto jv = parse(js, ec);
BOOST_TEST(ec == error::key_too_large);
}
// overflow in on_key
{
error_code ec;
std::string big;
big = "\\b";
big += std::string(
(string::max_size()*3)/2, '*');
auto const js =
"{\"" + big + "\":null}";
auto jv = parse(js, ec);
BOOST_TEST(ec == error::key_too_large);
}
// overflow in on_string_part
{
error_code ec;
std::string big;
big = "\\b";
big += std::string(
string::max_size()*2, '*');
auto const js =
"\"" + big + "\"";
auto jv = parse(js, ec);
BOOST_TEST(ec == error::string_too_large);
}
// overflow in on_string
{
error_code ec;
std::string big;
big = "\\b";
big += std::string(
(string::max_size()*3)/2, '*');
auto const js =
"\"" + big + "\"";
auto jv = parse(js, ec);
BOOST_TEST(ec == error::string_too_large);
}
// object overflow
{
error_code ec;
string_view s = R"({
"00":0,"01":0,"02":0,"03":0,"04":0,"05":0,"06":0,"07":0,"08":0,"09":0,
"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,
"20":0
})";
auto jv = parse(s, ec);
BOOST_TEST(ec == error::object_too_large);
}
// array overflow
{
error_code ec;
string_view s = "["
"0,0,0,0,0,0,0,0,0,0,"
"0,0,0,0,0,0,0,0,0,0,"
"0"
"]";
auto jv = parse(s, ec);
BOOST_TEST(ec == error::array_too_large);
}
}
void
run()
{
#if ! defined(BOOST_JSON_NO_MAX_STRUCTURED_SIZE) && \
! defined(BOOST_JSON_NO_MAX_STRING_SIZE) && \
! defined(BOOST_JSON_NO_MAX_STACK_SIZE) && \
! defined(BOOST_JSON_NO_STACK_BUFFER_SIZE)
//testValue();
testObject();
testArray();
testString();
testParser();
#else
BOOST_TEST_PASS();
#endif
}
};
TEST_SUITE(limits_test, "boost.json.limits");
BOOST_JSON_NS_END