Merge branch 'feature/issue323' into develop

This commit is contained in:
Niels 2016-10-12 21:21:59 +02:00
commit e7a60d8961
7 changed files with 95 additions and 9 deletions

View file

@ -515,17 +515,17 @@ To compile and run the tests, you need to execute
$ make check $ make check
=============================================================================== ===============================================================================
All tests passed (8905161 assertions in 35 test cases) All tests passed (8905166 assertions in 35 test cases)
``` ```
Alternatively, you can use [https://cmake.org](CMake) and run Alternatively, you can use [https://cmake.org](CMake) and run
```sh ```sh
mkdir build $ mkdir build
cd build $ cd build
cmake .. $ cmake ..
make $ make
ctest $ ctest
``` ```
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).

View file

@ -40,7 +40,7 @@ int main()
// output the changed array // output the changed array
std::cout << j["array"] << '\n'; std::cout << j["array"] << '\n';
// "change" the arry element past the end // "change" the array element past the end
j["/array/-"_json_pointer] = 55; j["/array/-"_json_pointer] = 55;
// output the changed array // output the changed array
std::cout << j["array"] << '\n'; std::cout << j["array"] << '\n';

View file

@ -32,6 +32,7 @@ SOFTWARE.
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cassert> #include <cassert>
#include <cctype>
#include <ciso646> #include <ciso646>
#include <cmath> #include <cmath>
#include <cstddef> #include <cstddef>
@ -9436,6 +9437,12 @@ basic_json_parser_63:
/*! /*!
@brief return a reference to the pointed to value @brief return a reference to the pointed to value
@note This version does not throw if a value is not present, but tries
to create nested values instead. For instance, calling this function
with pointer `"/this/that"` on a null value is equivalent to calling
`operator[]("this").operator[]("that")` on that value, effectively
changing the null value to an object.
@param[in] ptr a JSON value @param[in] ptr a JSON value
@return reference to the JSON value pointed to by the JSON pointer @return reference to the JSON value pointed to by the JSON pointer
@ -9450,6 +9457,29 @@ basic_json_parser_63:
{ {
for (const auto& reference_token : reference_tokens) for (const auto& reference_token : reference_tokens)
{ {
// convert null values to arrays or objects before continuing
if (ptr->m_type == value_t::null)
{
// check if reference token is a number
const bool nums = std::all_of(reference_token.begin(),
reference_token.end(),
[](const char x)
{
return std::isdigit(x);
});
// change value to array for numbers or "-" or to object
// otherwise
if (nums or reference_token == "-")
{
*ptr = value_t::array;
}
else
{
*ptr = value_t::object;
}
}
switch (ptr->m_type) switch (ptr->m_type)
{ {
case value_t::object: case value_t::object:
@ -9461,6 +9491,7 @@ basic_json_parser_63:
case value_t::array: case value_t::array:
{ {
// error condition (cf. RFC 6901, Sect. 4) // error condition (cf. RFC 6901, Sect. 4)
if (reference_token.size() > 1 and reference_token[0] == '0') if (reference_token.size() > 1 and reference_token[0] == '0')
{ {

View file

@ -32,6 +32,7 @@ SOFTWARE.
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cassert> #include <cassert>
#include <cctype>
#include <ciso646> #include <ciso646>
#include <cmath> #include <cmath>
#include <cstddef> #include <cstddef>
@ -8733,6 +8734,12 @@ class basic_json
/*! /*!
@brief return a reference to the pointed to value @brief return a reference to the pointed to value
@note This version does not throw if a value is not present, but tries
to create nested values instead. For instance, calling this function
with pointer `"/this/that"` on a null value is equivalent to calling
`operator[]("this").operator[]("that")` on that value, effectively
changing the null value to an object.
@param[in] ptr a JSON value @param[in] ptr a JSON value
@return reference to the JSON value pointed to by the JSON pointer @return reference to the JSON value pointed to by the JSON pointer
@ -8747,6 +8754,29 @@ class basic_json
{ {
for (const auto& reference_token : reference_tokens) for (const auto& reference_token : reference_tokens)
{ {
// convert null values to arrays or objects before continuing
if (ptr->m_type == value_t::null)
{
// check if reference token is a number
const bool nums = std::all_of(reference_token.begin(),
reference_token.end(),
[](const char x)
{
return std::isdigit(x);
});
// change value to array for numbers or "-" or to object
// otherwise
if (nums or reference_token == "-")
{
*ptr = value_t::array;
}
else
{
*ptr = value_t::object;
}
}
switch (ptr->m_type) switch (ptr->m_type)
{ {
case value_t::object: case value_t::object:
@ -8758,6 +8788,7 @@ class basic_json
case value_t::array: case value_t::array:
{ {
// error condition (cf. RFC 6901, Sect. 4) // error condition (cf. RFC 6901, Sect. 4)
if (reference_token.size() > 1 and reference_token[0] == '0') if (reference_token.size() > 1 and reference_token[0] == '0')
{ {

View file

@ -238,6 +238,18 @@ TEST_CASE("deserialization")
uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u', '1'}; uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u', '1'};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument);
} }
SECTION("case 3")
{
uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u', '1', '1', '1', '1', '1', '1', '1', '1'};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument);
}
SECTION("case 4")
{
uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', 'u', '1', '1', '1', '1', '1', '1', '1', '1', '\\'};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument);
}
} }
} }
} }

View file

@ -109,8 +109,13 @@ TEST_CASE("JSON pointers")
CHECK(j[json::json_pointer("/m~0n")] == j["m~n"]); CHECK(j[json::json_pointer("/m~0n")] == j["m~n"]);
// unescaped access // unescaped access
CHECK_THROWS_AS(j[json::json_pointer("/a/b")], std::out_of_range); // access to nonexisting values yield object creation
CHECK_THROWS_WITH(j[json::json_pointer("/a/b")], "unresolved reference token 'b'"); CHECK_NOTHROW(j[json::json_pointer("/a/b")] = 42);
CHECK(j["a"]["b"] == json(42));
CHECK_NOTHROW(j[json::json_pointer("/a/c/1")] = 42);
CHECK(j["a"]["c"] == json({nullptr, 42}));
CHECK_NOTHROW(j[json::json_pointer("/a/d/-")] = 42);
CHECK(j["a"]["d"] == json::array({42}));
// "/a/b" works for JSON {"a": {"b": 42}} // "/a/b" works for JSON {"a": {"b": 42}}
CHECK(json({{"a", {{"b", 42}}}})[json::json_pointer("/a/b")] == json(42)); CHECK(json({{"a", {{"b", 42}}}})[json::json_pointer("/a/b")] == json(42));

View file

@ -482,4 +482,11 @@ TEST_CASE("regression tests")
CHECK_NOTHROW(j << f); CHECK_NOTHROW(j << f);
} }
} }
SECTION("issue #323 - add nested object capabilities to pointers")
{
json j;
j["/this/that"_json_pointer] = 27;
CHECK(j == json({{"this", {{"that", 27}}}}));
}
} }