Skip to content

Commit

Permalink
Add more specific error for empty input
Browse files Browse the repository at this point in the history
  • Loading branch information
colbychaskell committed Oct 7, 2023
1 parent edffad0 commit cca9375
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 23 deletions.
24 changes: 12 additions & 12 deletions docs/mkdocs/docs/home/exceptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ Note that [`JSON_THROW_USER`](../api/macros/json_throw_user.md) should leave the

```cpp
#include <iostream>

#define JSON_TRY_USER if(true)
#define JSON_CATCH_USER(exception) if(false)
#define JSON_THROW_USER(exception) \
{std::clog << "Error in " << __FILE__ << ":" << __LINE__ \
<< " (function " << __FUNCTION__ << ") - " \
<< (exception).what() << std::endl; \
std::abort();}

#include <nlohmann/json.hpp>
```

Expand All @@ -63,7 +63,7 @@ Exceptions in the library are thrown in the local context of the JSON value they
```cpp
--8<-- "examples/diagnostics_standard.cpp"
```

Output:

```
Expand All @@ -81,7 +81,7 @@ As this global context comes at the price of storing one additional pointer per
```cpp
--8<-- "examples/diagnostics_extended.cpp"
```

Output:

```
Expand Down Expand Up @@ -116,7 +116,7 @@ Exceptions have ids 1xx.
```cpp
--8<-- "examples/parse_error.cpp"
```

Output:

```
Expand All @@ -139,7 +139,7 @@ This error indicates a syntax error while deserializing a JSON text. The error m
No input:

```
[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal
[json.exception.parse_error.101] parse error at line 1, column 1: attempting to parse an empty input; check that your input string or stream contains the expected JSON
```

Control character was not escaped:
Expand Down Expand Up @@ -368,7 +368,7 @@ Exceptions have ids 2xx.
```cpp
--8<-- "examples/invalid_iterator.cpp"
```

Output:

```
Expand Down Expand Up @@ -532,7 +532,7 @@ Exceptions have ids 3xx.
```cpp
--8<-- "examples/type_error.cpp"
```

Output:

```
Expand Down Expand Up @@ -726,7 +726,7 @@ The `dump()` function only works with UTF-8 encoded strings; that is, if you ass

- Store the source file with UTF-8 encoding.
- Pass an error handler as last parameter to the `dump()` function to avoid this exception:
- `json::error_handler_t::replace` will replace invalid bytes sequences with `U+FFFD`
- `json::error_handler_t::replace` will replace invalid bytes sequences with `U+FFFD`
- `json::error_handler_t::ignore` will silently ignore invalid byte sequences

### json.exception.type_error.317
Expand Down Expand Up @@ -761,7 +761,7 @@ Exceptions have ids 4xx.
```cpp
--8<-- "examples/out_of_range.cpp"
```

Output:

```
Expand Down Expand Up @@ -840,7 +840,7 @@ UBJSON and BSON only support integer numbers up to 9223372036854775807.

!!! note

Since version 3.9.0, integer numbers beyond int64 are serialized as high-precision UBJSON numbers, and this exception does not further occur.
Since version 3.9.0, integer numbers beyond int64 are serialized as high-precision UBJSON numbers, and this exception does not further occur.

### json.exception.out_of_range.408

Expand Down Expand Up @@ -876,7 +876,7 @@ Exceptions have ids 5xx.
```cpp
--8<-- "examples/other_error.cpp"
```

Output:

```
Expand Down
14 changes: 13 additions & 1 deletion include/nlohmann/detail/input/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,13 +341,25 @@ class parser
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr));
}
case token_type::end_of_input:
{
if (JSON_HEDLEY_UNLIKELY(m_lexer.get_position().chars_read_total == 1))
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(),
"attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
}

return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr));
}
case token_type::uninitialized:
case token_type::end_array:
case token_type::end_object:
case token_type::name_separator:
case token_type::value_separator:
case token_type::end_of_input:
case token_type::literal_or_value:
default: // the last token was unexpected
{
Expand Down
15 changes: 14 additions & 1 deletion single_include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12441,13 +12441,26 @@ class parser
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr));
}
case token_type::end_of_input:
{
if (JSON_HEDLEY_UNLIKELY(m_lexer.get_position().chars_read_total == 1))
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(),
"attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
}

return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr));

}
case token_type::uninitialized:
case token_type::end_array:
case token_type::end_object:
case token_type::name_separator:
case token_type::value_separator:
case token_type::end_of_input:
case token_type::literal_or_value:
default: // the last token was unexpected
{
Expand Down
2 changes: 1 addition & 1 deletion tests/src/unit-diagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ TEST_CASE("Better diagnostics")
SECTION("Parse error")
{
json _;
CHECK_THROWS_WITH_AS(_ = json::parse(""), "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error);
CHECK_THROWS_WITH_AS(_ = json::parse(""), "[json.exception.parse_error.101] parse error at line 1, column 1: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error);
}

SECTION("Wrong type in update()")
Expand Down
16 changes: 8 additions & 8 deletions tests/src/unit-regression1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -722,7 +722,7 @@ TEST_CASE("regression tests 1")
{
std::ifstream f("file_not_found.json");
json _;
CHECK_THROWS_WITH_AS(_ = json::parse(f), "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
CHECK_THROWS_WITH_AS(_ = json::parse(f), "[json.exception.parse_error.101] parse error at line 1, column 1: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error&);
}

SECTION("issue #367 - calling stream at EOF")
Expand All @@ -736,7 +736,7 @@ TEST_CASE("regression tests 1")
// ss is not at EOF; this yielded an error before the fix
// (threw basic_string::append). No, it should just throw
// a parse error because of the EOF.
CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error&);
}

SECTION("issue #367 - behavior of operator>> should more closely resemble that of built-in overloads")
Expand All @@ -745,7 +745,7 @@ TEST_CASE("regression tests 1")
{
std::stringstream ss;
json j;
CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error&);
}

SECTION("(whitespace)")
Expand All @@ -765,7 +765,7 @@ TEST_CASE("regression tests 1")
CHECK_NOTHROW(ss >> j);
CHECK(j == 111);

CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error&);
}

SECTION("one value + whitespace")
Expand All @@ -788,7 +788,7 @@ TEST_CASE("regression tests 1")
CHECK_NOTHROW(ss >> j);
CHECK(j == 333);

CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error&);
}

SECTION("three values")
Expand All @@ -803,7 +803,7 @@ TEST_CASE("regression tests 1")
CHECK_NOTHROW(ss >> j);
CHECK(j == 333);

CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error&);
}

SECTION("literals without whitespace")
Expand All @@ -820,7 +820,7 @@ TEST_CASE("regression tests 1")
CHECK_NOTHROW(ss >> j);
CHECK(j == "");

CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error&);
}

SECTION("example from #529")
Expand All @@ -833,7 +833,7 @@ TEST_CASE("regression tests 1")
CHECK_NOTHROW(ss >> j);
CHECK(j == json({{"three", 3}}));

CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error&);
}

SECTION("second example from #529")
Expand Down

0 comments on commit cca9375

Please sign in to comment.