Merge branch 'feature/json_pointer_contains' into develop
This commit is contained in:
		
						commit
						104c5c1996
					
				
					 7 changed files with 338 additions and 23 deletions
				
			
		
							
								
								
									
										45
									
								
								doc/examples/contains_json_pointer.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								doc/examples/contains_json_pointer.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | |||
| #include <iostream> | ||||
| #include <nlohmann/json.hpp> | ||||
| 
 | ||||
| using json = nlohmann::json; | ||||
| 
 | ||||
| int main() | ||||
| { | ||||
|     // create a JSON value
 | ||||
|     json j = | ||||
|     { | ||||
|         {"number", 1}, {"string", "foo"}, {"array", {1, 2}} | ||||
|     }; | ||||
| 
 | ||||
|     std::cout << std::boolalpha | ||||
|               << j.contains("/number"_json_pointer) << '\n' | ||||
|               << j.contains("/string"_json_pointer) << '\n' | ||||
|               << j.contains("/string"_json_pointer) << '\n' | ||||
|               << j.contains("/array"_json_pointer) << '\n' | ||||
|               << j.contains("/array/1"_json_pointer) << '\n' | ||||
|               << j.contains("/array/-"_json_pointer) << '\n' | ||||
|               << j.contains("/array/4"_json_pointer) << '\n' | ||||
|               << j.contains("/baz"_json_pointer) << std::endl; | ||||
| 
 | ||||
|     // out_of_range.106
 | ||||
|     try | ||||
|     { | ||||
|         // try to use an array index with leading '0'
 | ||||
|         j.contains("/array/01"_json_pointer); | ||||
|     } | ||||
|     catch (json::parse_error& e) | ||||
|     { | ||||
|         std::cout << e.what() << '\n'; | ||||
|     } | ||||
| 
 | ||||
|     // out_of_range.109
 | ||||
|     try | ||||
|     { | ||||
|         // try to use an array index that is not a number
 | ||||
|         j.contains("/array/one"_json_pointer); | ||||
|     } | ||||
|     catch (json::parse_error& e) | ||||
|     { | ||||
|         std::cout << e.what() << '\n'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1
									
								
								doc/examples/contains_json_pointer.link
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								doc/examples/contains_json_pointer.link
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| <a target="_blank" href="https://wandbox.org/permlink/3TJ79OzHP4vmN1Nb"><b>online</b></a> | ||||
							
								
								
									
										10
									
								
								doc/examples/contains_json_pointer.output
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								doc/examples/contains_json_pointer.output
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| true | ||||
| true | ||||
| true | ||||
| true | ||||
| true | ||||
| false | ||||
| false | ||||
| false | ||||
| [json.exception.parse_error.106] parse error: array index '01' must not begin with '0' | ||||
| [json.exception.parse_error.109] parse error: array index 'one' is not a number | ||||
|  | @ -2,6 +2,7 @@ | |||
| 
 | ||||
| #include <algorithm> // all_of
 | ||||
| #include <cassert> // assert
 | ||||
| #include <cctype> // isdigit
 | ||||
| #include <numeric> // accumulate
 | ||||
| #include <string> // string
 | ||||
| #include <utility> // move
 | ||||
|  | @ -369,7 +370,7 @@ class json_pointer | |||
|         // j which will be overwritten by a primitive value
 | ||||
|         for (const auto& reference_token : reference_tokens) | ||||
|         { | ||||
|             switch (result->m_type) | ||||
|             switch (result->type()) | ||||
|             { | ||||
|                 case detail::value_t::null: | ||||
|                 { | ||||
|  | @ -446,14 +447,14 @@ class json_pointer | |||
|         for (const auto& reference_token : reference_tokens) | ||||
|         { | ||||
|             // convert null values to arrays or objects before continuing
 | ||||
|             if (ptr->m_type == detail::value_t::null) | ||||
|             if (ptr->is_null()) | ||||
|             { | ||||
|                 // check if reference token is a number
 | ||||
|                 const bool nums = | ||||
|                     std::all_of(reference_token.begin(), reference_token.end(), | ||||
|                                 [](const char x) | ||||
|                                 [](const unsigned char x) | ||||
|                 { | ||||
|                     return x >= '0' and x <= '9'; | ||||
|                     return std::isdigit(x); | ||||
|                 }); | ||||
| 
 | ||||
|                 // change value to array for numbers or "-" or to object otherwise
 | ||||
|  | @ -462,7 +463,7 @@ class json_pointer | |||
|                        : detail::value_t::object; | ||||
|             } | ||||
| 
 | ||||
|             switch (ptr->m_type) | ||||
|             switch (ptr->type()) | ||||
|             { | ||||
|                 case detail::value_t::object: | ||||
|                 { | ||||
|  | @ -521,7 +522,7 @@ class json_pointer | |||
|         using size_type = typename BasicJsonType::size_type; | ||||
|         for (const auto& reference_token : reference_tokens) | ||||
|         { | ||||
|             switch (ptr->m_type) | ||||
|             switch (ptr->type()) | ||||
|             { | ||||
|                 case detail::value_t::object: | ||||
|                 { | ||||
|  | @ -586,7 +587,7 @@ class json_pointer | |||
|         using size_type = typename BasicJsonType::size_type; | ||||
|         for (const auto& reference_token : reference_tokens) | ||||
|         { | ||||
|             switch (ptr->m_type) | ||||
|             switch (ptr->type()) | ||||
|             { | ||||
|                 case detail::value_t::object: | ||||
|                 { | ||||
|  | @ -645,7 +646,7 @@ class json_pointer | |||
|         using size_type = typename BasicJsonType::size_type; | ||||
|         for (const auto& reference_token : reference_tokens) | ||||
|         { | ||||
|             switch (ptr->m_type) | ||||
|             switch (ptr->type()) | ||||
|             { | ||||
|                 case detail::value_t::object: | ||||
|                 { | ||||
|  | @ -692,6 +693,77 @@ class json_pointer | |||
|         return *ptr; | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @throw parse_error.106   if an array index begins with '0' | ||||
|     @throw parse_error.109   if an array index was not a number | ||||
|     */ | ||||
|     bool contains(const BasicJsonType* ptr) const | ||||
|     { | ||||
|         using size_type = typename BasicJsonType::size_type; | ||||
|         for (const auto& reference_token : reference_tokens) | ||||
|         { | ||||
|             switch (ptr->type()) | ||||
|             { | ||||
|                 case detail::value_t::object: | ||||
|                 { | ||||
|                     if (not ptr->contains(reference_token)) | ||||
|                     { | ||||
|                         // we did not find the key in the object
 | ||||
|                         return false; | ||||
|                     } | ||||
| 
 | ||||
|                     ptr = &ptr->operator[](reference_token); | ||||
|                     break; | ||||
|                 } | ||||
| 
 | ||||
|                 case detail::value_t::array: | ||||
|                 { | ||||
|                     if (JSON_UNLIKELY(reference_token == "-")) | ||||
|                     { | ||||
|                         // "-" always fails the range check
 | ||||
|                         return false; | ||||
|                     } | ||||
| 
 | ||||
|                     // error condition (cf. RFC 6901, Sect. 4)
 | ||||
|                     if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) | ||||
|                     { | ||||
|                         JSON_THROW(detail::parse_error::create(106, 0, | ||||
|                                                                "array index '" + reference_token + | ||||
|                                                                "' must not begin with '0'")); | ||||
|                     } | ||||
| 
 | ||||
|                     JSON_TRY | ||||
|                     { | ||||
|                         const auto idx = static_cast<size_type>(array_index(reference_token)); | ||||
|                         if (idx >= ptr->size()) | ||||
|                         { | ||||
|                             // index out of range
 | ||||
|                             return false; | ||||
|                         } | ||||
| 
 | ||||
|                         ptr = &ptr->operator[](idx); | ||||
|                         break; | ||||
|                     } | ||||
|                     JSON_CATCH(std::invalid_argument&) | ||||
|                     { | ||||
|                         JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); | ||||
|                     } | ||||
|                     break; | ||||
|                 } | ||||
| 
 | ||||
|                 default: | ||||
|                 { | ||||
|                     // we do not expect primitive values if there is still a
 | ||||
|                     // reference token to process
 | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // no reference token left means we found a primitive value
 | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief split the string input to reference tokens | ||||
| 
 | ||||
|  | @ -813,7 +885,7 @@ class json_pointer | |||
|                         const BasicJsonType& value, | ||||
|                         BasicJsonType& result) | ||||
|     { | ||||
|         switch (value.m_type) | ||||
|         switch (value.type()) | ||||
|         { | ||||
|             case detail::value_t::array: | ||||
|             { | ||||
|  |  | |||
|  | @ -4001,15 +4001,48 @@ class basic_json | |||
|     @liveexample{The following code shows an example for `contains()`.,contains} | ||||
| 
 | ||||
|     @sa @ref find(KeyT&&) -- returns an iterator to an object element | ||||
|     @sa @ref contains(const json_pointer&) const -- checks the existence for a JSON pointer | ||||
| 
 | ||||
|     @since version 3.6.0 | ||||
|     */ | ||||
|     template<typename KeyT> | ||||
|     bool contains(KeyT&& key) const | ||||
|     template<typename KeyT, typename std::enable_if< | ||||
|                  not std::is_same<KeyT, json_pointer>::value, int>::type = 0> | ||||
|     bool contains(KeyT && key) const | ||||
|     { | ||||
|         return is_object() and m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end(); | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief check the existence of an element in a JSON object given a JSON pointer | ||||
| 
 | ||||
|     Check wehther the given JSON pointer @a ptr can be resolved in the current | ||||
|     JSON value. | ||||
| 
 | ||||
|     @note This method can be executed on any JSON value type. | ||||
| 
 | ||||
|     @param[in] ptr JSON pointer to check its existence. | ||||
| 
 | ||||
|     @return true if the JSON pointer can be resolved to a stored value, false | ||||
|     otherwise. | ||||
| 
 | ||||
|     @post If `j.contains(ptr)` returns true, it is safe to call `j[ptr]`. | ||||
| 
 | ||||
|     @throw parse_error.106   if an array index begins with '0' | ||||
|     @throw parse_error.109   if an array index was not a number | ||||
| 
 | ||||
|     @complexity Logarithmic in the size of the JSON object. | ||||
| 
 | ||||
|     @liveexample{The following code shows an example for `contains()`.,contains_json_pointer} | ||||
| 
 | ||||
|     @sa @ref contains(KeyT &&) const -- checks the existence of a key | ||||
| 
 | ||||
|     @since version 3.7.0 | ||||
|     */ | ||||
|     bool contains(const json_pointer& ptr) const | ||||
|     { | ||||
|         return ptr.contains(this); | ||||
|     } | ||||
| 
 | ||||
|     /// @}
 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -8455,6 +8455,7 @@ class json_reverse_iterator : public std::reverse_iterator<Base> | |||
| 
 | ||||
| #include <algorithm> // all_of
 | ||||
| #include <cassert> // assert
 | ||||
| #include <cctype> // isdigit
 | ||||
| #include <numeric> // accumulate
 | ||||
| #include <string> // string
 | ||||
| #include <utility> // move
 | ||||
|  | @ -8825,7 +8826,7 @@ class json_pointer | |||
|         // j which will be overwritten by a primitive value
 | ||||
|         for (const auto& reference_token : reference_tokens) | ||||
|         { | ||||
|             switch (result->m_type) | ||||
|             switch (result->type()) | ||||
|             { | ||||
|                 case detail::value_t::null: | ||||
|                 { | ||||
|  | @ -8902,14 +8903,14 @@ class json_pointer | |||
|         for (const auto& reference_token : reference_tokens) | ||||
|         { | ||||
|             // convert null values to arrays or objects before continuing
 | ||||
|             if (ptr->m_type == detail::value_t::null) | ||||
|             if (ptr->is_null()) | ||||
|             { | ||||
|                 // check if reference token is a number
 | ||||
|                 const bool nums = | ||||
|                     std::all_of(reference_token.begin(), reference_token.end(), | ||||
|                                 [](const char x) | ||||
|                                 [](const unsigned char x) | ||||
|                 { | ||||
|                     return x >= '0' and x <= '9'; | ||||
|                     return std::isdigit(x); | ||||
|                 }); | ||||
| 
 | ||||
|                 // change value to array for numbers or "-" or to object otherwise
 | ||||
|  | @ -8918,7 +8919,7 @@ class json_pointer | |||
|                        : detail::value_t::object; | ||||
|             } | ||||
| 
 | ||||
|             switch (ptr->m_type) | ||||
|             switch (ptr->type()) | ||||
|             { | ||||
|                 case detail::value_t::object: | ||||
|                 { | ||||
|  | @ -8977,7 +8978,7 @@ class json_pointer | |||
|         using size_type = typename BasicJsonType::size_type; | ||||
|         for (const auto& reference_token : reference_tokens) | ||||
|         { | ||||
|             switch (ptr->m_type) | ||||
|             switch (ptr->type()) | ||||
|             { | ||||
|                 case detail::value_t::object: | ||||
|                 { | ||||
|  | @ -9042,7 +9043,7 @@ class json_pointer | |||
|         using size_type = typename BasicJsonType::size_type; | ||||
|         for (const auto& reference_token : reference_tokens) | ||||
|         { | ||||
|             switch (ptr->m_type) | ||||
|             switch (ptr->type()) | ||||
|             { | ||||
|                 case detail::value_t::object: | ||||
|                 { | ||||
|  | @ -9101,7 +9102,7 @@ class json_pointer | |||
|         using size_type = typename BasicJsonType::size_type; | ||||
|         for (const auto& reference_token : reference_tokens) | ||||
|         { | ||||
|             switch (ptr->m_type) | ||||
|             switch (ptr->type()) | ||||
|             { | ||||
|                 case detail::value_t::object: | ||||
|                 { | ||||
|  | @ -9148,6 +9149,77 @@ class json_pointer | |||
|         return *ptr; | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @throw parse_error.106   if an array index begins with '0' | ||||
|     @throw parse_error.109   if an array index was not a number | ||||
|     */ | ||||
|     bool contains(const BasicJsonType* ptr) const | ||||
|     { | ||||
|         using size_type = typename BasicJsonType::size_type; | ||||
|         for (const auto& reference_token : reference_tokens) | ||||
|         { | ||||
|             switch (ptr->type()) | ||||
|             { | ||||
|                 case detail::value_t::object: | ||||
|                 { | ||||
|                     if (not ptr->contains(reference_token)) | ||||
|                     { | ||||
|                         // we did not find the key in the object
 | ||||
|                         return false; | ||||
|                     } | ||||
| 
 | ||||
|                     ptr = &ptr->operator[](reference_token); | ||||
|                     break; | ||||
|                 } | ||||
| 
 | ||||
|                 case detail::value_t::array: | ||||
|                 { | ||||
|                     if (JSON_UNLIKELY(reference_token == "-")) | ||||
|                     { | ||||
|                         // "-" always fails the range check
 | ||||
|                         return false; | ||||
|                     } | ||||
| 
 | ||||
|                     // error condition (cf. RFC 6901, Sect. 4)
 | ||||
|                     if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) | ||||
|                     { | ||||
|                         JSON_THROW(detail::parse_error::create(106, 0, | ||||
|                                                                "array index '" + reference_token + | ||||
|                                                                "' must not begin with '0'")); | ||||
|                     } | ||||
| 
 | ||||
|                     JSON_TRY | ||||
|                     { | ||||
|                         const auto idx = static_cast<size_type>(array_index(reference_token)); | ||||
|                         if (idx >= ptr->size()) | ||||
|                         { | ||||
|                             // index out of range
 | ||||
|                             return false; | ||||
|                         } | ||||
| 
 | ||||
|                         ptr = &ptr->operator[](idx); | ||||
|                         break; | ||||
|                     } | ||||
|                     JSON_CATCH(std::invalid_argument&) | ||||
|                     { | ||||
|                         JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); | ||||
|                     } | ||||
|                     break; | ||||
|                 } | ||||
| 
 | ||||
|                 default: | ||||
|                 { | ||||
|                     // we do not expect primitive values if there is still a
 | ||||
|                     // reference token to process
 | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // no reference token left means we found a primitive value
 | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief split the string input to reference tokens | ||||
| 
 | ||||
|  | @ -9269,7 +9341,7 @@ class json_pointer | |||
|                         const BasicJsonType& value, | ||||
|                         BasicJsonType& result) | ||||
|     { | ||||
|         switch (value.m_type) | ||||
|         switch (value.type()) | ||||
|         { | ||||
|             case detail::value_t::array: | ||||
|             { | ||||
|  | @ -16812,15 +16884,48 @@ class basic_json | |||
|     @liveexample{The following code shows an example for `contains()`.,contains} | ||||
| 
 | ||||
|     @sa @ref find(KeyT&&) -- returns an iterator to an object element | ||||
|     @sa @ref contains(const json_pointer&) const -- checks the existence for a JSON pointer | ||||
| 
 | ||||
|     @since version 3.6.0 | ||||
|     */ | ||||
|     template<typename KeyT> | ||||
|     bool contains(KeyT&& key) const | ||||
|     template<typename KeyT, typename std::enable_if< | ||||
|                  not std::is_same<KeyT, json_pointer>::value, int>::type = 0> | ||||
|     bool contains(KeyT && key) const | ||||
|     { | ||||
|         return is_object() and m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end(); | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief check the existence of an element in a JSON object given a JSON pointer | ||||
| 
 | ||||
|     Check wehther the given JSON pointer @a ptr can be resolved in the current | ||||
|     JSON value. | ||||
| 
 | ||||
|     @note This method can be executed on any JSON value type. | ||||
| 
 | ||||
|     @param[in] ptr JSON pointer to check its existence. | ||||
| 
 | ||||
|     @return true if the JSON pointer can be resolved to a stored value, false | ||||
|     otherwise. | ||||
| 
 | ||||
|     @post If `j.contains(ptr)` returns true, it is safe to call `j[ptr]`. | ||||
| 
 | ||||
|     @throw parse_error.106   if an array index begins with '0' | ||||
|     @throw parse_error.109   if an array index was not a number | ||||
| 
 | ||||
|     @complexity Logarithmic in the size of the JSON object. | ||||
| 
 | ||||
|     @liveexample{The following code shows an example for `contains()`.,contains_json_pointer} | ||||
| 
 | ||||
|     @sa @ref contains(KeyT &&) const -- checks the existence of a key | ||||
| 
 | ||||
|     @since version 3.7.0 | ||||
|     */ | ||||
|     bool contains(const json_pointer& ptr) const | ||||
|     { | ||||
|         return ptr.contains(this); | ||||
|     } | ||||
| 
 | ||||
|     /// @}
 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -90,12 +90,18 @@ TEST_CASE("JSON pointers") | |||
|             // the whole document
 | ||||
|             CHECK(j[json::json_pointer()] == j); | ||||
|             CHECK(j[json::json_pointer("")] == j); | ||||
|             CHECK(j.contains(json::json_pointer())); | ||||
|             CHECK(j.contains(json::json_pointer(""))); | ||||
| 
 | ||||
|             // array access
 | ||||
|             CHECK(j[json::json_pointer("/foo")] == j["foo"]); | ||||
|             CHECK(j.contains(json::json_pointer("/foo"))); | ||||
|             CHECK(j[json::json_pointer("/foo/0")] == j["foo"][0]); | ||||
|             CHECK(j[json::json_pointer("/foo/1")] == j["foo"][1]); | ||||
|             CHECK(j["/foo/1"_json_pointer] == j["foo"][1]); | ||||
|             CHECK(j.contains(json::json_pointer("/foo/0"))); | ||||
|             CHECK(j.contains(json::json_pointer("/foo/1"))); | ||||
|             CHECK(not j.contains(json::json_pointer("/foo/-"))); | ||||
| 
 | ||||
|             // checked array access
 | ||||
|             CHECK(j.at(json::json_pointer("/foo/0")) == j["foo"][0]); | ||||
|  | @ -103,6 +109,8 @@ TEST_CASE("JSON pointers") | |||
| 
 | ||||
|             // empty string access
 | ||||
|             CHECK(j[json::json_pointer("/")] == j[""]); | ||||
|             CHECK(j.contains(json::json_pointer(""))); | ||||
|             CHECK(j.contains(json::json_pointer("/"))); | ||||
| 
 | ||||
|             // other cases
 | ||||
|             CHECK(j[json::json_pointer("/ ")] == j[" "]); | ||||
|  | @ -112,6 +120,14 @@ TEST_CASE("JSON pointers") | |||
|             CHECK(j[json::json_pointer("/i\\j")] == j["i\\j"]); | ||||
|             CHECK(j[json::json_pointer("/k\"l")] == j["k\"l"]); | ||||
| 
 | ||||
|             // contains
 | ||||
|             CHECK(j.contains(json::json_pointer("/ "))); | ||||
|             CHECK(j.contains(json::json_pointer("/c%d"))); | ||||
|             CHECK(j.contains(json::json_pointer("/e^f"))); | ||||
|             CHECK(j.contains(json::json_pointer("/g|h"))); | ||||
|             CHECK(j.contains(json::json_pointer("/i\\j"))); | ||||
|             CHECK(j.contains(json::json_pointer("/k\"l"))); | ||||
| 
 | ||||
|             // checked access
 | ||||
|             CHECK(j.at(json::json_pointer("/ ")) == j[" "]); | ||||
|             CHECK(j.at(json::json_pointer("/c%d")) == j["c%d"]); | ||||
|  | @ -123,14 +139,24 @@ TEST_CASE("JSON pointers") | |||
|             // escaped access
 | ||||
|             CHECK(j[json::json_pointer("/a~1b")] == j["a/b"]); | ||||
|             CHECK(j[json::json_pointer("/m~0n")] == j["m~n"]); | ||||
|             CHECK(j.contains(json::json_pointer("/a~1b"))); | ||||
|             CHECK(j.contains(json::json_pointer("/m~0n"))); | ||||
| 
 | ||||
|             // unescaped access
 | ||||
|             // access to nonexisting values yield object creation
 | ||||
|             CHECK(not j.contains(json::json_pointer("/a/b"))); | ||||
|             CHECK_NOTHROW(j[json::json_pointer("/a/b")] = 42); | ||||
|             CHECK(j.contains(json::json_pointer("/a/b"))); | ||||
|             CHECK(j["a"]["b"] == json(42)); | ||||
| 
 | ||||
|             CHECK(not j.contains(json::json_pointer("/a/c/1"))); | ||||
|             CHECK_NOTHROW(j[json::json_pointer("/a/c/1")] = 42); | ||||
|             CHECK(j["a"]["c"] == json({nullptr, 42})); | ||||
|             CHECK(j.contains(json::json_pointer("/a/c/1"))); | ||||
| 
 | ||||
|             CHECK(not j.contains(json::json_pointer("/a/d/-"))); | ||||
|             CHECK_NOTHROW(j[json::json_pointer("/a/d/-")] = 42); | ||||
|             CHECK(not j.contains(json::json_pointer("/a/d/-"))); | ||||
|             CHECK(j["a"]["d"] == json::array({42})); | ||||
|             // "/a/b" works for JSON {"a": {"b": 42}}
 | ||||
|             CHECK(json({{"a", {{"b", 42}}}})[json::json_pointer("/a/b")] == json(42)); | ||||
|  | @ -143,6 +169,7 @@ TEST_CASE("JSON pointers") | |||
|             CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), json::out_of_range&); | ||||
|             CHECK_THROWS_WITH(j_primitive.at("/foo"_json_pointer), | ||||
|                               "[json.exception.out_of_range.404] unresolved reference token 'foo'"); | ||||
|             CHECK(not j_primitive.contains(json::json_pointer("/foo"))); | ||||
|         } | ||||
| 
 | ||||
|         SECTION("const access") | ||||
|  | @ -233,11 +260,16 @@ TEST_CASE("JSON pointers") | |||
| 
 | ||||
|             // the whole document
 | ||||
|             CHECK(j[""_json_pointer] == j); | ||||
|             CHECK(j.contains(""_json_pointer)); | ||||
| 
 | ||||
|             // array access
 | ||||
|             CHECK(j["/foo"_json_pointer] == j["foo"]); | ||||
|             CHECK(j["/foo/0"_json_pointer] == j["foo"][0]); | ||||
|             CHECK(j["/foo/1"_json_pointer] == j["foo"][1]); | ||||
|             CHECK(j.contains("/foo"_json_pointer)); | ||||
|             CHECK(j.contains("/foo/0"_json_pointer)); | ||||
|             CHECK(j.contains("/foo/1"_json_pointer)); | ||||
|             CHECK(not j.contains("/foo/-"_json_pointer)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -278,6 +310,12 @@ TEST_CASE("JSON pointers") | |||
|             CHECK_THROWS_AS(j_const.at("/01"_json_pointer), json::parse_error&); | ||||
|             CHECK_THROWS_WITH(j_const.at("/01"_json_pointer), | ||||
|                               "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"); | ||||
|             CHECK_THROWS_AS(j.contains("/01"_json_pointer), json::parse_error&); | ||||
|             CHECK_THROWS_WITH(j.contains("/01"_json_pointer), | ||||
|                               "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"); | ||||
|             CHECK_THROWS_AS(j_const.contains("/01"_json_pointer), json::parse_error&); | ||||
|             CHECK_THROWS_WITH(j_const.contains("/01"_json_pointer), | ||||
|                               "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"); | ||||
| 
 | ||||
|             // error with incorrect numbers
 | ||||
|             CHECK_THROWS_AS(j["/one"_json_pointer] = 1, json::parse_error&); | ||||
|  | @ -294,6 +332,13 @@ TEST_CASE("JSON pointers") | |||
|             CHECK_THROWS_WITH(j_const.at("/one"_json_pointer) == 1, | ||||
|                               "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); | ||||
| 
 | ||||
|             CHECK_THROWS_AS(j.contains("/one"_json_pointer), json::parse_error&); | ||||
|             CHECK_THROWS_WITH(j.contains("/one"_json_pointer), | ||||
|                               "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); | ||||
|             CHECK_THROWS_AS(j_const.contains("/one"_json_pointer), json::parse_error&); | ||||
|             CHECK_THROWS_WITH(j_const.contains("/one"_json_pointer), | ||||
|                               "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); | ||||
| 
 | ||||
|             CHECK_THROWS_AS(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(), json::parse_error&); | ||||
|             CHECK_THROWS_WITH(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(), | ||||
|             "[json.exception.parse_error.109] parse error: array index 'three' is not a number"); | ||||
|  | @ -306,6 +351,7 @@ TEST_CASE("JSON pointers") | |||
|             CHECK_THROWS_AS(j_const["/-"_json_pointer], json::out_of_range&); | ||||
|             CHECK_THROWS_WITH(j_const["/-"_json_pointer], | ||||
|                               "[json.exception.out_of_range.402] array index '-' (3) is out of range"); | ||||
|             CHECK(not j_const.contains("/-"_json_pointer)); | ||||
| 
 | ||||
|             // error when using "-" with at
 | ||||
|             CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range&); | ||||
|  | @ -314,6 +360,7 @@ TEST_CASE("JSON pointers") | |||
|             CHECK_THROWS_AS(j_const.at("/-"_json_pointer), json::out_of_range&); | ||||
|             CHECK_THROWS_WITH(j_const.at("/-"_json_pointer), | ||||
|                               "[json.exception.out_of_range.402] array index '-' (3) is out of range"); | ||||
|             CHECK(not j_const.contains("/-"_json_pointer)); | ||||
|         } | ||||
| 
 | ||||
|         SECTION("const access") | ||||
|  | @ -329,11 +376,13 @@ TEST_CASE("JSON pointers") | |||
|             CHECK_THROWS_AS(j.at("/3"_json_pointer), json::out_of_range&); | ||||
|             CHECK_THROWS_WITH(j.at("/3"_json_pointer), | ||||
|                               "[json.exception.out_of_range.401] array index 3 is out of range"); | ||||
|             CHECK(not j.contains("/3"_json_pointer)); | ||||
| 
 | ||||
|             // assign to nonexisting index (with gap)
 | ||||
|             CHECK_THROWS_AS(j.at("/5"_json_pointer), json::out_of_range&); | ||||
|             CHECK_THROWS_WITH(j.at("/5"_json_pointer), | ||||
|                               "[json.exception.out_of_range.401] array index 5 is out of range"); | ||||
|             CHECK(not j.contains("/5"_json_pointer)); | ||||
| 
 | ||||
|             // assign to "-"
 | ||||
|             CHECK_THROWS_AS(j["/-"_json_pointer], json::out_of_range&); | ||||
|  | @ -342,8 +391,8 @@ TEST_CASE("JSON pointers") | |||
|             CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range&); | ||||
|             CHECK_THROWS_WITH(j.at("/-"_json_pointer), | ||||
|                               "[json.exception.out_of_range.402] array index '-' (3) is out of range"); | ||||
|             CHECK(not j.contains("/-"_json_pointer)); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     SECTION("flatten") | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue