Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
J
json
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
json
Commits
104c5c19
Unverified
Commit
104c5c19
authored
Jul 09, 2019
by
Niels Lohmann
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature/json_pointer_contains' into develop
parents
7a23aa1c
258fa798
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
338 additions
and
23 deletions
+338
-23
doc/examples/contains_json_pointer.cpp
doc/examples/contains_json_pointer.cpp
+45
-0
doc/examples/contains_json_pointer.link
doc/examples/contains_json_pointer.link
+1
-0
doc/examples/contains_json_pointer.output
doc/examples/contains_json_pointer.output
+10
-0
include/nlohmann/detail/json_pointer.hpp
include/nlohmann/detail/json_pointer.hpp
+81
-9
include/nlohmann/json.hpp
include/nlohmann/json.hpp
+35
-2
single_include/nlohmann/json.hpp
single_include/nlohmann/json.hpp
+116
-11
test/src/unit-json_pointer.cpp
test/src/unit-json_pointer.cpp
+50
-1
No files found.
doc/examples/contains_json_pointer.cpp
0 → 100644
View file @
104c5c19
#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'
;
}
}
doc/examples/contains_json_pointer.link
0 → 100644
View file @
104c5c19
<a target="_blank" href="https://wandbox.org/permlink/3TJ79OzHP4vmN1Nb"><b>online</b></a>
\ No newline at end of file
doc/examples/contains_json_pointer.output
0 → 100644
View file @
104c5c19
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
include/nlohmann/detail/json_pointer.hpp
View file @
104c5c19
...
@@ -2,6 +2,7 @@
...
@@ -2,6 +2,7 @@
#include <algorithm> // all_of
#include <algorithm> // all_of
#include <cassert> // assert
#include <cassert> // assert
#include <cctype> // isdigit
#include <numeric> // accumulate
#include <numeric> // accumulate
#include <string> // string
#include <string> // string
#include <utility> // move
#include <utility> // move
...
@@ -369,7 +370,7 @@ class json_pointer
...
@@ -369,7 +370,7 @@ class json_pointer
// j which will be overwritten by a primitive 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
->
type
()
)
{
{
case
detail
:
:
value_t
::
null
:
case
detail
:
:
value_t
::
null
:
{
{
...
@@ -446,14 +447,14 @@ class json_pointer
...
@@ -446,14 +447,14 @@ class json_pointer
for
(
const
auto
&
reference_token
:
reference_tokens
)
for
(
const
auto
&
reference_token
:
reference_tokens
)
{
{
// convert null values to arrays or objects before continuing
// 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
// check if reference token is a number
const
bool
nums
=
const
bool
nums
=
std
::
all_of
(
reference_token
.
begin
(),
reference_token
.
end
(),
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
// change value to array for numbers or "-" or to object otherwise
...
@@ -462,7 +463,7 @@ class json_pointer
...
@@ -462,7 +463,7 @@ class json_pointer
:
detail
::
value_t
::
object
;
:
detail
::
value_t
::
object
;
}
}
switch
(
ptr
->
m_type
)
switch
(
ptr
->
type
()
)
{
{
case
detail
:
:
value_t
::
object
:
case
detail
:
:
value_t
::
object
:
{
{
...
@@ -521,7 +522,7 @@ class json_pointer
...
@@ -521,7 +522,7 @@ class json_pointer
using
size_type
=
typename
BasicJsonType
::
size_type
;
using
size_type
=
typename
BasicJsonType
::
size_type
;
for
(
const
auto
&
reference_token
:
reference_tokens
)
for
(
const
auto
&
reference_token
:
reference_tokens
)
{
{
switch
(
ptr
->
m_type
)
switch
(
ptr
->
type
()
)
{
{
case
detail
:
:
value_t
::
object
:
case
detail
:
:
value_t
::
object
:
{
{
...
@@ -586,7 +587,7 @@ class json_pointer
...
@@ -586,7 +587,7 @@ class json_pointer
using
size_type
=
typename
BasicJsonType
::
size_type
;
using
size_type
=
typename
BasicJsonType
::
size_type
;
for
(
const
auto
&
reference_token
:
reference_tokens
)
for
(
const
auto
&
reference_token
:
reference_tokens
)
{
{
switch
(
ptr
->
m_type
)
switch
(
ptr
->
type
()
)
{
{
case
detail
:
:
value_t
::
object
:
case
detail
:
:
value_t
::
object
:
{
{
...
@@ -645,7 +646,7 @@ class json_pointer
...
@@ -645,7 +646,7 @@ class json_pointer
using
size_type
=
typename
BasicJsonType
::
size_type
;
using
size_type
=
typename
BasicJsonType
::
size_type
;
for
(
const
auto
&
reference_token
:
reference_tokens
)
for
(
const
auto
&
reference_token
:
reference_tokens
)
{
{
switch
(
ptr
->
m_type
)
switch
(
ptr
->
type
()
)
{
{
case
detail
:
:
value_t
::
object
:
case
detail
:
:
value_t
::
object
:
{
{
...
@@ -692,6 +693,77 @@ class json_pointer
...
@@ -692,6 +693,77 @@ class json_pointer
return
*
ptr
;
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
@brief split the string input to reference tokens
...
@@ -813,7 +885,7 @@ class json_pointer
...
@@ -813,7 +885,7 @@ class json_pointer
const
BasicJsonType
&
value
,
const
BasicJsonType
&
value
,
BasicJsonType
&
result
)
BasicJsonType
&
result
)
{
{
switch
(
value
.
m_type
)
switch
(
value
.
type
()
)
{
{
case
detail
:
:
value_t
::
array
:
case
detail
:
:
value_t
::
array
:
{
{
...
...
include/nlohmann/json.hpp
View file @
104c5c19
...
@@ -4001,15 +4001,48 @@ class basic_json
...
@@ -4001,15 +4001,48 @@ class basic_json
@liveexample{The following code shows an example for `contains()`.,contains}
@liveexample{The following code shows an example for `contains()`.,contains}
@sa @ref find(KeyT&&) -- returns an iterator to an object element
@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
@since version 3.6.0
*/
*/
template
<
typename
KeyT
>
template
<
typename
KeyT
,
typename
std
::
enable_if
<
bool
contains
(
KeyT
&&
key
)
const
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
();
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
);
}
/// @}
/// @}
...
...
single_include/nlohmann/json.hpp
View file @
104c5c19
...
@@ -8455,6 +8455,7 @@ class json_reverse_iterator : public std::reverse_iterator<Base>
...
@@ -8455,6 +8455,7 @@ class json_reverse_iterator : public std::reverse_iterator<Base>
#include <algorithm> // all_of
#include <algorithm> // all_of
#include <cassert> // assert
#include <cassert> // assert
#include <cctype> // isdigit
#include <numeric> // accumulate
#include <numeric> // accumulate
#include <string> // string
#include <string> // string
#include <utility> // move
#include <utility> // move
...
@@ -8825,7 +8826,7 @@ class json_pointer
...
@@ -8825,7 +8826,7 @@ class json_pointer
// j which will be overwritten by a primitive 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
->
type
()
)
{
{
case
detail
:
:
value_t
::
null
:
case
detail
:
:
value_t
::
null
:
{
{
...
@@ -8902,14 +8903,14 @@ class json_pointer
...
@@ -8902,14 +8903,14 @@ class json_pointer
for
(
const
auto
&
reference_token
:
reference_tokens
)
for
(
const
auto
&
reference_token
:
reference_tokens
)
{
{
// convert null values to arrays or objects before continuing
// 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
// check if reference token is a number
const
bool
nums
=
const
bool
nums
=
std
::
all_of
(
reference_token
.
begin
(),
reference_token
.
end
(),
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
// change value to array for numbers or "-" or to object otherwise
...
@@ -8918,7 +8919,7 @@ class json_pointer
...
@@ -8918,7 +8919,7 @@ class json_pointer
:
detail
::
value_t
::
object
;
:
detail
::
value_t
::
object
;
}
}
switch
(
ptr
->
m_type
)
switch
(
ptr
->
type
()
)
{
{
case
detail
:
:
value_t
::
object
:
case
detail
:
:
value_t
::
object
:
{
{
...
@@ -8977,7 +8978,7 @@ class json_pointer
...
@@ -8977,7 +8978,7 @@ class json_pointer
using
size_type
=
typename
BasicJsonType
::
size_type
;
using
size_type
=
typename
BasicJsonType
::
size_type
;
for
(
const
auto
&
reference_token
:
reference_tokens
)
for
(
const
auto
&
reference_token
:
reference_tokens
)
{
{
switch
(
ptr
->
m_type
)
switch
(
ptr
->
type
()
)
{
{
case
detail
:
:
value_t
::
object
:
case
detail
:
:
value_t
::
object
:
{
{
...
@@ -9042,7 +9043,7 @@ class json_pointer
...
@@ -9042,7 +9043,7 @@ class json_pointer
using
size_type
=
typename
BasicJsonType
::
size_type
;
using
size_type
=
typename
BasicJsonType
::
size_type
;
for
(
const
auto
&
reference_token
:
reference_tokens
)
for
(
const
auto
&
reference_token
:
reference_tokens
)
{
{
switch
(
ptr
->
m_type
)
switch
(
ptr
->
type
()
)
{
{
case
detail
:
:
value_t
::
object
:
case
detail
:
:
value_t
::
object
:
{
{
...
@@ -9101,7 +9102,7 @@ class json_pointer
...
@@ -9101,7 +9102,7 @@ class json_pointer
using
size_type
=
typename
BasicJsonType
::
size_type
;
using
size_type
=
typename
BasicJsonType
::
size_type
;
for
(
const
auto
&
reference_token
:
reference_tokens
)
for
(
const
auto
&
reference_token
:
reference_tokens
)
{
{
switch
(
ptr
->
m_type
)
switch
(
ptr
->
type
()
)
{
{
case
detail
:
:
value_t
::
object
:
case
detail
:
:
value_t
::
object
:
{
{
...
@@ -9148,6 +9149,77 @@ class json_pointer
...
@@ -9148,6 +9149,77 @@ class json_pointer
return
*
ptr
;
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
@brief split the string input to reference tokens
...
@@ -9269,7 +9341,7 @@ class json_pointer
...
@@ -9269,7 +9341,7 @@ class json_pointer
const
BasicJsonType
&
value
,
const
BasicJsonType
&
value
,
BasicJsonType
&
result
)
BasicJsonType
&
result
)
{
{
switch
(
value
.
m_type
)
switch
(
value
.
type
()
)
{
{
case
detail
:
:
value_t
::
array
:
case
detail
:
:
value_t
::
array
:
{
{
...
@@ -16812,15 +16884,48 @@ class basic_json
...
@@ -16812,15 +16884,48 @@ class basic_json
@liveexample{The following code shows an example for `contains()`.,contains}
@liveexample{The following code shows an example for `contains()`.,contains}
@sa @ref find(KeyT&&) -- returns an iterator to an object element
@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
@since version 3.6.0
*/
*/
template
<
typename
KeyT
>
template
<
typename
KeyT
,
typename
std
::
enable_if
<
bool
contains
(
KeyT
&&
key
)
const
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
();
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
);
}
/// @}
/// @}
...
...
test/src/unit-json_pointer.cpp
View file @
104c5c19
...
@@ -90,12 +90,18 @@ TEST_CASE("JSON pointers")
...
@@ -90,12 +90,18 @@ TEST_CASE("JSON pointers")
// the whole document
// the whole document
CHECK
(
j
[
json
::
json_pointer
()]
==
j
);
CHECK
(
j
[
json
::
json_pointer
()]
==
j
);
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
// array access
CHECK
(
j
[
json
::
json_pointer
(
"/foo"
)]
==
j
[
"foo"
]);
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/0"
)]
==
j
[
"foo"
][
0
]);
CHECK
(
j
[
json
::
json_pointer
(
"/foo/1"
)]
==
j
[
"foo"
][
1
]);
CHECK
(
j
[
json
::
json_pointer
(
"/foo/1"
)]
==
j
[
"foo"
][
1
]);
CHECK
(
j
[
"/foo/1"
_json_pointer
]
==
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
// checked array access
CHECK
(
j
.
at
(
json
::
json_pointer
(
"/foo/0"
))
==
j
[
"foo"
][
0
]);
CHECK
(
j
.
at
(
json
::
json_pointer
(
"/foo/0"
))
==
j
[
"foo"
][
0
]);
...
@@ -103,6 +109,8 @@ TEST_CASE("JSON pointers")
...
@@ -103,6 +109,8 @@ TEST_CASE("JSON pointers")
// empty string access
// empty string access
CHECK
(
j
[
json
::
json_pointer
(
"/"
)]
==
j
[
""
]);
CHECK
(
j
[
json
::
json_pointer
(
"/"
)]
==
j
[
""
]);
CHECK
(
j
.
contains
(
json
::
json_pointer
(
""
)));
CHECK
(
j
.
contains
(
json
::
json_pointer
(
"/"
)));
// other cases
// other cases
CHECK
(
j
[
json
::
json_pointer
(
"/ "
)]
==
j
[
" "
]);
CHECK
(
j
[
json
::
json_pointer
(
"/ "
)]
==
j
[
" "
]);
...
@@ -112,6 +120,14 @@ TEST_CASE("JSON pointers")
...
@@ -112,6 +120,14 @@ TEST_CASE("JSON pointers")
CHECK
(
j
[
json
::
json_pointer
(
"/i
\\
j"
)]
==
j
[
"i
\\
j"
]);
CHECK
(
j
[
json
::
json_pointer
(
"/i
\\
j"
)]
==
j
[
"i
\\
j"
]);
CHECK
(
j
[
json
::
json_pointer
(
"/k
\"
l"
)]
==
j
[
"k
\"
l"
]);
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
// checked access
CHECK
(
j
.
at
(
json
::
json_pointer
(
"/ "
))
==
j
[
" "
]);
CHECK
(
j
.
at
(
json
::
json_pointer
(
"/ "
))
==
j
[
" "
]);
CHECK
(
j
.
at
(
json
::
json_pointer
(
"/c%d"
))
==
j
[
"c%d"
]);
CHECK
(
j
.
at
(
json
::
json_pointer
(
"/c%d"
))
==
j
[
"c%d"
]);
...
@@ -123,14 +139,24 @@ TEST_CASE("JSON pointers")
...
@@ -123,14 +139,24 @@ TEST_CASE("JSON pointers")
// escaped access
// escaped access
CHECK
(
j
[
json
::
json_pointer
(
"/a~1b"
)]
==
j
[
"a/b"
]);
CHECK
(
j
[
json
::
json_pointer
(
"/a~1b"
)]
==
j
[
"a/b"
]);
CHECK
(
j
[
json
::
json_pointer
(
"/m~0n"
)]
==
j
[
"m~n"
]);
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
// unescaped access
// access to nonexisting values yield object creation
// 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_NOTHROW
(
j
[
json
::
json_pointer
(
"/a/b"
)]
=
42
);
CHECK
(
j
.
contains
(
json
::
json_pointer
(
"/a/b"
)));
CHECK
(
j
[
"a"
][
"b"
]
==
json
(
42
));
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_NOTHROW
(
j
[
json
::
json_pointer
(
"/a/c/1"
)]
=
42
);
CHECK
(
j
[
"a"
][
"c"
]
==
json
({
nullptr
,
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_NOTHROW
(
j
[
json
::
json_pointer
(
"/a/d/-"
)]
=
42
);
CHECK
(
not
j
.
contains
(
json
::
json_pointer
(
"/a/d/-"
)));
CHECK
(
j
[
"a"
][
"d"
]
==
json
::
array
({
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
));
...
@@ -143,6 +169,7 @@ TEST_CASE("JSON pointers")
...
@@ -143,6 +169,7 @@ TEST_CASE("JSON pointers")
CHECK_THROWS_AS
(
j_primitive
.
at
(
"/foo"
_json_pointer
),
json
::
out_of_range
&
);
CHECK_THROWS_AS
(
j_primitive
.
at
(
"/foo"
_json_pointer
),
json
::
out_of_range
&
);
CHECK_THROWS_WITH
(
j_primitive
.
at
(
"/foo"
_json_pointer
),
CHECK_THROWS_WITH
(
j_primitive
.
at
(
"/foo"
_json_pointer
),
"[json.exception.out_of_range.404] unresolved reference token 'foo'"
);
"[json.exception.out_of_range.404] unresolved reference token 'foo'"
);
CHECK
(
not
j_primitive
.
contains
(
json
::
json_pointer
(
"/foo"
)));
}
}
SECTION
(
"const access"
)
SECTION
(
"const access"
)
...
@@ -233,11 +260,16 @@ TEST_CASE("JSON pointers")
...
@@ -233,11 +260,16 @@ TEST_CASE("JSON pointers")
// the whole document
// the whole document
CHECK
(
j
[
""
_json_pointer
]
==
j
);
CHECK
(
j
[
""
_json_pointer
]
==
j
);
CHECK
(
j
.
contains
(
""
_json_pointer
));
// array access
// array access
CHECK
(
j
[
"/foo"
_json_pointer
]
==
j
[
"foo"
]);
CHECK
(
j
[
"/foo"
_json_pointer
]
==
j
[
"foo"
]);
CHECK
(
j
[
"/foo/0"
_json_pointer
]
==
j
[
"foo"
][
0
]);
CHECK
(
j
[
"/foo/0"
_json_pointer
]
==
j
[
"foo"
][
0
]);
CHECK
(
j
[
"/foo/1"
_json_pointer
]
==
j
[
"foo"
][
1
]);
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")
...
@@ -278,6 +310,12 @@ TEST_CASE("JSON pointers")
CHECK_THROWS_AS
(
j_const
.
at
(
"/01"
_json_pointer
),
json
::
parse_error
&
);
CHECK_THROWS_AS
(
j_const
.
at
(
"/01"
_json_pointer
),
json
::
parse_error
&
);
CHECK_THROWS_WITH
(
j_const
.
at
(
"/01"
_json_pointer
),
CHECK_THROWS_WITH
(
j_const
.
at
(
"/01"
_json_pointer
),
"[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"
);
"[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
// error with incorrect numbers
CHECK_THROWS_AS
(
j
[
"/one"
_json_pointer
]
=
1
,
json
::
parse_error
&
);
CHECK_THROWS_AS
(
j
[
"/one"
_json_pointer
]
=
1
,
json
::
parse_error
&
);
...
@@ -294,6 +332,13 @@ TEST_CASE("JSON pointers")
...
@@ -294,6 +332,13 @@ TEST_CASE("JSON pointers")
CHECK_THROWS_WITH
(
j_const
.
at
(
"/one"
_json_pointer
)
==
1
,
CHECK_THROWS_WITH
(
j_const
.
at
(
"/one"
_json_pointer
)
==
1
,
"[json.exception.parse_error.109] parse error: array index 'one' is not a number"
);
"[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_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
(),
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"
);
"[json.exception.parse_error.109] parse error: array index 'three' is not a number"
);
...
@@ -306,6 +351,7 @@ TEST_CASE("JSON pointers")
...
@@ -306,6 +351,7 @@ TEST_CASE("JSON pointers")
CHECK_THROWS_AS
(
j_const
[
"/-"
_json_pointer
],
json
::
out_of_range
&
);
CHECK_THROWS_AS
(
j_const
[
"/-"
_json_pointer
],
json
::
out_of_range
&
);
CHECK_THROWS_WITH
(
j_const
[
"/-"
_json_pointer
],
CHECK_THROWS_WITH
(
j_const
[
"/-"
_json_pointer
],
"[json.exception.out_of_range.402] array index '-' (3) is out of range"
);
"[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
// error when using "-" with at
CHECK_THROWS_AS
(
j
.
at
(
"/-"
_json_pointer
),
json
::
out_of_range
&
);
CHECK_THROWS_AS
(
j
.
at
(
"/-"
_json_pointer
),
json
::
out_of_range
&
);
...
@@ -314,6 +360,7 @@ TEST_CASE("JSON pointers")
...
@@ -314,6 +360,7 @@ TEST_CASE("JSON pointers")
CHECK_THROWS_AS
(
j_const
.
at
(
"/-"
_json_pointer
),
json
::
out_of_range
&
);
CHECK_THROWS_AS
(
j_const
.
at
(
"/-"
_json_pointer
),
json
::
out_of_range
&
);
CHECK_THROWS_WITH
(
j_const
.
at
(
"/-"
_json_pointer
),
CHECK_THROWS_WITH
(
j_const
.
at
(
"/-"
_json_pointer
),
"[json.exception.out_of_range.402] array index '-' (3) is out of range"
);
"[json.exception.out_of_range.402] array index '-' (3) is out of range"
);
CHECK
(
not
j_const
.
contains
(
"/-"
_json_pointer
));
}
}
SECTION
(
"const access"
)
SECTION
(
"const access"
)
...
@@ -329,11 +376,13 @@ TEST_CASE("JSON pointers")
...
@@ -329,11 +376,13 @@ TEST_CASE("JSON pointers")
CHECK_THROWS_AS
(
j
.
at
(
"/3"
_json_pointer
),
json
::
out_of_range
&
);
CHECK_THROWS_AS
(
j
.
at
(
"/3"
_json_pointer
),
json
::
out_of_range
&
);
CHECK_THROWS_WITH
(
j
.
at
(
"/3"
_json_pointer
),
CHECK_THROWS_WITH
(
j
.
at
(
"/3"
_json_pointer
),
"[json.exception.out_of_range.401] array index 3 is out of range"
);
"[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)
// assign to nonexisting index (with gap)
CHECK_THROWS_AS
(
j
.
at
(
"/5"
_json_pointer
),
json
::
out_of_range
&
);
CHECK_THROWS_AS
(
j
.
at
(
"/5"
_json_pointer
),
json
::
out_of_range
&
);
CHECK_THROWS_WITH
(
j
.
at
(
"/5"
_json_pointer
),
CHECK_THROWS_WITH
(
j
.
at
(
"/5"
_json_pointer
),
"[json.exception.out_of_range.401] array index 5 is out of range"
);
"[json.exception.out_of_range.401] array index 5 is out of range"
);
CHECK
(
not
j
.
contains
(
"/5"
_json_pointer
));
// assign to "-"
// assign to "-"
CHECK_THROWS_AS
(
j
[
"/-"
_json_pointer
],
json
::
out_of_range
&
);
CHECK_THROWS_AS
(
j
[
"/-"
_json_pointer
],
json
::
out_of_range
&
);
...
@@ -342,8 +391,8 @@ TEST_CASE("JSON pointers")
...
@@ -342,8 +391,8 @@ TEST_CASE("JSON pointers")
CHECK_THROWS_AS
(
j
.
at
(
"/-"
_json_pointer
),
json
::
out_of_range
&
);
CHECK_THROWS_AS
(
j
.
at
(
"/-"
_json_pointer
),
json
::
out_of_range
&
);
CHECK_THROWS_WITH
(
j
.
at
(
"/-"
_json_pointer
),
CHECK_THROWS_WITH
(
j
.
at
(
"/-"
_json_pointer
),
"[json.exception.out_of_range.402] array index '-' (3) is out of range"
);
"[json.exception.out_of_range.402] array index '-' (3) is out of range"
);
CHECK
(
not
j
.
contains
(
"/-"
_json_pointer
));
}
}
}
}
SECTION
(
"flatten"
)
SECTION
(
"flatten"
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment