Commit a82ce4ef authored by mgiuca's avatar mgiuca Committed by Commit bot

JSONStringValueSerializer takes a StringPiece instead of std::string&.

This allows callers to pass a char* (string literal) or StringPiece
(lightweight substring) without having to explicitly construct a string
object.

Refactored the implementation to avoid an ugly const_cast and Boolean to
avoid mutating a const pointer. Updated tests to use char* literals, and
added some new tests to test the new edge cases.

BUG=455068

Review URL: https://codereview.chromium.org/895913004

Cr-Commit-Position: refs/heads/master@{#314728}
parent 607b3692
...@@ -12,16 +12,15 @@ using base::Value; ...@@ -12,16 +12,15 @@ using base::Value;
JSONStringValueSerializer::JSONStringValueSerializer(std::string* json_string) JSONStringValueSerializer::JSONStringValueSerializer(std::string* json_string)
: json_string_(json_string), : json_string_(json_string),
initialized_with_const_string_(false), json_string_readonly_(*json_string),
pretty_print_(false), pretty_print_(false),
allow_trailing_comma_(false) { allow_trailing_comma_(false) {
DCHECK(json_string);
} }
JSONStringValueSerializer::JSONStringValueSerializer( JSONStringValueSerializer::JSONStringValueSerializer(
const std::string& json_string) const base::StringPiece& json_string)
: json_string_(&const_cast<std::string&>(json_string)), : json_string_(nullptr),
initialized_with_const_string_(true), json_string_readonly_(json_string),
pretty_print_(false), pretty_print_(false),
allow_trailing_comma_(false) { allow_trailing_comma_(false) {
} }
...@@ -39,7 +38,7 @@ bool JSONStringValueSerializer::SerializeAndOmitBinaryValues( ...@@ -39,7 +38,7 @@ bool JSONStringValueSerializer::SerializeAndOmitBinaryValues(
bool JSONStringValueSerializer::SerializeInternal(const Value& root, bool JSONStringValueSerializer::SerializeInternal(const Value& root,
bool omit_binary_values) { bool omit_binary_values) {
if (initialized_with_const_string_) if (!json_string_)
return false; return false;
int options = 0; int options = 0;
...@@ -53,7 +52,7 @@ bool JSONStringValueSerializer::SerializeInternal(const Value& root, ...@@ -53,7 +52,7 @@ bool JSONStringValueSerializer::SerializeInternal(const Value& root,
Value* JSONStringValueSerializer::Deserialize(int* error_code, Value* JSONStringValueSerializer::Deserialize(int* error_code,
std::string* error_str) { std::string* error_str) {
return base::JSONReader::ReadAndReturnError(*json_string_, return base::JSONReader::ReadAndReturnError(json_string_readonly_,
allow_trailing_comma_ ? base::JSON_ALLOW_TRAILING_COMMAS : allow_trailing_comma_ ? base::JSON_ALLOW_TRAILING_COMMAS :
base::JSON_PARSE_RFC, base::JSON_PARSE_RFC,
error_code, error_str); error_code, error_str);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/base_export.h" #include "base/base_export.h"
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/strings/string_piece.h"
#include "base/values.h" #include "base/values.h"
class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer { class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer {
...@@ -19,10 +20,10 @@ class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer { ...@@ -19,10 +20,10 @@ class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer {
// retains ownership of the string. |json_string| must not be null. // retains ownership of the string. |json_string| must not be null.
explicit JSONStringValueSerializer(std::string* json_string); explicit JSONStringValueSerializer(std::string* json_string);
// This version allows initialization with a const string reference for // This version allows initialization with a StringPiece for deserialization
// deserialization only. Retains a reference to |json_string|, so the string // only. Retains a reference to the contents of |json_string|, so the data
// argument must outlive the JSONStringValueSerializer. // must outlive the JSONStringValueSerializer.
explicit JSONStringValueSerializer(const std::string& json_string); explicit JSONStringValueSerializer(const base::StringPiece& json_string);
~JSONStringValueSerializer() override; ~JSONStringValueSerializer() override;
...@@ -55,8 +56,12 @@ class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer { ...@@ -55,8 +56,12 @@ class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer {
private: private:
bool SerializeInternal(const base::Value& root, bool omit_binary_values); bool SerializeInternal(const base::Value& root, bool omit_binary_values);
std::string* json_string_; // Not null. // String for writing. Owned by the caller of the constructor. Will be null if
bool initialized_with_const_string_; // the serializer was initialized with a const string.
std::string* json_string_;
// String for reading. Data is owned by the caller of the constructor. If
// |json_string_| is non-null, this is a view onto |json_string_|.
base::StringPiece json_string_readonly_;
bool pretty_print_; // If true, serialization will span multiple lines. bool pretty_print_; // If true, serialization will span multiple lines.
// If true, deserialization will allow trailing commas. // If true, deserialization will allow trailing commas.
bool allow_trailing_comma_; bool allow_trailing_comma_;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/json/json_writer.h" #include "base/json/json_writer.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/values.h" #include "base/values.h"
...@@ -42,6 +43,20 @@ const char kProperJSONWithCommas[] = ...@@ -42,6 +43,20 @@ const char kProperJSONWithCommas[] =
"\t\"compound\": { \"a\": 1, \"b\": 2, },\n" "\t\"compound\": { \"a\": 1, \"b\": 2, },\n"
"}\n"; "}\n";
// kProperJSON with a few misc characters at the begin and end.
const char kProperJSONPadded[] =
")]}'\n"
"{\n"
" \"compound\": {\n"
" \"a\": 1,\n"
" \"b\": 2\n"
" },\n"
" \"some_String\": \"1337\",\n"
" \"some_int\": 42,\n"
" \"the_list\": [ \"val1\", \"val2\" ]\n"
"}\n"
"?!ab\n";
const char kWinLineEnds[] = "\r\n"; const char kWinLineEnds[] = "\r\n";
const char kLinuxLineEnds[] = "\n"; const char kLinuxLineEnds[] = "\n";
...@@ -74,7 +89,43 @@ void ValidateJsonList(const std::string& json) { ...@@ -74,7 +89,43 @@ void ValidateJsonList(const std::string& json) {
// Test proper JSON [de]serialization from string is working. // Test proper JSON [de]serialization from string is working.
TEST(JSONValueSerializerTest, ReadProperJSONFromString) { TEST(JSONValueSerializerTest, ReadProperJSONFromString) {
// Try to deserialize it through the serializer. // Try to deserialize it through the serializer.
JSONStringValueSerializer str_deserializer(kProperJSON);
int error_code = 0;
std::string error_message;
scoped_ptr<Value> value(
str_deserializer.Deserialize(&error_code, &error_message));
ASSERT_TRUE(value.get());
ASSERT_EQ(0, error_code);
ASSERT_TRUE(error_message.empty());
// Verify if the same JSON is still there.
CheckJSONIsStillTheSame(*value);
}
// Test proper JSON deserialization from a string pointer is working.
TEST(JSONValueSerializerTest, ReadProperJSONFromStringPointer) {
// Try to deserialize a string pointer through the serializer. (This exercises
// a separate code path to passing a StringPiece.)
std::string proper_json(kProperJSON); std::string proper_json(kProperJSON);
JSONStringValueSerializer str_deserializer(&proper_json);
int error_code = 0;
std::string error_message;
scoped_ptr<Value> value(
str_deserializer.Deserialize(&error_code, &error_message));
ASSERT_TRUE(value.get());
ASSERT_EQ(0, error_code);
ASSERT_TRUE(error_message.empty());
// Verify if the same JSON is still there.
CheckJSONIsStillTheSame(*value);
}
// Test proper JSON deserialization from a StringPiece substring.
TEST(JSONValueSerializerTest, ReadProperJSONFromStringPiece) {
// Create a StringPiece for the substring of kProperJSONPadded that matches
// kProperJSON.
base::StringPiece proper_json(kProperJSONPadded);
proper_json = proper_json.substr(5, proper_json.length() - 10);
JSONStringValueSerializer str_deserializer(proper_json); JSONStringValueSerializer str_deserializer(proper_json);
int error_code = 0; int error_code = 0;
...@@ -92,8 +143,7 @@ TEST(JSONValueSerializerTest, ReadProperJSONFromString) { ...@@ -92,8 +143,7 @@ TEST(JSONValueSerializerTest, ReadProperJSONFromString) {
// the proper flag for that is set. // the proper flag for that is set.
TEST(JSONValueSerializerTest, ReadJSONWithTrailingCommasFromString) { TEST(JSONValueSerializerTest, ReadJSONWithTrailingCommasFromString) {
// Try to deserialize it through the serializer. // Try to deserialize it through the serializer.
std::string proper_json(kProperJSONWithCommas); JSONStringValueSerializer str_deserializer(kProperJSONWithCommas);
JSONStringValueSerializer str_deserializer(proper_json);
int error_code = 0; int error_code = 0;
std::string error_message; std::string error_message;
...@@ -165,9 +215,9 @@ TEST(JSONValueSerializerTest, ReadJSONWithCommasFromFile) { ...@@ -165,9 +215,9 @@ TEST(JSONValueSerializerTest, ReadJSONWithCommasFromFile) {
} }
TEST(JSONValueSerializerTest, Roundtrip) { TEST(JSONValueSerializerTest, Roundtrip) {
const std::string original_serialization = static const char kOriginalSerialization[] =
"{\"bool\":true,\"double\":3.14,\"int\":42,\"list\":[1,2],\"null\":null}"; "{\"bool\":true,\"double\":3.14,\"int\":42,\"list\":[1,2],\"null\":null}";
JSONStringValueSerializer serializer(original_serialization); JSONStringValueSerializer serializer(kOriginalSerialization);
scoped_ptr<Value> root(serializer.Deserialize(NULL, NULL)); scoped_ptr<Value> root(serializer.Deserialize(NULL, NULL));
ASSERT_TRUE(root.get()); ASSERT_TRUE(root.get());
ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
...@@ -198,7 +248,7 @@ TEST(JSONValueSerializerTest, Roundtrip) { ...@@ -198,7 +248,7 @@ TEST(JSONValueSerializerTest, Roundtrip) {
std::string test_serialization; std::string test_serialization;
JSONStringValueSerializer mutable_serializer(&test_serialization); JSONStringValueSerializer mutable_serializer(&test_serialization);
ASSERT_TRUE(mutable_serializer.Serialize(*root_dict)); ASSERT_TRUE(mutable_serializer.Serialize(*root_dict));
ASSERT_EQ(original_serialization, test_serialization); ASSERT_EQ(kOriginalSerialization, test_serialization);
mutable_serializer.set_pretty_print(true); mutable_serializer.set_pretty_print(true);
ASSERT_TRUE(mutable_serializer.Serialize(*root_dict)); ASSERT_TRUE(mutable_serializer.Serialize(*root_dict));
...@@ -273,15 +323,15 @@ TEST(JSONValueSerializerTest, UnicodeStrings) { ...@@ -273,15 +323,15 @@ TEST(JSONValueSerializerTest, UnicodeStrings) {
string16 test(WideToUTF16(L"\x7F51\x9875")); string16 test(WideToUTF16(L"\x7F51\x9875"));
root.SetString("web", test); root.SetString("web", test);
std::string expected = "{\"web\":\"\xE7\xBD\x91\xE9\xA1\xB5\"}"; static const char kExpected[] = "{\"web\":\"\xE7\xBD\x91\xE9\xA1\xB5\"}";
std::string actual; std::string actual;
JSONStringValueSerializer serializer(&actual); JSONStringValueSerializer serializer(&actual);
ASSERT_TRUE(serializer.Serialize(root)); ASSERT_TRUE(serializer.Serialize(root));
ASSERT_EQ(expected, actual); ASSERT_EQ(kExpected, actual);
// escaped ascii text -> json // escaped ascii text -> json
JSONStringValueSerializer deserializer(expected); JSONStringValueSerializer deserializer(kExpected);
scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL)); scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL));
ASSERT_TRUE(deserial_root.get()); ASSERT_TRUE(deserial_root.get());
DictionaryValue* dict_root = DictionaryValue* dict_root =
...@@ -297,15 +347,15 @@ TEST(JSONValueSerializerTest, HexStrings) { ...@@ -297,15 +347,15 @@ TEST(JSONValueSerializerTest, HexStrings) {
string16 test(WideToUTF16(L"\x01\x02")); string16 test(WideToUTF16(L"\x01\x02"));
root.SetString("test", test); root.SetString("test", test);
std::string expected = "{\"test\":\"\\u0001\\u0002\"}"; static const char kExpected[] = "{\"test\":\"\\u0001\\u0002\"}";
std::string actual; std::string actual;
JSONStringValueSerializer serializer(&actual); JSONStringValueSerializer serializer(&actual);
ASSERT_TRUE(serializer.Serialize(root)); ASSERT_TRUE(serializer.Serialize(root));
ASSERT_EQ(expected, actual); ASSERT_EQ(kExpected, actual);
// escaped ascii text -> json // escaped ascii text -> json
JSONStringValueSerializer deserializer(expected); JSONStringValueSerializer deserializer(kExpected);
scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL)); scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL));
ASSERT_TRUE(deserial_root.get()); ASSERT_TRUE(deserial_root.get());
DictionaryValue* dict_root = DictionaryValue* dict_root =
...@@ -315,8 +365,8 @@ TEST(JSONValueSerializerTest, HexStrings) { ...@@ -315,8 +365,8 @@ TEST(JSONValueSerializerTest, HexStrings) {
ASSERT_EQ(test, test_value); ASSERT_EQ(test, test_value);
// Test converting escaped regular chars // Test converting escaped regular chars
std::string escaped_chars = "{\"test\":\"\\u0067\\u006f\"}"; static const char kEscapedChars[] = "{\"test\":\"\\u0067\\u006f\"}";
JSONStringValueSerializer deserializer2(escaped_chars); JSONStringValueSerializer deserializer2(kEscapedChars);
deserial_root.reset(deserializer2.Deserialize(NULL, NULL)); deserial_root.reset(deserializer2.Deserialize(NULL, NULL));
ASSERT_TRUE(deserial_root.get()); ASSERT_TRUE(deserial_root.get());
dict_root = static_cast<DictionaryValue*>(deserial_root.get()); dict_root = static_cast<DictionaryValue*>(deserial_root.get());
...@@ -327,12 +377,12 @@ TEST(JSONValueSerializerTest, HexStrings) { ...@@ -327,12 +377,12 @@ TEST(JSONValueSerializerTest, HexStrings) {
TEST(JSONValueSerializerTest, AllowTrailingComma) { TEST(JSONValueSerializerTest, AllowTrailingComma) {
scoped_ptr<Value> root; scoped_ptr<Value> root;
scoped_ptr<Value> root_expected; scoped_ptr<Value> root_expected;
std::string test_with_commas("{\"key\": [true,],}"); static const char kTestWithCommas[] = "{\"key\": [true,],}";
std::string test_no_commas("{\"key\": [true]}"); static const char kTestNoCommas[] = "{\"key\": [true]}";
JSONStringValueSerializer serializer(test_with_commas); JSONStringValueSerializer serializer(kTestWithCommas);
serializer.set_allow_trailing_comma(true); serializer.set_allow_trailing_comma(true);
JSONStringValueSerializer serializer_expected(test_no_commas); JSONStringValueSerializer serializer_expected(kTestNoCommas);
root.reset(serializer.Deserialize(NULL, NULL)); root.reset(serializer.Deserialize(NULL, NULL));
ASSERT_TRUE(root.get()); ASSERT_TRUE(root.get());
root_expected.reset(serializer_expected.Deserialize(NULL, NULL)); root_expected.reset(serializer_expected.Deserialize(NULL, NULL));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment