improved documentation and test coverage
This commit is contained in:
parent
7034ae2486
commit
6268287940
7 changed files with 105 additions and 24 deletions
|
@ -428,7 +428,7 @@ $ make
|
||||||
$ ./json_unit "*"
|
$ ./json_unit "*"
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
All tests passed (3344299 assertions in 29 test cases)
|
All tests passed (3344416 assertions in 30 test cases)
|
||||||
```
|
```
|
||||||
|
|
||||||
For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml).
|
For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml).
|
||||||
|
|
|
@ -31,4 +31,7 @@ int main()
|
||||||
|
|
||||||
// call flatten()
|
// call flatten()
|
||||||
std::cout << std::setw(4) << j.flatten() << '\n';
|
std::cout << std::setw(4) << j.flatten() << '\n';
|
||||||
|
|
||||||
|
// flatten for a primitive value
|
||||||
|
std::cout << j["pi"].flatten() << '\n';
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/kODXfzcksgstdBRD"><b>online</b></a>
|
<a target="_blank" href="http://melpon.org/wandbox/permlink/skGi8b32VhI8HOgV"><b>online</b></a>
|
|
@ -14,3 +14,4 @@
|
||||||
"/object/~1": "slash",
|
"/object/~1": "slash",
|
||||||
"/pi": 3.141
|
"/pi": 3.141
|
||||||
}
|
}
|
||||||
|
{"":3.141}
|
||||||
|
|
58
src/json.hpp
58
src/json.hpp
|
@ -3273,8 +3273,8 @@ class basic_json
|
||||||
|
|
||||||
@return reference to the element at index @a idx
|
@return reference to the element at index @a idx
|
||||||
|
|
||||||
@throw std::domain_error if JSON is not an array or null; example: `"cannot
|
@throw std::domain_error if JSON is not an array or null; example:
|
||||||
use operator[] with string"`
|
`"cannot use operator[] with string"`
|
||||||
|
|
||||||
@complexity Constant if @a idx is in the range of the array. Otherwise
|
@complexity Constant if @a idx is in the range of the array. Otherwise
|
||||||
linear in `idx - size()`.
|
linear in `idx - size()`.
|
||||||
|
@ -3620,7 +3620,9 @@ class basic_json
|
||||||
|
|
||||||
@complexity Linear in the length of the JSON pointer.
|
@complexity Linear in the length of the JSON pointer.
|
||||||
|
|
||||||
@throw std::out_of_range if the JSON pointer can not be resolved
|
@throw std::out_of_range if the JSON pointer can not be resolved
|
||||||
|
@throw std::domain_error if an array index begins with '0'
|
||||||
|
@throw std::invalid_argument if an array index was not a number
|
||||||
|
|
||||||
@liveexample{The behavior is shown in the example.,operatorjson_pointer}
|
@liveexample{The behavior is shown in the example.,operatorjson_pointer}
|
||||||
|
|
||||||
|
@ -3645,8 +3647,9 @@ class basic_json
|
||||||
|
|
||||||
@complexity Linear in the length of the JSON pointer.
|
@complexity Linear in the length of the JSON pointer.
|
||||||
|
|
||||||
@throw std::out_of_range if the JSON pointer can not be resolved
|
@throw std::out_of_range if the JSON pointer can not be resolved
|
||||||
@throw std::out_of_range if the special value `-` is used for an array
|
@throw std::domain_error if an array index begins with '0'
|
||||||
|
@throw std::invalid_argument if an array index was not a number
|
||||||
|
|
||||||
@liveexample{The behavior is shown in the example.,
|
@liveexample{The behavior is shown in the example.,
|
||||||
operatorjson_pointer_const}
|
operatorjson_pointer_const}
|
||||||
|
@ -8923,9 +8926,12 @@ basic_json_parser_63:
|
||||||
empty string is assumed which references the whole JSON
|
empty string is assumed which references the whole JSON
|
||||||
value
|
value
|
||||||
|
|
||||||
@throw std::domain_error if reference token is nonempty and does not
|
@throw std::domain_error if reference token is nonempty and does not
|
||||||
begin with a slash (`/`), or if a tilde (`~`) is not followed
|
begin with a slash (`/`); example: `"JSON pointer must be empty or
|
||||||
by `0` (representing `~`) or `1` (representing `/`).
|
begin with /"`
|
||||||
|
@throw std::domain_error if a tilde (`~`) is not followed by `0`
|
||||||
|
(representing `~`) or `1` (representing `/`); example: `"escape error:
|
||||||
|
~ must be followed with 0 or 1"`
|
||||||
|
|
||||||
@liveexample{The example shows the construction several valid JSON
|
@liveexample{The example shows the construction several valid JSON
|
||||||
pointers as well as the exceptional behavior.,json_pointer}
|
pointers as well as the exceptional behavior.,json_pointer}
|
||||||
|
@ -8944,6 +8950,8 @@ basic_json_parser_63:
|
||||||
{
|
{
|
||||||
pointer result = &j;
|
pointer result = &j;
|
||||||
|
|
||||||
|
// in case no reference tokens exist, return a reference to the
|
||||||
|
// JSON value j which will be overwritten by a primitive value
|
||||||
for (const auto& reference_token : reference_tokens)
|
for (const auto& reference_token : reference_tokens)
|
||||||
{
|
{
|
||||||
switch (result->m_type)
|
switch (result->m_type)
|
||||||
|
@ -8952,10 +8960,12 @@ basic_json_parser_63:
|
||||||
{
|
{
|
||||||
if (reference_token == "0")
|
if (reference_token == "0")
|
||||||
{
|
{
|
||||||
|
// start a new array if reference token is 0
|
||||||
result = &result->operator[](0);
|
result = &result->operator[](0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// start a new object otherwise
|
||||||
result = &result->operator[](reference_token);
|
result = &result->operator[](reference_token);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -8963,19 +8973,38 @@ basic_json_parser_63:
|
||||||
|
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
|
// create an entry in the object
|
||||||
result = &result->operator[](reference_token);
|
result = &result->operator[](reference_token);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case value_t::array:
|
case value_t::array:
|
||||||
{
|
{
|
||||||
|
// create an entry in the array
|
||||||
result = &result->operator[](static_cast<size_t>(std::stoi(reference_token)));
|
result = &result->operator[](static_cast<size_t>(std::stoi(reference_token)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This function is only to be called from the unflatten()
|
||||||
|
function. There, j is initially of type null.
|
||||||
|
|
||||||
|
- In case the reference tokens are empty, a reference to
|
||||||
|
j is returned and overwritten by the desired value by
|
||||||
|
the unflatten() function.
|
||||||
|
- If there are reference tokens, the null value of j will
|
||||||
|
be changed to an object or array after reading the first
|
||||||
|
reference token.
|
||||||
|
- All subsequent tokens work on arrays or objects and will
|
||||||
|
not change the type of j.
|
||||||
|
|
||||||
|
Consequently, the type of @a j will always be null,
|
||||||
|
object, or array. Hence, the following line is
|
||||||
|
unreachable.
|
||||||
|
*/
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
throw std::domain_error("unresolved reference token '" + reference_token + "'");
|
break; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9361,7 +9390,11 @@ basic_json_parser_63:
|
||||||
throw std::domain_error("values in object must be primitive");
|
throw std::domain_error("values in object must be primitive");
|
||||||
}
|
}
|
||||||
|
|
||||||
// assign value to reference pointed to by JSON pointer
|
// assign value to reference pointed to by JSON pointer;
|
||||||
|
// Note that if the JSON pointer is "" (i.e., points to the
|
||||||
|
// whole value), function get_and_create returns a reference
|
||||||
|
// to result itself. An assignment will then create a
|
||||||
|
// primitive value.
|
||||||
json_pointer(element.first).get_and_create(result) = element.second;
|
json_pointer(element.first).get_and_create(result) = element.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9390,7 +9423,8 @@ basic_json_parser_63:
|
||||||
|
|
||||||
@return an object that maps JSON pointers to primitve values
|
@return an object that maps JSON pointers to primitve values
|
||||||
|
|
||||||
@note Empty objects and arrays are flattened to `null`.
|
@note Empty objects and arrays are flattened to `null` and will not be
|
||||||
|
reconstructed correctly by the @ref unflatten() function.
|
||||||
|
|
||||||
@complexity Linear in the size the JSON value.
|
@complexity Linear in the size the JSON value.
|
||||||
|
|
||||||
|
@ -9428,6 +9462,8 @@ basic_json_parser_63:
|
||||||
|
|
||||||
@complexity Linear in the size the JSON value.
|
@complexity Linear in the size the JSON value.
|
||||||
|
|
||||||
|
@throws std::domain_error
|
||||||
|
|
||||||
@liveexample{The following code shows how a flattened JSON object is
|
@liveexample{The following code shows how a flattened JSON object is
|
||||||
unflattened into the original nested JSON object.,unflatten}
|
unflattened into the original nested JSON object.,unflatten}
|
||||||
|
|
||||||
|
|
|
@ -3273,8 +3273,8 @@ class basic_json
|
||||||
|
|
||||||
@return reference to the element at index @a idx
|
@return reference to the element at index @a idx
|
||||||
|
|
||||||
@throw std::domain_error if JSON is not an array or null; example: `"cannot
|
@throw std::domain_error if JSON is not an array or null; example:
|
||||||
use operator[] with string"`
|
`"cannot use operator[] with string"`
|
||||||
|
|
||||||
@complexity Constant if @a idx is in the range of the array. Otherwise
|
@complexity Constant if @a idx is in the range of the array. Otherwise
|
||||||
linear in `idx - size()`.
|
linear in `idx - size()`.
|
||||||
|
@ -3620,7 +3620,9 @@ class basic_json
|
||||||
|
|
||||||
@complexity Linear in the length of the JSON pointer.
|
@complexity Linear in the length of the JSON pointer.
|
||||||
|
|
||||||
@throw std::out_of_range if the JSON pointer can not be resolved
|
@throw std::out_of_range if the JSON pointer can not be resolved
|
||||||
|
@throw std::domain_error if an array index begins with '0'
|
||||||
|
@throw std::invalid_argument if an array index was not a number
|
||||||
|
|
||||||
@liveexample{The behavior is shown in the example.,operatorjson_pointer}
|
@liveexample{The behavior is shown in the example.,operatorjson_pointer}
|
||||||
|
|
||||||
|
@ -3645,8 +3647,9 @@ class basic_json
|
||||||
|
|
||||||
@complexity Linear in the length of the JSON pointer.
|
@complexity Linear in the length of the JSON pointer.
|
||||||
|
|
||||||
@throw std::out_of_range if the JSON pointer can not be resolved
|
@throw std::out_of_range if the JSON pointer can not be resolved
|
||||||
@throw std::out_of_range if the special value `-` is used for an array
|
@throw std::domain_error if an array index begins with '0'
|
||||||
|
@throw std::invalid_argument if an array index was not a number
|
||||||
|
|
||||||
@liveexample{The behavior is shown in the example.,
|
@liveexample{The behavior is shown in the example.,
|
||||||
operatorjson_pointer_const}
|
operatorjson_pointer_const}
|
||||||
|
@ -8233,9 +8236,12 @@ class basic_json
|
||||||
empty string is assumed which references the whole JSON
|
empty string is assumed which references the whole JSON
|
||||||
value
|
value
|
||||||
|
|
||||||
@throw std::domain_error if reference token is nonempty and does not
|
@throw std::domain_error if reference token is nonempty and does not
|
||||||
begin with a slash (`/`), or if a tilde (`~`) is not followed
|
begin with a slash (`/`); example: `"JSON pointer must be empty or
|
||||||
by `0` (representing `~`) or `1` (representing `/`).
|
begin with /"`
|
||||||
|
@throw std::domain_error if a tilde (`~`) is not followed by `0`
|
||||||
|
(representing `~`) or `1` (representing `/`); example: `"escape error:
|
||||||
|
~ must be followed with 0 or 1"`
|
||||||
|
|
||||||
@liveexample{The example shows the construction several valid JSON
|
@liveexample{The example shows the construction several valid JSON
|
||||||
pointers as well as the exceptional behavior.,json_pointer}
|
pointers as well as the exceptional behavior.,json_pointer}
|
||||||
|
@ -8254,6 +8260,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
pointer result = &j;
|
pointer result = &j;
|
||||||
|
|
||||||
|
// in case no reference tokens exist, return a reference to the
|
||||||
|
// JSON value j which will be overwritten by a primitive value
|
||||||
for (const auto& reference_token : reference_tokens)
|
for (const auto& reference_token : reference_tokens)
|
||||||
{
|
{
|
||||||
switch (result->m_type)
|
switch (result->m_type)
|
||||||
|
@ -8262,10 +8270,12 @@ class basic_json
|
||||||
{
|
{
|
||||||
if (reference_token == "0")
|
if (reference_token == "0")
|
||||||
{
|
{
|
||||||
|
// start a new array if reference token is 0
|
||||||
result = &result->operator[](0);
|
result = &result->operator[](0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// start a new object otherwise
|
||||||
result = &result->operator[](reference_token);
|
result = &result->operator[](reference_token);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -8273,19 +8283,38 @@ class basic_json
|
||||||
|
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
|
// create an entry in the object
|
||||||
result = &result->operator[](reference_token);
|
result = &result->operator[](reference_token);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case value_t::array:
|
case value_t::array:
|
||||||
{
|
{
|
||||||
|
// create an entry in the array
|
||||||
result = &result->operator[](static_cast<size_t>(std::stoi(reference_token)));
|
result = &result->operator[](static_cast<size_t>(std::stoi(reference_token)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This function is only to be called from the unflatten()
|
||||||
|
function. There, j is initially of type null.
|
||||||
|
|
||||||
|
- In case the reference tokens are empty, a reference to
|
||||||
|
j is returned and overwritten by the desired value by
|
||||||
|
the unflatten() function.
|
||||||
|
- If there are reference tokens, the null value of j will
|
||||||
|
be changed to an object or array after reading the first
|
||||||
|
reference token.
|
||||||
|
- All subsequent tokens work on arrays or objects and will
|
||||||
|
not change the type of j.
|
||||||
|
|
||||||
|
Consequently, the type of @a j will always be null,
|
||||||
|
object, or array. Hence, the following line is
|
||||||
|
unreachable.
|
||||||
|
*/
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
throw std::domain_error("unresolved reference token '" + reference_token + "'");
|
break; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8671,7 +8700,11 @@ class basic_json
|
||||||
throw std::domain_error("values in object must be primitive");
|
throw std::domain_error("values in object must be primitive");
|
||||||
}
|
}
|
||||||
|
|
||||||
// assign value to reference pointed to by JSON pointer
|
// assign value to reference pointed to by JSON pointer;
|
||||||
|
// Note that if the JSON pointer is "" (i.e., points to the
|
||||||
|
// whole value), function get_and_create returns a reference
|
||||||
|
// to result itself. An assignment will then create a
|
||||||
|
// primitive value.
|
||||||
json_pointer(element.first).get_and_create(result) = element.second;
|
json_pointer(element.first).get_and_create(result) = element.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8700,7 +8733,8 @@ class basic_json
|
||||||
|
|
||||||
@return an object that maps JSON pointers to primitve values
|
@return an object that maps JSON pointers to primitve values
|
||||||
|
|
||||||
@note Empty objects and arrays are flattened to `null`.
|
@note Empty objects and arrays are flattened to `null` and will not be
|
||||||
|
reconstructed correctly by the @ref unflatten() function.
|
||||||
|
|
||||||
@complexity Linear in the size the JSON value.
|
@complexity Linear in the size the JSON value.
|
||||||
|
|
||||||
|
@ -8738,6 +8772,8 @@ class basic_json
|
||||||
|
|
||||||
@complexity Linear in the size the JSON value.
|
@complexity Linear in the size the JSON value.
|
||||||
|
|
||||||
|
@throws std::domain_error
|
||||||
|
|
||||||
@liveexample{The following code shows how a flattened JSON object is
|
@liveexample{The following code shows how a flattened JSON object is
|
||||||
unflattened into the original nested JSON object.,unflatten}
|
unflattened into the original nested JSON object.,unflatten}
|
||||||
|
|
||||||
|
|
|
@ -12365,6 +12365,11 @@ TEST_CASE("JSON pointers")
|
||||||
CHECK_THROWS_AS(json({{"/1", {1, 2, 3}}}).unflatten(), std::domain_error);
|
CHECK_THROWS_AS(json({{"/1", {1, 2, 3}}}).unflatten(), std::domain_error);
|
||||||
CHECK_THROWS_WITH(json({{"/1", {1, 2, 3}}}).unflatten(), "values in object must be primitive");
|
CHECK_THROWS_WITH(json({{"/1", {1, 2, 3}}}).unflatten(), "values in object must be primitive");
|
||||||
|
|
||||||
|
// error for conflicting values
|
||||||
|
json j_error = {{"", 42}, {"/foo", 17}};
|
||||||
|
CHECK_THROWS_AS(j_error.unflatten(), std::domain_error);
|
||||||
|
CHECK_THROWS_WITH(j_error.unflatten(), "unresolved reference token 'foo'");
|
||||||
|
|
||||||
// explicit roundtrip check
|
// explicit roundtrip check
|
||||||
CHECK(j.flatten().unflatten() == j);
|
CHECK(j.flatten().unflatten() == j);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue