diff --git a/README.md b/README.md index b671f357..11d350ef 100644 --- a/README.md +++ b/README.md @@ -398,7 +398,7 @@ $ make $ ./json_unit "*" =============================================================================== -All tests passed (3341848 assertions in 28 test cases) +All tests passed (3341888 assertions in 28 test cases) ``` For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). diff --git a/doc/examples/at__object_t_key_type.cpp b/doc/examples/at__object_t_key_type.cpp index 85de5656..29c24c0c 100644 --- a/doc/examples/at__object_t_key_type.cpp +++ b/doc/examples/at__object_t_key_type.cpp @@ -26,8 +26,8 @@ int main() { object.at("the fast") = "il rapido"; } - catch (std::out_of_range) + catch (std::out_of_range& e) { - std::cout << "out of range" << '\n'; + std::cout << "out of range: " << e.what() << '\n'; } } diff --git a/doc/examples/at__object_t_key_type.link b/doc/examples/at__object_t_key_type.link index 1f495637..beba6a0f 100644 --- a/doc/examples/at__object_t_key_type.link +++ b/doc/examples/at__object_t_key_type.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at__object_t_key_type.output b/doc/examples/at__object_t_key_type.output index 90ccb1cd..79cff2d7 100644 --- a/doc/examples/at__object_t_key_type.output +++ b/doc/examples/at__object_t_key_type.output @@ -1,3 +1,3 @@ "il brutto" {"the bad":"il cattivo","the good":"il buono","the ugly":"il brutto"} -out of range +out of range: key 'the fast' not found diff --git a/doc/examples/at__size_type.cpp b/doc/examples/at__size_type.cpp index 5195005e..617485bf 100644 --- a/doc/examples/at__size_type.cpp +++ b/doc/examples/at__size_type.cpp @@ -21,8 +21,8 @@ int main() { array.at(5) = "sixth"; } - catch (std::out_of_range) + catch (std::out_of_range& e) { - std::cout << "out of range" << '\n'; + std::cout << "out of range: " << e.what() << '\n'; } } diff --git a/doc/examples/at__size_type.link b/doc/examples/at__size_type.link index 49830f7b..a5ce10e4 100644 --- a/doc/examples/at__size_type.link +++ b/doc/examples/at__size_type.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at__size_type.output b/doc/examples/at__size_type.output index 93748f7f..d1f68bdb 100644 --- a/doc/examples/at__size_type.output +++ b/doc/examples/at__size_type.output @@ -1,3 +1,3 @@ "third" ["first","second","third","fourth"] -out of range +out of range: array index 5 is out of range diff --git a/src/json.hpp b/src/json.hpp index e11bae2d..ee6b1743 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -2602,9 +2602,10 @@ class basic_json @return reference to the element at index @a idx - @throw std::domain_error if JSON is not an array + @throw std::domain_error if the JSON value is not an array; example: + `"cannot use at() with string"` @throw std::out_of_range if the index @a idx is out of range of the array; - that is, `idx >= size()` + that is, `idx >= size()`; example: `"array index 7 is out of range"` @complexity Constant. @@ -2618,7 +2619,15 @@ class basic_json // at only works for arrays if (is_array()) { - return m_value.array->at(idx); + try + { + return m_value.array->at(idx); + } + catch (std::out_of_range& e) + { + // create better exception explanation + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } } else { @@ -2636,9 +2645,10 @@ class basic_json @return const reference to the element at index @a idx - @throw std::domain_error if JSON is not an array + @throw std::domain_error if the JSON value is not an array; example: + `"cannot use at() with string"` @throw std::out_of_range if the index @a idx is out of range of the array; - that is, `idx >= size()` + that is, `idx >= size()`; example: `"array index 7 is out of range"` @complexity Constant. @@ -2652,7 +2662,15 @@ class basic_json // at only works for arrays if (is_array()) { - return m_value.array->at(idx); + try + { + return m_value.array->at(idx); + } + catch (std::out_of_range& e) + { + // create better exception explanation + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } } else { @@ -2670,9 +2688,10 @@ class basic_json @return reference to the element at key @a key - @throw std::domain_error if JSON is not an object + @throw std::domain_error if the JSON value is not an object; example: + `"cannot use at() with boolean"` @throw std::out_of_range if the key @a key is is not stored in the object; - that is, `find(key) == end()` + that is, `find(key) == end()`; example: `"key "the fast" not found"` @complexity Logarithmic in the size of the container. @@ -2690,7 +2709,15 @@ class basic_json // at only works for objects if (is_object()) { - return m_value.object->at(key); + try + { + return m_value.object->at(key); + } + catch (std::out_of_range& e) + { + // create better exception explanation + throw std::out_of_range("key '" + key + "' not found"); + } } else { @@ -2708,9 +2735,10 @@ class basic_json @return const reference to the element at key @a key - @throw std::domain_error if JSON is not an object + @throw std::domain_error if the JSON value is not an object; example: + `"cannot use at() with boolean"` @throw std::out_of_range if the key @a key is is not stored in the object; - that is, `find(key) == end()` + that is, `find(key) == end()`; example: `"key "the fast" not found"` @complexity Logarithmic in the size of the container. @@ -2728,7 +2756,15 @@ class basic_json // at only works for objects if (is_object()) { - return m_value.object->at(key); + try + { + return m_value.object->at(key); + } + catch (std::out_of_range& e) + { + // create better exception explanation + throw std::out_of_range("key '" + key + "' not found"); + } } else { diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 119ec5c2..cea396d6 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2602,9 +2602,10 @@ class basic_json @return reference to the element at index @a idx - @throw std::domain_error if JSON is not an array + @throw std::domain_error if the JSON value is not an array; example: + `"cannot use at() with string"` @throw std::out_of_range if the index @a idx is out of range of the array; - that is, `idx >= size()` + that is, `idx >= size()`; example: `"array index 7 is out of range"` @complexity Constant. @@ -2618,7 +2619,15 @@ class basic_json // at only works for arrays if (is_array()) { - return m_value.array->at(idx); + try + { + return m_value.array->at(idx); + } + catch (std::out_of_range& e) + { + // create better exception explanation + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } } else { @@ -2636,9 +2645,10 @@ class basic_json @return const reference to the element at index @a idx - @throw std::domain_error if JSON is not an array + @throw std::domain_error if the JSON value is not an array; example: + `"cannot use at() with string"` @throw std::out_of_range if the index @a idx is out of range of the array; - that is, `idx >= size()` + that is, `idx >= size()`; example: `"array index 7 is out of range"` @complexity Constant. @@ -2652,7 +2662,15 @@ class basic_json // at only works for arrays if (is_array()) { - return m_value.array->at(idx); + try + { + return m_value.array->at(idx); + } + catch (std::out_of_range& e) + { + // create better exception explanation + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } } else { @@ -2670,9 +2688,10 @@ class basic_json @return reference to the element at key @a key - @throw std::domain_error if JSON is not an object + @throw std::domain_error if the JSON value is not an object; example: + `"cannot use at() with boolean"` @throw std::out_of_range if the key @a key is is not stored in the object; - that is, `find(key) == end()` + that is, `find(key) == end()`; example: `"key "the fast" not found"` @complexity Logarithmic in the size of the container. @@ -2690,7 +2709,15 @@ class basic_json // at only works for objects if (is_object()) { - return m_value.object->at(key); + try + { + return m_value.object->at(key); + } + catch (std::out_of_range& e) + { + // create better exception explanation + throw std::out_of_range("key '" + key + "' not found"); + } } else { @@ -2708,9 +2735,10 @@ class basic_json @return const reference to the element at key @a key - @throw std::domain_error if JSON is not an object + @throw std::domain_error if the JSON value is not an object; example: + `"cannot use at() with boolean"` @throw std::out_of_range if the key @a key is is not stored in the object; - that is, `find(key) == end()` + that is, `find(key) == end()`; example: `"key "the fast" not found"` @complexity Logarithmic in the size of the container. @@ -2728,7 +2756,15 @@ class basic_json // at only works for objects if (is_object()) { - return m_value.object->at(key); + try + { + return m_value.object->at(key); + } + catch (std::out_of_range& e) + { + // create better exception explanation + throw std::out_of_range("key '" + key + "' not found"); + } } else { diff --git a/test/unit.cpp b/test/unit.cpp index e52128ce..3a89e94f 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -2662,6 +2662,16 @@ TEST_CASE("element access") { CHECK_THROWS_AS(j.at(7), std::out_of_range); CHECK_THROWS_AS(j_const.at(7), std::out_of_range); + + // exception name + try + { + j.at(7); + } + catch (std::out_of_range& e) + { + CHECK(std::string(e.what()) == "array index 7 is out of range"); + } } SECTION("access on non-array type") @@ -2672,6 +2682,16 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + // exception name + try + { + j_nonarray.at(0); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with null"); + } } SECTION("boolean") @@ -2680,6 +2700,16 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + // exception name + try + { + j_nonarray.at(0); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with boolean"); + } } SECTION("string") @@ -2688,6 +2718,16 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + // exception name + try + { + j_nonarray.at(0); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with string"); + } } SECTION("object") @@ -2696,6 +2736,16 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + // exception name + try + { + j_nonarray.at(0); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with object"); + } } SECTION("number (integer)") @@ -2704,6 +2754,16 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + // exception name + try + { + j_nonarray.at(0); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with number"); + } } SECTION("number (floating-point)") @@ -2712,6 +2772,16 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + // exception name + try + { + j_nonarray.at(0); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with number"); + } } } } @@ -3028,6 +3098,16 @@ TEST_CASE("element access") { CHECK_THROWS_AS(j.at("foo"), std::out_of_range); CHECK_THROWS_AS(j_const.at("foo"), std::out_of_range); + + // exception name + try + { + j.at("foo"); + } + catch (std::out_of_range& e) + { + CHECK(std::string(e.what()) == "key 'foo' not found"); + } } SECTION("access on non-object type") @@ -3038,6 +3118,16 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); + + // exception name + try + { + j_nonobject.at("foo"); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with null"); + } } SECTION("boolean") @@ -3046,6 +3136,16 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); + + // exception name + try + { + j_nonobject.at("foo"); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with boolean"); + } } SECTION("string") @@ -3054,6 +3154,16 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); + + // exception name + try + { + j_nonobject.at("foo"); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with string"); + } } SECTION("array") @@ -3062,6 +3172,16 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); + + // exception name + try + { + j_nonobject.at("foo"); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with array"); + } } SECTION("number (integer)") @@ -3070,6 +3190,16 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); + + // exception name + try + { + j_nonobject.at("foo"); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with number"); + } } SECTION("number (floating-point)") @@ -3078,6 +3208,16 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); + + // exception name + try + { + j_nonobject.at("foo"); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with number"); + } } } }