Add JSON parsing support (issue #1188).

This commit is contained in:
Yu-Teh Shen 2015-04-17 22:19:30 +08:00 committed by Marshall Greenblatt
parent 373180fef2
commit d02f03a71a
12 changed files with 577 additions and 1 deletions

View File

@ -1072,6 +1072,7 @@
'libcef/common/drag_data_impl.h',
'libcef/common/http_header_utils.cc',
'libcef/common/http_header_utils.h',
'libcef/common/json_impl.cc',
'libcef/common/main_delegate.cc',
'libcef/common/main_delegate.h',
'libcef/common/net_resource_provider.cc',

View File

@ -122,6 +122,26 @@ CEF_EXPORT cef_string_userfree_t cef_uridecode(const cef_string_t* text,
CEF_EXPORT int cef_parse_csscolor(const cef_string_t* string, int strict,
cef_color_t* color);
// Parses the specified |json_string| and returns a dictionary or list
// representation. If JSON parsing fails this function returns NULL.
CEF_EXPORT struct _cef_value_t* cef_parse_json(const cef_string_t* json_string,
cef_json_parser_options_t options);
// Parses the specified |json_string| and returns a dictionary or list
// representation. If JSON parsing fails this function returns NULL and
// populates |error_code_out| and |error_msg_out| with an error code and a
// formatted error message respectively.
CEF_EXPORT struct _cef_value_t* cef_parse_jsonand_return_error(
const cef_string_t* json_string, cef_json_parser_options_t options,
cef_json_parser_error_t* error_code_out, cef_string_t* error_msg_out);
// Generates a JSON string from the specified root |node| which should be a
// dictionary or list value. Returns an NULL string on failure. This function
// requires exclusive access to |node| including any underlying data.
// The resulting string must be freed by calling cef_string_userfree_free().
CEF_EXPORT cef_string_userfree_t cef_write_json(struct _cef_value_t* node,
cef_json_writer_options_t options);
#ifdef __cplusplus
}
#endif

View File

@ -123,4 +123,28 @@ bool CefParseCSSColor(const CefString& string,
bool strict,
cef_color_t& color);
// Parses the specified |json_string| and returns a dictionary or list
// representation. If JSON parsing fails this method returns NULL.
/*--cef()--*/
CefRefPtr<CefValue> CefParseJSON(const CefString& json_string,
cef_json_parser_options_t options);
// Parses the specified |json_string| and returns a dictionary or list
// representation. If JSON parsing fails this method returns NULL and populates
// |error_code_out| and |error_msg_out| with an error code and a formatted error
// message respectively.
/*--cef()--*/
CefRefPtr<CefValue> CefParseJSONAndReturnError(
const CefString& json_string,
cef_json_parser_options_t options,
cef_json_parser_error_t& error_code_out,
CefString& error_msg_out);
// Generates a JSON string from the specified root |node| which should be a
// dictionary or list value. Returns an empty string on failure. This method
// requires exclusive access to |node| including any underlying data.
/*--cef()--*/
CefString CefWriteJSON(CefRefPtr<CefValue> node,
cef_json_writer_options_t options);
#endif // CEF_INCLUDE_CEF_PARSER_H_

View File

@ -2130,6 +2130,70 @@ typedef enum {
UU_REPLACE_PLUS_WITH_SPACE = 16,
} cef_uri_unescape_rule_t;
///
// Options that can be passed to CefParseJSON.
///
typedef enum {
///
// Parses the input strictly according to RFC 4627. See comments in Chromium's
// base/json/json_reader.h file for known limitations/deviations from the RFC.
///
JSON_PARSER_RFC = 0,
///
// Allows commas to exist after the last element in structures.
///
JSON_PARSER_ALLOW_TRAILING_COMMAS = 1 << 0,
} cef_json_parser_options_t;
///
// Error codes that can be returned from CefParseJSONAndReturnError.
///
typedef enum {
JSON_NO_ERROR = 0,
JSON_INVALID_ESCAPE,
JSON_SYNTAX_ERROR,
JSON_UNEXPECTED_TOKEN,
JSON_TRAILING_COMMA,
JSON_TOO_MUCH_NESTING,
JSON_UNEXPECTED_DATA_AFTER_ROOT,
JSON_UNSUPPORTED_ENCODING,
JSON_UNQUOTED_DICTIONARY_KEY,
JSON_PARSE_ERROR_COUNT
} cef_json_parser_error_t;
///
// Options that can be passed to CefWriteJSON.
///
typedef enum {
///
// Default behavior.
///
JSON_WRITER_DEFAULT = 0,
///
// This option instructs the writer that if a Binary value is encountered,
// the value (and key if within a dictionary) will be omitted from the
// output, and success will be returned. Otherwise, if a binary value is
// encountered, failure will be returned.
///
JSON_WRITER_OMIT_BINARY_VALUES = 1 << 0,
///
// This option instructs the writer to write doubles that have no fractional
// part as a normal integer (i.e., without using exponential notation
// or appending a '.0') as long as the value is within the range of a
// 64-bit int.
///
JSON_WRITER_OMIT_DOUBLE_TYPE_PRESERVATION = 1 << 1,
///
// Return a slightly nicer formatted json string (pads with whitespace to
// help with readability).
///
JSON_WRITER_PRETTY_PRINT = 1 << 2,
} cef_json_writer_options_t;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,78 @@
// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.
#include "include/cef_parser.h"
#include "libcef/common/values_impl.h"
#include "base/values.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
namespace {
int GetJSONReaderOptions(cef_json_parser_options_t options) {
int op = base::JSON_PARSE_RFC;
if (options & JSON_PARSER_ALLOW_TRAILING_COMMAS)
op |= base::JSON_ALLOW_TRAILING_COMMAS;
return op;
}
int GetJSONWriterOptions(cef_json_writer_options_t options) {
int op = 0;
if (op & JSON_WRITER_OMIT_BINARY_VALUES)
op |= base::JSONWriter::OPTIONS_OMIT_BINARY_VALUES;
if (op & JSON_WRITER_OMIT_DOUBLE_TYPE_PRESERVATION)
op |= base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION;
if (op & JSON_WRITER_PRETTY_PRINT)
op |= base::JSONWriter::OPTIONS_PRETTY_PRINT;
return op;
}
} // namespace
CefRefPtr<CefValue> CefParseJSON(const CefString& json_string,
cef_json_parser_options_t options) {
const std::string& json = json_string.ToString();
base::Value* parse_result =
base::JSONReader::Read(json, GetJSONReaderOptions(options));
if (parse_result)
return new CefValueImpl(parse_result);
return NULL;
}
CefRefPtr<CefValue> CefParseJSONAndReturnError(
const CefString& json_string,
cef_json_parser_options_t options,
cef_json_parser_error_t& error_code_out,
CefString& error_msg_out) {
const std::string& json = json_string.ToString();
int error_code;
std::string error_msg;
base::Value* parse_result = base::JSONReader::ReadAndReturnError(
json, GetJSONReaderOptions(options), &error_code, &error_msg);
if (parse_result)
return new CefValueImpl(parse_result);
error_code_out = static_cast<cef_json_parser_error_t>(error_code);
error_msg_out = error_msg;
return NULL;
}
CefString CefWriteJSON(CefRefPtr<CefValue> node,
cef_json_writer_options_t options) {
if (!node.get() || !node->IsValid())
return CefString();
CefValueImpl* impl = static_cast<CefValueImpl*>(node.get());
CefValueImpl::ScopedLockedValue scoped_value(impl);
std::string json_string;
if (base::JSONWriter::WriteWithOptions(scoped_value.value(),
GetJSONWriterOptions(options),
&json_string)) {
return json_string;
}
return CefString();
}

View File

@ -71,6 +71,9 @@ class CefValueController
// Returns true if the controller is locked on the current thread.
virtual bool locked() =0;
// Assert that the lock has been acquired.
virtual void AssertLockAcquired() =0;
// Verify that the current thread is correct for accessing the controller.
inline bool VerifyThread() {
if (!thread_safe() && !on_correct_thread()) {
@ -149,6 +152,9 @@ class CefValueControllerThreadSafe : public CefValueController {
bool locked() override {
return (locked_thread_id_ == base::PlatformThread::CurrentId());
}
void AssertLockAcquired() override {
lock_.AssertAcquired();
}
private:
base::Lock lock_;
@ -171,6 +177,9 @@ class CefValueControllerNonThreadSafe : public CefValueController {
void lock() override {}
void unlock() override {}
bool locked() override { return on_correct_thread(); }
void AssertLockAcquired() override {
DCHECK(locked());
}
private:
base::PlatformThreadId thread_id_;

View File

@ -363,6 +363,55 @@ void CefValueImpl::SetValueInternal(base::Value* value) {
}
}
CefValueController* CefValueImpl::GetValueController() const {
lock_.AssertAcquired();
if (binary_value_) {
return static_cast<CefBinaryValueImpl*>(binary_value_.get())->controller();
} else if (dictionary_value_) {
return static_cast<CefDictionaryValueImpl*>(dictionary_value_.get())->
controller();
} else if (list_value_) {
return static_cast<CefListValueImpl*>(list_value_.get())->controller();
}
return NULL;
}
void CefValueImpl::AcquireLock() {
lock_.Acquire();
CefValueController* controller = GetValueController();
if (controller)
controller->lock();
}
void CefValueImpl::ReleaseLock() {
CefValueController* controller = GetValueController();
if (controller) {
controller->AssertLockAcquired();
controller->unlock();
}
lock_.Release();
}
base::Value* CefValueImpl::GetValueUnsafe() const {
lock_.AssertAcquired();
if (binary_value_) {
return static_cast<CefBinaryValueImpl*>(binary_value_.get())->
GetValueUnsafe();
} else if (dictionary_value_) {
return static_cast<CefDictionaryValueImpl*>(dictionary_value_.get())->
GetValueUnsafe();
} else if (list_value_) {
return static_cast<CefListValueImpl*>(list_value_.get())->GetValueUnsafe();
}
return value_.get();
}
// CefBinaryValueImpl implementation.
@ -441,6 +490,13 @@ bool CefBinaryValueImpl::IsEqualValue(const base::BinaryValue* that) {
return const_value().Equals(that);
}
base::BinaryValue* CefBinaryValueImpl::GetValueUnsafe() {
if (!VerifyAttached())
return NULL;
controller()->AssertLockAcquired();
return const_cast<base::BinaryValue*>(&const_value());
}
bool CefBinaryValueImpl::IsValid() {
return !detached();
}
@ -572,6 +628,13 @@ bool CefDictionaryValueImpl::IsEqualValue(const base::DictionaryValue* that) {
return const_value().Equals(that);
}
base::DictionaryValue* CefDictionaryValueImpl::GetValueUnsafe() {
if (!VerifyAttached())
return NULL;
controller()->AssertLockAcquired();
return const_cast<base::DictionaryValue*>(&const_value());
}
bool CefDictionaryValueImpl::IsValid() {
return !detached();
}
@ -979,6 +1042,13 @@ bool CefListValueImpl::IsEqualValue(const base::ListValue* that) {
return const_value().Equals(that);
}
base::ListValue* CefListValueImpl::GetValueUnsafe() {
if (!VerifyAttached())
return NULL;
controller()->AssertLockAcquired();
return const_cast<base::ListValue*>(&const_value());
}
bool CefListValueImpl::IsValid() {
return !detached();
}

View File

@ -73,9 +73,41 @@ class CefValueImpl : public CefValue {
bool SetDictionary(CefRefPtr<CefDictionaryValue> value) override;
bool SetList(CefRefPtr<CefListValue> value) override;
// Ensures exclusive access to the underlying data for the life of this scoped
// object.
class ScopedLockedValue {
public:
explicit ScopedLockedValue(CefRefPtr<CefValueImpl> impl)
: impl_(impl) {
impl_->AcquireLock();
}
~ScopedLockedValue() {
impl_->ReleaseLock();
}
base::Value* value() const {
return impl_->GetValueUnsafe();
}
private:
CefRefPtr<CefValueImpl> impl_;
DISALLOW_COPY_AND_ASSIGN(ScopedLockedValue);
};
private:
void SetValueInternal(base::Value* value);
// Returns the controller for the current value, if any.
CefValueController* GetValueController() const;
// Explicitly lock/unlock this object and the underlying data.
void AcquireLock();
void ReleaseLock();
// Returns a reference to the underlying data. Access must be protected by
// calling AcquireLock/ReleaseLock.
base::Value* GetValueUnsafe() const;
// Access to all members must be protected by |lock_|.
base::Lock lock_;
@ -127,6 +159,10 @@ class CefBinaryValueImpl
bool IsSameValue(const base::BinaryValue* that);
bool IsEqualValue(const base::BinaryValue* that);
// Returns the underlying value. Access must be protected by calling
// lock/unlock on the controller.
base::BinaryValue* GetValueUnsafe();
// CefBinaryValue methods.
bool IsValid() override;
bool IsOwned() override;
@ -181,6 +217,10 @@ class CefDictionaryValueImpl
bool IsSameValue(const base::DictionaryValue* that);
bool IsEqualValue(const base::DictionaryValue* that);
// Returns the underlying value. Access must be protected by calling
// lock/unlock on the controller.
base::DictionaryValue* GetValueUnsafe();
// CefDictionaryValue methods.
bool IsValid() override;
bool IsOwned() override;
@ -264,7 +304,11 @@ class CefListValueImpl
bool IsSameValue(const base::ListValue* that);
bool IsEqualValue(const base::ListValue* that);
/// CefListValue methods.
// Returns the underlying value. Access must be protected by calling
// lock/unlock on the controller.
base::ListValue* GetValueUnsafe();
// CefListValue methods.
bool IsValid() override;
bool IsOwned() override;
bool IsReadOnly() override;

View File

@ -594,6 +594,81 @@ CEF_EXPORT int cef_parse_csscolor(const cef_string_t* string, int strict,
return _retval;
}
CEF_EXPORT struct _cef_value_t* cef_parse_json(const cef_string_t* json_string,
cef_json_parser_options_t options) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: json_string; type: string_byref_const
DCHECK(json_string);
if (!json_string)
return NULL;
// Execute
CefRefPtr<CefValue> _retval = CefParseJSON(
CefString(json_string),
options);
// Return type: refptr_same
return CefValueCppToC::Wrap(_retval);
}
CEF_EXPORT struct _cef_value_t* cef_parse_jsonand_return_error(
const cef_string_t* json_string, cef_json_parser_options_t options,
cef_json_parser_error_t* error_code_out, cef_string_t* error_msg_out) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: json_string; type: string_byref_const
DCHECK(json_string);
if (!json_string)
return NULL;
// Verify param: error_code_out; type: simple_byref
DCHECK(error_code_out);
if (!error_code_out)
return NULL;
// Verify param: error_msg_out; type: string_byref
DCHECK(error_msg_out);
if (!error_msg_out)
return NULL;
// Translate param: error_code_out; type: simple_byref
cef_json_parser_error_t error_code_outVal =
error_code_out?*error_code_out:JSON_NO_ERROR;
// Translate param: error_msg_out; type: string_byref
CefString error_msg_outStr(error_msg_out);
// Execute
CefRefPtr<CefValue> _retval = CefParseJSONAndReturnError(
CefString(json_string),
options,
error_code_outVal,
error_msg_outStr);
// Restore param: error_code_out; type: simple_byref
if (error_code_out)
*error_code_out = error_code_outVal;
// Return type: refptr_same
return CefValueCppToC::Wrap(_retval);
}
CEF_EXPORT cef_string_userfree_t cef_write_json(struct _cef_value_t* node,
cef_json_writer_options_t options) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: node; type: refptr_same
DCHECK(node);
if (!node)
return NULL;
// Execute
CefString _retval = CefWriteJSON(
CefValueCppToC::Unwrap(node),
options);
// Return type: string
return _retval.DetachToUserFree();
}
CEF_EXPORT int cef_get_path(cef_path_key_t key, cef_string_t* path) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING

View File

@ -549,6 +549,65 @@ CEF_GLOBAL bool CefParseCSSColor(const CefString& string, bool strict,
return _retval?true:false;
}
CEF_GLOBAL CefRefPtr<CefValue> CefParseJSON(const CefString& json_string,
cef_json_parser_options_t options) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: json_string; type: string_byref_const
DCHECK(!json_string.empty());
if (json_string.empty())
return NULL;
// Execute
cef_value_t* _retval = cef_parse_json(
json_string.GetStruct(),
options);
// Return type: refptr_same
return CefValueCToCpp::Wrap(_retval);
}
CEF_GLOBAL CefRefPtr<CefValue> CefParseJSONAndReturnError(
const CefString& json_string, cef_json_parser_options_t options,
cef_json_parser_error_t& error_code_out, CefString& error_msg_out) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: json_string; type: string_byref_const
DCHECK(!json_string.empty());
if (json_string.empty())
return NULL;
// Execute
cef_value_t* _retval = cef_parse_jsonand_return_error(
json_string.GetStruct(),
options,
&error_code_out,
error_msg_out.GetWritableStruct());
// Return type: refptr_same
return CefValueCToCpp::Wrap(_retval);
}
CEF_GLOBAL CefString CefWriteJSON(CefRefPtr<CefValue> node,
cef_json_writer_options_t options) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: node; type: refptr_same
DCHECK(node.get());
if (!node.get())
return CefString();
// Execute
cef_string_userfree_t _retval = cef_write_json(
CefValueCToCpp::Unwrap(node),
options);
// Return type: string
CefString _retvalStr;
_retvalStr.AttachToUserFree(_retval);
return _retvalStr;
}
CEF_GLOBAL bool CefGetPath(PathKey key, CefString& path) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING

View File

@ -309,3 +309,134 @@ TEST(ParserTest, ParseCSSColor) {
EXPECT_FALSE(CefParseCSSColor(value, false, color));
EXPECT_EQ(0U, color);
}
TEST(ParserTest, ParseJSONInvalid) {
const char data[] = "This is my test data";
CefRefPtr<CefValue> value = CefParseJSON(data, JSON_PARSER_RFC);
EXPECT_FALSE(value.get());
}
TEST(ParserTest, ParseJSONNull) {
const char data[] = "{\"key1\":null}";
CefRefPtr<CefValue> value = CefParseJSON(data, JSON_PARSER_RFC);
EXPECT_TRUE(value.get());
EXPECT_TRUE(value->IsValid());
EXPECT_TRUE(value->GetType() == VTYPE_DICTIONARY);
EXPECT_FALSE(value->IsOwned());
CefRefPtr<CefDictionaryValue> dict = value->GetDictionary();
CefDictionaryValue::KeyList key_list;
EXPECT_TRUE(dict->GetKeys(key_list));
EXPECT_EQ((size_t)1, key_list.size());
EXPECT_EQ("key1", key_list[0].ToString());
EXPECT_EQ(VTYPE_NULL, dict->GetType("key1"));
// generate string from parsed result
CefString result = CefWriteJSON(value, JSON_WRITER_DEFAULT);
CefString expected_result = data;
EXPECT_EQ(expected_result, result);
}
TEST(ParserTest, WriteJSONBinary) {
const char data[] = "\00\01\02";
CefRefPtr<CefDictionaryValue> dict = CefDictionaryValue::Create();
CefRefPtr<CefBinaryValue> binary = CefBinaryValue::Create(data, sizeof(data));
dict->SetBinary("key1", binary);
CefRefPtr<CefValue> node = CefValue::Create();
node->SetDictionary(dict);
CefString result = CefWriteJSON(node, JSON_WRITER_DEFAULT);
CefString expect_result = "";
// binary data will be omitted.
EXPECT_EQ(expect_result, result);
}
TEST(ParserTest, ParseJSONDictionary) {
const char data[] = "{\"key1\":\"value1\",\"key2\":123,\"key3\":[1,2,3]}";
CefRefPtr<CefValue> value = CefParseJSON(data, JSON_PARSER_RFC);
EXPECT_TRUE(value.get());
EXPECT_TRUE(value->IsValid());
EXPECT_FALSE(value->IsOwned());
EXPECT_TRUE(value->GetType() == VTYPE_DICTIONARY);
CefRefPtr<CefDictionaryValue> dict = value->GetDictionary();
CefDictionaryValue::KeyList key_list;
EXPECT_TRUE(dict->GetKeys(key_list));
EXPECT_EQ((size_t)3, key_list.size());
EXPECT_EQ("key1", key_list[0].ToString());
EXPECT_EQ("key2", key_list[1].ToString());
EXPECT_EQ("key3", key_list[2].ToString());
EXPECT_EQ(VTYPE_STRING, dict->GetType("key1"));
EXPECT_EQ(dict->GetString("key1"), "value1");
EXPECT_EQ(VTYPE_INT, dict->GetType("key2"));
EXPECT_EQ(123, dict->GetInt("key2"));
EXPECT_EQ(VTYPE_LIST, dict->GetType("key3"));
CefRefPtr<CefListValue> key3 = dict->GetList("key3");
EXPECT_TRUE(NULL != key3);
EXPECT_TRUE(key3->IsValid());
EXPECT_EQ((size_t)3, key3->GetSize());
EXPECT_EQ(1, key3->GetInt(0));
EXPECT_EQ(2, key3->GetInt(1));
EXPECT_EQ(3, key3->GetInt(2));
// generate string from parsed result
CefString result = CefWriteJSON(value, JSON_WRITER_DEFAULT);
CefString expected_result = data;
EXPECT_EQ(expected_result, result);
}
TEST(ParserTest, ParseJSONList) {
const char data[] = "[\"value1\", 123, {\"key3\": [1, 2, 3]}]";
CefRefPtr<CefValue> value = CefParseJSON(data, JSON_PARSER_RFC);
EXPECT_TRUE(value.get());
EXPECT_TRUE(value->IsValid());
EXPECT_TRUE(value->GetType() == VTYPE_LIST);
EXPECT_FALSE(value->IsOwned());
CefRefPtr<CefListValue> list = value->GetList();
EXPECT_TRUE(NULL != list);
EXPECT_TRUE(list->IsValid());
EXPECT_EQ((size_t)3, list->GetSize());
EXPECT_EQ(VTYPE_STRING, list->GetType(0));
EXPECT_EQ(list->GetString(0), "value1");
EXPECT_EQ(VTYPE_INT, list->GetType(1));
EXPECT_EQ(123, list->GetInt(1));
EXPECT_EQ(VTYPE_DICTIONARY, list->GetType(2));
CefRefPtr<CefDictionaryValue> dict = list->GetDictionary(2);
CefDictionaryValue::KeyList key_list2;
EXPECT_TRUE(dict->GetKeys(key_list2));
EXPECT_EQ((size_t)1, key_list2.size());
CefRefPtr<CefListValue> list2 = dict->GetList("key3");
EXPECT_EQ((size_t)3, list2->GetSize());
EXPECT_EQ(1, list2->GetInt(0));
EXPECT_EQ(2, list2->GetInt(1));
EXPECT_EQ(3, list2->GetInt(2));
// generate string from parsed result
CefString result = CefWriteJSON(value, JSON_WRITER_DEFAULT);
CefString expected_result = "[\"value1\",123,{\"key3\":[1,2,3]}]";
EXPECT_EQ(expected_result.ToString(), result.ToString());
}
TEST(ParserTest, ParseJSONAndReturnErrorInvalid) {
const char data[] = "This is my test data";
cef_json_parser_error_t error_code;
CefString error_msg;
CefRefPtr<CefValue> value = CefParseJSONAndReturnError(data,
JSON_PARSER_RFC, error_code, error_msg);
CefString expect_error_msg = "Line: 1, column: 1, Unexpected token.";
EXPECT_FALSE(value.get());
EXPECT_EQ(JSON_UNEXPECTED_TOKEN, error_code);
EXPECT_EQ(expect_error_msg, error_msg);
}
TEST(ParserTest, ParseJSONAndReturnErrorTrailingComma) {
const char data[] = "{\"key1\":123,}";
cef_json_parser_error_t error_code;
CefString error_msg;
CefRefPtr<CefValue> value = CefParseJSONAndReturnError(data,
JSON_PARSER_RFC, error_code, error_msg);
CefString expect_error_msg =
"Line: 1, column: 13, Trailing comma not allowed.";
EXPECT_FALSE(value.get());
EXPECT_EQ(JSON_TRAILING_COMMA, error_code);
EXPECT_EQ(expect_error_msg, error_msg);
}

View File

@ -396,6 +396,7 @@ _simpletypes = {
'char': ['char', '0'],
'char* const': ['char* const', 'NULL'],
'cef_color_t': ['cef_color_t', '0'],
'cef_json_parser_error_t': ['cef_json_parser_error_t', 'JSON_NO_ERROR'],
'CefCursorHandle' : ['cef_cursor_handle_t', 'kNullCursorHandle'],
'CefEventHandle' : ['cef_event_handle_t', 'kNullEventHandle'],
'CefWindowHandle' : ['cef_window_handle_t', 'kNullWindowHandle'],