Skip to content

Commit b2b9c76

Browse files
author
Blake Gross
committed
Added parsing overload functions and added better unit test coverage
1 parent 4195bcc commit b2b9c76

File tree

4 files changed

+142
-9
lines changed

4 files changed

+142
-9
lines changed

Release/include/cpprest/json.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ namespace json
395395
/// Attempts to parse a string and construct a JSON value.
396396
/// </summary>
397397
/// <param name="value">The C++ value to create a JSON value from, a C++ STL double-byte string</param>
398-
/// <param name="errorCode">If parsing fails, the error code is filled with a protocol error</param>
398+
/// <param name="errorCode">If parsing fails, the error code is greater than 0</param>
399399
/// <returns>The parsed object. Returns web::json::value::null if failed</returns>
400400
_ASYNCRTIMP static value parse(const utility::string_t&, std::error_code&);
401401

@@ -419,6 +419,14 @@ namespace json
419419
/// <returns>The JSON value object created from the input stream.</returns>
420420
_ASYNCRTIMP static value parse(utility::istream_t &input);
421421

422+
/// <summary>
423+
/// Parses a JSON value from the contents of an input stream using the native platform character width.
424+
/// </summary>
425+
/// <param name="input">The stream to read the JSON value from</param>
426+
/// <param name="errorCode">If parsing fails, the error code is greater than 0</param>
427+
/// <returns>The parsed object. Returns web::json::value::null if failed</returns>
428+
_ASYNCRTIMP static value parse(utility::istream_t &input, std::error_code& error);
429+
422430
/// <summary>
423431
/// Writes the current JSON value to a stream with the native platform character width.
424432
/// </summary>
@@ -432,6 +440,14 @@ namespace json
432440
/// <param name="stream">The stream to read the JSON value from</param>
433441
_ASYNCRTIMP static value parse(std::istream& stream);
434442

443+
/// <summary>
444+
/// Parses a JSON value from the contents of a single-byte (UTF8) stream.
445+
/// </summary>
446+
/// <param name="stream">The stream to read the JSON value from</param>
447+
/// <param name="errorCode">If parsing fails, the error code is greater than 0</param>
448+
/// <returns>The parsed object. Returns web::json::value::null if failed</returns>
449+
_ASYNCRTIMP static value parse(std::istream& stream, std::error_code& error);
450+
435451
/// <summary>
436452
/// Serializes the content of the value into a single-byte (UTF8) stream.
437453
/// </summary>

Release/src/json/json_parsing.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,6 +1208,31 @@ static web::json::value _parse_stream(utility::istream_t &stream)
12081208
return value;
12091209
}
12101210

1211+
static web::json::value _parse_stream(utility::istream_t &stream, std::error_code& error)
1212+
{
1213+
web::json::details::JSON_StreamParser<utility::char_t> parser(stream);
1214+
1215+
web::json::details::JSON_Parser<utility::char_t>::Token tkn;
1216+
1217+
parser.GetNextToken(tkn);
1218+
1219+
web::json::value returnObject;
1220+
1221+
if (tkn.err.value() == 0)
1222+
{
1223+
returnObject = parser.ParseValue(tkn);
1224+
1225+
if (tkn.kind != web::json::details::JSON_Parser<utility::char_t>::Token::TKN_EOF)
1226+
{
1227+
returnObject = web::json::value();
1228+
web::json::details::SetErrorCode(tkn, web::json::details::json_error::left_over_character_in_stream);
1229+
}
1230+
}
1231+
1232+
error = std::move(tkn.err);
1233+
return returnObject;
1234+
}
1235+
12111236
#ifdef _MS_WINDOWS
12121237
static web::json::value _parse_narrow_stream(std::istream &stream)
12131238
{
@@ -1235,6 +1260,31 @@ static web::json::value _parse_narrow_stream(std::istream &stream)
12351260
}
12361261
return value;
12371262
}
1263+
1264+
static web::json::value _parse_narrow_stream(std::istream &stream, std::error_code& error)
1265+
{
1266+
web::json::details::JSON_StreamParser<char> parser(stream);
1267+
1268+
web::json::details::JSON_StreamParser<char>::Token tkn;
1269+
1270+
parser.GetNextToken(tkn);
1271+
1272+
web::json::value returnObject;
1273+
1274+
if (tkn.err.value() == 0)
1275+
{
1276+
returnObject = parser.ParseValue(tkn);
1277+
1278+
if (tkn.kind != web::json::details::JSON_Parser<utility::char_t>::Token::TKN_EOF)
1279+
{
1280+
returnObject = web::json::value();
1281+
web::json::details::SetErrorCode(tkn, web::json::details::json_error::left_over_character_in_stream);
1282+
}
1283+
}
1284+
1285+
error = std::move(tkn.err);
1286+
return returnObject;
1287+
}
12381288
#endif
12391289

12401290
web::json::value web::json::value::parse(const utility::string_t& str)
@@ -1268,6 +1318,7 @@ web::json::value web::json::value::parse(const utility::string_t& str, std::erro
12681318
web::json::details::JSON_StringParser<utility::char_t> parser(str);
12691319

12701320
web::json::details::JSON_Parser<utility::char_t>::Token tkn;
1321+
12711322
parser.GetNextToken(tkn);
12721323

12731324
web::json::value returnObject;
@@ -1292,9 +1343,19 @@ web::json::value web::json::value::parse(utility::istream_t &stream)
12921343
return _parse_stream(stream);
12931344
}
12941345

1346+
web::json::value web::json::value::parse(utility::istream_t &stream, std::error_code& error)
1347+
{
1348+
return _parse_stream(stream, error);
1349+
}
1350+
12951351
#ifdef _MS_WINDOWS
12961352
web::json::value web::json::value::parse(std::istream& stream)
12971353
{
12981354
return _parse_narrow_stream(stream);
12991355
}
1356+
1357+
web::json::value web::json::value::parse(std::istream& stream, std::error_code& error)
1358+
{
1359+
return _parse_narrow_stream(stream, error);
1360+
}
13001361
#endif

Release/tests/functional/json/negative_parsing_tests.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ namespace tests { namespace functional { namespace json_tests {
3838
VERIFY_IS_TRUE(ec_.value() > 0); \
3939
VERIFY_IS_TRUE(value_.is_null()); \
4040
}
41-
4241
#endif
4342

4443
SUITE(negative_parsing_tests)
@@ -155,7 +154,7 @@ TEST(stream_left_over_chars)
155154
std::stringbuf buf;
156155
buf.sputn("[false]false", 12);
157156
std::istream stream(&buf);
158-
VERIFY_THROWS(web::json::value::parse(stream), json::json_exception);
157+
VERIFY_JSON_THROWS(stream);
159158
}
160159

161160
// Test using Windows only API.
@@ -165,7 +164,7 @@ TEST(wstream_left_over_chars)
165164
std::wstringbuf buf;
166165
buf.sputn(L"[false]false", 12);
167166
std::wistream stream(&buf);
168-
VERIFY_THROWS(web::json::value::parse(stream), json::json_exception);
167+
VERIFY_JSON_THROWS(stream);
169168
}
170169
#endif
171170

Release/tests/functional/json/parsing_tests.cpp

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ do { \
6868
} \
6969
} while (false)
7070

71+
72+
#define JSON_TEST_HELPER(jsonData) \
73+
{ \
74+
std::error_code err; \
75+
auto parsedObject = web::json::value::parse(jsonData, err); \
76+
\
77+
VERIFY_IS_TRUE(err.value() == 0); \
78+
VERIFY_IS_TRUE(!parsedObject.is_null()); \
79+
}
80+
7181
SUITE(parsing_tests)
7282
{
7383

@@ -616,21 +626,68 @@ TEST(non_default_locale)
616626
TEST(parse_overload_success)
617627
{
618628
std::error_code err;
619-
utility::string_t str(U("\"JSONString\""));
620-
json::value parsedObject = json::value::parse(str, err);
629+
utility::string_t valueStr(U("\"JSONString\""));
630+
utility::string_t arrStr(U("[true,false,-1.55,5,null,{\"abc\":5555}]"));
631+
utility::string_t objStr(U("{\"k\":3, \"j\":2, \"i\":1}"));
632+
633+
JSON_TEST_HELPER(valueStr);
634+
JSON_TEST_HELPER(arrStr);
635+
JSON_TEST_HELPER(objStr);
636+
637+
utility::stringstream_t valueStringStream;
638+
utility::stringstream_t arrayStringStream;
639+
utility::stringstream_t objStringStream;
640+
641+
valueStringStream << valueStr;
642+
arrayStringStream << arrStr;
643+
objStringStream << objStr;
644+
645+
JSON_TEST_HELPER(valueStringStream.str());
646+
JSON_TEST_HELPER(arrayStringStream.str());
647+
JSON_TEST_HELPER(objStringStream.str());
648+
649+
#ifdef _MS_WINDOWS
650+
std::wstringbuf buf;
651+
652+
buf.sputn(valueStr.c_str(), valueStr.size());
653+
std::wistream valStream(&buf);
654+
JSON_TEST_HELPER(valStream);
621655

622-
VERIFY_IS_TRUE(err.value() == 0);
623-
VERIFY_IS_TRUE(!parsedObject.is_null());
656+
buf.sputn(arrStr.c_str(), arrStr.size());
657+
std::wistream arrStream(&buf);
658+
JSON_TEST_HELPER(arrStream);
659+
660+
buf.sputn(objStr.c_str(), objStr.size());
661+
std::wistream objStream(&buf);
662+
JSON_TEST_HELPER(objStream);
663+
#endif
624664
}
625665

626666
TEST(parse_overload_failed)
627667
{
628-
std::error_code err;
668+
std::error_code err, streamErr, iStreamErr;
629669
utility::string_t str(U("JSONString"));
670+
utility::string_t arrStr(U("[true, false"));
630671
json::value parsedObject = json::value::parse(str, err);
631672

632673
VERIFY_IS_TRUE(err.value() > 0);
633674
VERIFY_IS_TRUE(parsedObject.is_null());
675+
676+
utility::stringstream_t stream;
677+
stream << str;
678+
679+
parsedObject = json::value::parse(arrStr, streamErr);
680+
VERIFY_IS_TRUE(streamErr.value() > 0);
681+
VERIFY_IS_TRUE(parsedObject.is_null());
682+
683+
#ifdef _MS_WINDOWS
684+
std::wstringbuf buf;
685+
buf.sputn(str.c_str(), str.size());
686+
std::wistream iStream(&buf);
687+
parsedObject = json::value::parse(str, iStreamErr);
688+
VERIFY_IS_TRUE(iStreamErr.value() > 0);
689+
VERIFY_IS_TRUE(parsedObject.is_null());
690+
#endif
634691
}
635692

636693
} // SUITE(parsing_tests)

0 commit comments

Comments
 (0)