[DevTools] Roll inspector_protocol (v8) (file split)
This decomposes the crdtp library into multiple files. Since it wasn't previously rolled it's a bit more than just that. Upstream review: https://chromium-review.googlesource.com/c/deps/inspector_protocol/+/1907115 New Revision: d020a9e614d4a5116a7c71f288c0340e282e1a6e Change-Id: I5c588469654bec3e933804ac706fa967c6fe57bc Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1907973 Auto-Submit: Johannes Henkel <johannes@chromium.org> Reviewed-by: Yang Guo <yangguo@chromium.org> Commit-Queue: Yang Guo <yangguo@chromium.org> Cr-Commit-Position: refs/heads/master@{#64902}
This commit is contained in:
parent
36e812bee7
commit
b67cafe716
@ -65,9 +65,7 @@ config("inspector_config") {
|
|||||||
visibility = [ ":*" ] # Only targets in this file can depend on this.
|
visibility = [ ":*" ] # Only targets in this file can depend on this.
|
||||||
|
|
||||||
configs = [ "../../:internal_config" ]
|
configs = [ "../../:internal_config" ]
|
||||||
include_dirs = [
|
include_dirs = [ "../../include" ]
|
||||||
"../../include",
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
v8_header_set("inspector_test_headers") {
|
v8_header_set("inspector_test_headers") {
|
||||||
@ -97,8 +95,7 @@ v8_source_set("inspector") {
|
|||||||
deps = [
|
deps = [
|
||||||
":inspector_string_conversions",
|
":inspector_string_conversions",
|
||||||
"../..:v8_version",
|
"../..:v8_version",
|
||||||
"../../third_party/inspector_protocol:encoding",
|
"../../third_party/inspector_protocol:crdtp",
|
||||||
"../../third_party/inspector_protocol:bindings",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
public_deps = [
|
public_deps = [
|
||||||
|
@ -18,8 +18,6 @@ include_rules = [
|
|||||||
"+src/debug/debug-interface.h",
|
"+src/debug/debug-interface.h",
|
||||||
"+src/debug/interface-types.h",
|
"+src/debug/interface-types.h",
|
||||||
"+src/utils/vector.h",
|
"+src/utils/vector.h",
|
||||||
"+third_party/inspector_protocol/encoding/encoding.h",
|
"+third_party/inspector_protocol/crdtp",
|
||||||
"+third_party/inspector_protocol/encoding/encoding.cc",
|
"+../../third_party/inspector_protocol/crdtp",
|
||||||
"+../../third_party/inspector_protocol/encoding/encoding.h",
|
|
||||||
"+../../third_party/inspector_protocol/encoding/encoding.cc",
|
|
||||||
]
|
]
|
||||||
|
@ -46,11 +46,7 @@
|
|||||||
"string_header": "src/inspector/string-util.h"
|
"string_header": "src/inspector/string-util.h"
|
||||||
},
|
},
|
||||||
|
|
||||||
"encoding_lib": {
|
"crdtp": {
|
||||||
"namespace": "v8_inspector_protocol_encoding"
|
"namespace": "v8_crdtp"
|
||||||
},
|
|
||||||
|
|
||||||
"bindings_lib": {
|
|
||||||
"namespace": "v8_inspector_protocol_bindings"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,21 +5,24 @@
|
|||||||
#include "src/inspector/v8-inspector-protocol-encoding.h"
|
#include "src/inspector/v8-inspector-protocol-encoding.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "../../third_party/inspector_protocol/encoding/encoding.h"
|
#include "../../third_party/inspector_protocol/crdtp/json.h"
|
||||||
#include "src/numbers/conversions.h"
|
#include "src/numbers/conversions.h"
|
||||||
#include "src/utils/vector.h"
|
#include "src/utils/vector.h"
|
||||||
|
|
||||||
namespace v8_inspector {
|
namespace v8_inspector {
|
||||||
namespace {
|
namespace {
|
||||||
using IPEStatus = ::v8_inspector_protocol_encoding::Status;
|
using v8_crdtp::span;
|
||||||
using ::v8_inspector_protocol_encoding::span;
|
using v8_crdtp::Status;
|
||||||
|
|
||||||
class Platform : public ::v8_inspector_protocol_encoding::json::Platform {
|
class Platform : public v8_crdtp::json::Platform {
|
||||||
public:
|
// Parses |str| into |result|. Returns false iff there are
|
||||||
|
// leftover characters or parsing errors.
|
||||||
bool StrToD(const char* str, double* result) const override {
|
bool StrToD(const char* str, double* result) const override {
|
||||||
*result = v8::internal::StringToDouble(str, v8::internal::NO_FLAGS);
|
*result = v8::internal::StringToDouble(str, v8::internal::NO_FLAGS);
|
||||||
return !std::isnan(*result);
|
return !std::isnan(*result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prints |value| in a format suitable for JSON.
|
||||||
std::unique_ptr<char[]> DToStr(double value) const override {
|
std::unique_ptr<char[]> DToStr(double value) const override {
|
||||||
v8::internal::ScopedVector<char> buffer(
|
v8::internal::ScopedVector<char> buffer(
|
||||||
v8::internal::kDoubleToCStringMinBufferSize);
|
v8::internal::kDoubleToCStringMinBufferSize);
|
||||||
@ -33,19 +36,18 @@ class Platform : public ::v8_inspector_protocol_encoding::json::Platform {
|
|||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
IPEStatus ConvertCBORToJSON(span<uint8_t> cbor, std::vector<uint8_t>* json) {
|
Status ConvertCBORToJSON(span<uint8_t> cbor, std::vector<uint8_t>* json) {
|
||||||
Platform platform;
|
Platform platform;
|
||||||
return ConvertCBORToJSON(platform, cbor, json);
|
return v8_crdtp::json::ConvertCBORToJSON(platform, cbor, json);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPEStatus ConvertJSONToCBOR(span<uint8_t> json, std::vector<uint8_t>* cbor) {
|
Status ConvertJSONToCBOR(span<uint8_t> json, std::vector<uint8_t>* cbor) {
|
||||||
Platform platform;
|
Platform platform;
|
||||||
return ConvertJSONToCBOR(platform, json, cbor);
|
return v8_crdtp::json::ConvertJSONToCBOR(platform, json, cbor);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPEStatus ConvertJSONToCBOR(span<uint16_t> json, std::vector<uint8_t>* cbor) {
|
Status ConvertJSONToCBOR(span<uint16_t> json, std::vector<uint8_t>* cbor) {
|
||||||
Platform platform;
|
Platform platform;
|
||||||
return ConvertJSONToCBOR(platform, json, cbor);
|
return v8_crdtp::json::ConvertJSONToCBOR(platform, json, cbor);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace v8_inspector
|
} // namespace v8_inspector
|
||||||
|
@ -5,21 +5,19 @@
|
|||||||
#ifndef V8_INSPECTOR_V8_INSPECTOR_PROTOCOL_ENCODING_H_
|
#ifndef V8_INSPECTOR_V8_INSPECTOR_PROTOCOL_ENCODING_H_
|
||||||
#define V8_INSPECTOR_V8_INSPECTOR_PROTOCOL_ENCODING_H_
|
#define V8_INSPECTOR_V8_INSPECTOR_PROTOCOL_ENCODING_H_
|
||||||
|
|
||||||
#include "../../third_party/inspector_protocol/encoding/encoding.h"
|
#include "../../third_party/inspector_protocol/crdtp/span.h"
|
||||||
|
#include "../../third_party/inspector_protocol/crdtp/status.h"
|
||||||
|
|
||||||
namespace v8_inspector {
|
namespace v8_inspector {
|
||||||
|
|
||||||
::v8_inspector_protocol_encoding::Status ConvertCBORToJSON(
|
v8_crdtp::Status ConvertCBORToJSON(v8_crdtp::span<uint8_t> cbor,
|
||||||
::v8_inspector_protocol_encoding::span<uint8_t> cbor,
|
std::vector<uint8_t>* json);
|
||||||
std::vector<uint8_t>* json);
|
|
||||||
|
|
||||||
::v8_inspector_protocol_encoding::Status ConvertJSONToCBOR(
|
v8_crdtp::Status ConvertJSONToCBOR(v8_crdtp::span<uint8_t> json,
|
||||||
::v8_inspector_protocol_encoding::span<uint8_t> json,
|
std::vector<uint8_t>* cbor);
|
||||||
std::vector<uint8_t>* cbor);
|
|
||||||
|
|
||||||
::v8_inspector_protocol_encoding::Status ConvertJSONToCBOR(
|
v8_crdtp::Status ConvertJSONToCBOR(v8_crdtp::span<uint16_t> json,
|
||||||
::v8_inspector_protocol_encoding::span<uint16_t> json,
|
std::vector<uint8_t>* cbor);
|
||||||
std::vector<uint8_t>* cbor);
|
|
||||||
|
|
||||||
} // namespace v8_inspector
|
} // namespace v8_inspector
|
||||||
|
|
||||||
|
@ -24,9 +24,9 @@
|
|||||||
|
|
||||||
namespace v8_inspector {
|
namespace v8_inspector {
|
||||||
namespace {
|
namespace {
|
||||||
using ::v8_inspector_protocol_encoding::span;
|
using v8_crdtp::span;
|
||||||
using ::v8_inspector_protocol_encoding::SpanFrom;
|
using v8_crdtp::SpanFrom;
|
||||||
using IPEStatus = ::v8_inspector_protocol_encoding::Status;
|
using IPEStatus = v8_crdtp::Status;
|
||||||
|
|
||||||
bool IsCBORMessage(const StringView& msg) {
|
bool IsCBORMessage(const StringView& msg) {
|
||||||
return msg.is8Bit() && msg.length() >= 2 && msg.characters8()[0] == 0xd8 &&
|
return msg.is8Bit() && msg.length() >= 2 && msg.characters8()[0] == 0xd8 &&
|
||||||
@ -332,8 +332,8 @@ void V8InspectorSessionImpl::reportAllContexts(V8RuntimeAgentImpl* agent) {
|
|||||||
|
|
||||||
void V8InspectorSessionImpl::dispatchProtocolMessage(
|
void V8InspectorSessionImpl::dispatchProtocolMessage(
|
||||||
const StringView& message) {
|
const StringView& message) {
|
||||||
using ::v8_inspector_protocol_encoding::span;
|
using v8_crdtp::span;
|
||||||
using ::v8_inspector_protocol_encoding::SpanFrom;
|
using v8_crdtp::SpanFrom;
|
||||||
span<uint8_t> cbor;
|
span<uint8_t> cbor;
|
||||||
std::vector<uint8_t> converted_cbor;
|
std::vector<uint8_t> converted_cbor;
|
||||||
if (IsCBORMessage(message)) {
|
if (IsCBORMessage(message)) {
|
||||||
|
@ -295,8 +295,7 @@ v8_source_set("unittests_sources") {
|
|||||||
"../..:v8_for_testing",
|
"../..:v8_for_testing",
|
||||||
"../..:v8_libbase",
|
"../..:v8_libbase",
|
||||||
"../..:v8_libplatform",
|
"../..:v8_libplatform",
|
||||||
"../../third_party/inspector_protocol:bindings_test",
|
"../../third_party/inspector_protocol:crdtp_test",
|
||||||
"../../third_party/inspector_protocol:encoding_test",
|
|
||||||
"//build/win:default_exe_manifest",
|
"//build/win:default_exe_manifest",
|
||||||
"//testing/gmock",
|
"//testing/gmock",
|
||||||
"//testing/gtest",
|
"//testing/gtest",
|
||||||
|
71
third_party/inspector_protocol/BUILD.gn
vendored
71
third_party/inspector_protocol/BUILD.gn
vendored
@ -2,60 +2,47 @@
|
|||||||
# Use of this source code is governed by a BSD-style license that can be
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
# found in the LICENSE file.
|
# found in the LICENSE file.
|
||||||
|
|
||||||
static_library("encoding") {
|
|
||||||
sources = [
|
|
||||||
"encoding/encoding.cc",
|
|
||||||
"encoding/encoding.h",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
static_library("bindings") {
|
|
||||||
sources = [
|
|
||||||
"bindings/bindings.cc",
|
|
||||||
"bindings/bindings.h",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
# encoding_test is part of the unittests, defined in
|
|
||||||
# test/unittests/BUILD.gn.
|
|
||||||
|
|
||||||
import("../../gni/v8.gni")
|
import("../../gni/v8.gni")
|
||||||
|
|
||||||
v8_source_set("encoding_test") {
|
v8_source_set("crdtp") {
|
||||||
sources = [
|
sources = [
|
||||||
"encoding/encoding_test.cc",
|
"crdtp/cbor.cc",
|
||||||
"encoding/encoding_test_helper.h",
|
"crdtp/cbor.h",
|
||||||
|
"crdtp/export.h",
|
||||||
|
"crdtp/glue.h",
|
||||||
|
"crdtp/json.cc",
|
||||||
|
"crdtp/json.h",
|
||||||
|
"crdtp/json_platform.h",
|
||||||
|
"crdtp/parser_handler.h",
|
||||||
|
"crdtp/span.h",
|
||||||
|
"crdtp/status.cc",
|
||||||
|
"crdtp/status.h",
|
||||||
|
]
|
||||||
|
configs = [ "../../:internal_config" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
# crdtp_test is part of the unittests, defined in
|
||||||
|
# test/unittests/BUILD.gn.
|
||||||
|
v8_source_set("crdtp_test") {
|
||||||
|
testonly = true
|
||||||
|
sources = [
|
||||||
|
"crdtp/cbor_test.cc",
|
||||||
|
"crdtp/glue_test.cc",
|
||||||
|
"crdtp/json_test.cc",
|
||||||
|
"crdtp/span_test.cc",
|
||||||
|
"crdtp/status_test.cc",
|
||||||
|
"crdtp/test_platform.cc",
|
||||||
|
"crdtp/test_platform.h",
|
||||||
]
|
]
|
||||||
configs = [
|
configs = [
|
||||||
"../..:external_config",
|
"../..:external_config",
|
||||||
"../..:internal_config_base",
|
"../..:internal_config_base",
|
||||||
]
|
]
|
||||||
deps = [
|
deps = [
|
||||||
":encoding",
|
":crdtp",
|
||||||
"../..:v8_libbase",
|
"../..:v8_libbase",
|
||||||
"../../src/inspector:inspector_string_conversions",
|
"../../src/inspector:inspector_string_conversions",
|
||||||
"//testing/gmock",
|
"//testing/gmock",
|
||||||
"//testing/gtest",
|
"//testing/gtest",
|
||||||
]
|
]
|
||||||
testonly = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
v8_source_set("bindings_test") {
|
|
||||||
sources = [
|
|
||||||
"bindings/bindings_test.cc",
|
|
||||||
"bindings/bindings_test_helper.h",
|
|
||||||
]
|
|
||||||
configs = [
|
|
||||||
"../..:external_config",
|
|
||||||
"../..:internal_config_base",
|
|
||||||
]
|
|
||||||
deps = [
|
|
||||||
":bindings",
|
|
||||||
"../..:v8_libbase",
|
|
||||||
"../../src/inspector:inspector_string_conversions",
|
|
||||||
"//testing/gmock",
|
|
||||||
"//testing/gtest",
|
|
||||||
]
|
|
||||||
testonly = true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
2
third_party/inspector_protocol/README.v8
vendored
2
third_party/inspector_protocol/README.v8
vendored
@ -2,7 +2,7 @@ Name: inspector protocol
|
|||||||
Short Name: inspector_protocol
|
Short Name: inspector_protocol
|
||||||
URL: https://chromium.googlesource.com/deps/inspector_protocol/
|
URL: https://chromium.googlesource.com/deps/inspector_protocol/
|
||||||
Version: 0
|
Version: 0
|
||||||
Revision: d2fc9b958e1eeb1e956f3e2208afa9923bdc9b67
|
Revision: d020a9e614d4a5116a7c71f288c0340e282e1a6e
|
||||||
License: BSD
|
License: BSD
|
||||||
License File: LICENSE
|
License File: LICENSE
|
||||||
Security Critical: no
|
Security Critical: no
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
// Copyright 2019 The V8 Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
// This file is V8 specific, to make bindings_test.cc work.
|
|
||||||
// It is not rolled from the upstream project.
|
|
||||||
|
|
||||||
#ifndef V8_INSPECTOR_PROTOCOL_BINDINGS_BINDINGS_TEST_HELPER_H_
|
|
||||||
#define V8_INSPECTOR_PROTOCOL_BINDINGS_BINDINGS_TEST_HELPER_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "src/base/logging.h"
|
|
||||||
#include "testing/gmock/include/gmock/gmock.h"
|
|
||||||
#include "testing/gtest/include/gtest/gtest.h"
|
|
||||||
|
|
||||||
#endif // V8_INSPECTOR_PROTOCOL_BINDINGS_BINDINGS_TEST_HELPER_H_
|
|
13
third_party/inspector_protocol/code_generator.py
vendored
13
third_party/inspector_protocol/code_generator.py
vendored
@ -112,16 +112,9 @@ def read_config():
|
|||||||
".lib": False,
|
".lib": False,
|
||||||
".lib.export_macro": "",
|
".lib.export_macro": "",
|
||||||
".lib.export_header": False,
|
".lib.export_header": False,
|
||||||
# The encoding lib consists of encoding/encoding.h and
|
".crdtp": False,
|
||||||
# encoding/encoding.cc in its subdirectory, which binaries
|
".crdtp.dir": os.path.join(inspector_protocol_dir, "crdtp"),
|
||||||
# must link / depend on.
|
".crdtp.namespace": "inspector_protocol",
|
||||||
".encoding_lib.header": os.path.join(inspector_protocol_dir,
|
|
||||||
"encoding/encoding.h"),
|
|
||||||
".encoding_lib.namespace": "",
|
|
||||||
# Ditto for bindings, see bindings/bindings.h.
|
|
||||||
".bindings_lib.header": os.path.join(inspector_protocol_dir,
|
|
||||||
"bindings/bindings.h"),
|
|
||||||
".bindings_lib.namespace": ""
|
|
||||||
}
|
}
|
||||||
for key_value in config_values:
|
for key_value in config_values:
|
||||||
parts = key_value.split("=")
|
parts = key_value.split("=")
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2,8 +2,8 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
#ifndef V8_INSPECTOR_PROTOCOL_ENCODING_ENCODING_H_
|
#ifndef V8_CRDTP_CBOR_H_
|
||||||
#define V8_INSPECTOR_PROTOCOL_ENCODING_ENCODING_H_
|
#define V8_CRDTP_CBOR_H_
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
@ -14,190 +14,11 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace v8_inspector_protocol_encoding {
|
#include "export.h"
|
||||||
// This library is designed to be portable. The only allowed dependency
|
#include "parser_handler.h"
|
||||||
// are the C/C++ standard libraries, up to C++11. We support both 32 bit
|
#include "span.h"
|
||||||
// and 64 architectures.
|
|
||||||
//
|
|
||||||
// Types used below:
|
|
||||||
// uint8_t: a byte, e.g. for raw bytes or UTF8 characters
|
|
||||||
// uint16_t: two bytes, e.g. for UTF16 characters
|
|
||||||
// For input parameters:
|
|
||||||
// span<uint8_t>: pointer to bytes and length
|
|
||||||
// span<uint16_t>: pointer to UTF16 chars and length
|
|
||||||
// For output parameters:
|
|
||||||
// std::vector<uint8_t> - Owned segment of bytes / utf8 characters and length.
|
|
||||||
// std::string - Same, for compatibility, even though char is signed.
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// span - sequence of bytes
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// This template is similar to std::span, which will be included in C++20.
|
|
||||||
template <typename T>
|
|
||||||
class span {
|
|
||||||
public:
|
|
||||||
using index_type = size_t;
|
|
||||||
|
|
||||||
span() : data_(nullptr), size_(0) {}
|
|
||||||
span(const T* data, index_type size) : data_(data), size_(size) {}
|
|
||||||
|
|
||||||
const T* data() const { return data_; }
|
|
||||||
|
|
||||||
const T* begin() const { return data_; }
|
|
||||||
const T* end() const { return data_ + size_; }
|
|
||||||
|
|
||||||
const T& operator[](index_type idx) const { return data_[idx]; }
|
|
||||||
|
|
||||||
span<T> subspan(index_type offset, index_type count) const {
|
|
||||||
return span(data_ + offset, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
span<T> subspan(index_type offset) const {
|
|
||||||
return span(data_ + offset, size_ - offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool empty() const { return size_ == 0; }
|
|
||||||
|
|
||||||
index_type size() const { return size_; }
|
|
||||||
index_type size_bytes() const { return size_ * sizeof(T); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
const T* data_;
|
|
||||||
index_type size_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
span<T> SpanFrom(const std::vector<T>& v) {
|
|
||||||
return span<T>(v.data(), v.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t N>
|
|
||||||
span<uint8_t> SpanFrom(const char (&str)[N]) {
|
|
||||||
return span<uint8_t>(reinterpret_cast<const uint8_t*>(str), N - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline span<uint8_t> SpanFrom(const char* str) {
|
|
||||||
return str ? span<uint8_t>(reinterpret_cast<const uint8_t*>(str), strlen(str))
|
|
||||||
: span<uint8_t>();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline span<uint8_t> SpanFrom(const std::string& v) {
|
|
||||||
return span<uint8_t>(reinterpret_cast<const uint8_t*>(v.data()), v.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Less than / equality comparison functions for sorting / searching for byte
|
|
||||||
// spans. These are similar to absl::string_view's < and == operators.
|
|
||||||
inline bool SpanLessThan(span<uint8_t> x, span<uint8_t> y) noexcept {
|
|
||||||
auto min_size = std::min(x.size(), y.size());
|
|
||||||
const int r = min_size == 0 ? 0 : memcmp(x.data(), y.data(), min_size);
|
|
||||||
return (r < 0) || (r == 0 && x.size() < y.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool SpanEquals(span<uint8_t> x, span<uint8_t> y) noexcept {
|
|
||||||
auto len = x.size();
|
|
||||||
if (len != y.size())
|
|
||||||
return false;
|
|
||||||
return x.data() == y.data() || len == 0 ||
|
|
||||||
std::memcmp(x.data(), y.data(), len) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// Status and Error codes
|
|
||||||
// =============================================================================
|
|
||||||
enum class Error {
|
|
||||||
OK = 0,
|
|
||||||
// JSON parsing errors - json_parser.{h,cc}.
|
|
||||||
JSON_PARSER_UNPROCESSED_INPUT_REMAINS = 0x01,
|
|
||||||
JSON_PARSER_STACK_LIMIT_EXCEEDED = 0x02,
|
|
||||||
JSON_PARSER_NO_INPUT = 0x03,
|
|
||||||
JSON_PARSER_INVALID_TOKEN = 0x04,
|
|
||||||
JSON_PARSER_INVALID_NUMBER = 0x05,
|
|
||||||
JSON_PARSER_INVALID_STRING = 0x06,
|
|
||||||
JSON_PARSER_UNEXPECTED_ARRAY_END = 0x07,
|
|
||||||
JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED = 0x08,
|
|
||||||
JSON_PARSER_STRING_LITERAL_EXPECTED = 0x09,
|
|
||||||
JSON_PARSER_COLON_EXPECTED = 0x0a,
|
|
||||||
JSON_PARSER_UNEXPECTED_MAP_END = 0x0b,
|
|
||||||
JSON_PARSER_COMMA_OR_MAP_END_EXPECTED = 0x0c,
|
|
||||||
JSON_PARSER_VALUE_EXPECTED = 0x0d,
|
|
||||||
|
|
||||||
CBOR_INVALID_INT32 = 0x0e,
|
|
||||||
CBOR_INVALID_DOUBLE = 0x0f,
|
|
||||||
CBOR_INVALID_ENVELOPE = 0x10,
|
|
||||||
CBOR_ENVELOPE_CONTENTS_LENGTH_MISMATCH = 0x11,
|
|
||||||
CBOR_MAP_OR_ARRAY_EXPECTED_IN_ENVELOPE = 0x12,
|
|
||||||
CBOR_INVALID_STRING8 = 0x13,
|
|
||||||
CBOR_INVALID_STRING16 = 0x14,
|
|
||||||
CBOR_INVALID_BINARY = 0x15,
|
|
||||||
CBOR_UNSUPPORTED_VALUE = 0x16,
|
|
||||||
CBOR_NO_INPUT = 0x17,
|
|
||||||
CBOR_INVALID_START_BYTE = 0x18,
|
|
||||||
CBOR_UNEXPECTED_EOF_EXPECTED_VALUE = 0x19,
|
|
||||||
CBOR_UNEXPECTED_EOF_IN_ARRAY = 0x1a,
|
|
||||||
CBOR_UNEXPECTED_EOF_IN_MAP = 0x1b,
|
|
||||||
CBOR_INVALID_MAP_KEY = 0x1c,
|
|
||||||
CBOR_STACK_LIMIT_EXCEEDED = 0x1d,
|
|
||||||
CBOR_TRAILING_JUNK = 0x1e,
|
|
||||||
CBOR_MAP_START_EXPECTED = 0x1f,
|
|
||||||
CBOR_MAP_STOP_EXPECTED = 0x20,
|
|
||||||
CBOR_ARRAY_START_EXPECTED = 0x21,
|
|
||||||
CBOR_ENVELOPE_SIZE_LIMIT_EXCEEDED = 0x22,
|
|
||||||
|
|
||||||
BINDINGS_MANDATORY_FIELD_MISSING = 0x23,
|
|
||||||
BINDINGS_BOOL_VALUE_EXPECTED = 0x24,
|
|
||||||
BINDINGS_INT32_VALUE_EXPECTED = 0x25,
|
|
||||||
BINDINGS_DOUBLE_VALUE_EXPECTED = 0x26,
|
|
||||||
BINDINGS_STRING_VALUE_EXPECTED = 0x27,
|
|
||||||
BINDINGS_STRING8_VALUE_EXPECTED = 0x28,
|
|
||||||
BINDINGS_BINARY_VALUE_EXPECTED = 0x29,
|
|
||||||
};
|
|
||||||
|
|
||||||
// A status value with position that can be copied. The default status
|
|
||||||
// is OK. Usually, error status values should come with a valid position.
|
|
||||||
struct Status {
|
|
||||||
static constexpr size_t npos() { return std::numeric_limits<size_t>::max(); }
|
|
||||||
|
|
||||||
bool ok() const { return error == Error::OK; }
|
|
||||||
|
|
||||||
Error error = Error::OK;
|
|
||||||
size_t pos = npos();
|
|
||||||
Status(Error error, size_t pos) : error(error), pos(pos) {}
|
|
||||||
Status() = default;
|
|
||||||
|
|
||||||
// Returns a 7 bit US-ASCII string, either "OK" or an error message
|
|
||||||
// that includes the position.
|
|
||||||
std::string ToASCIIString() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string ToASCIIString(const char* msg) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handler interface for parser events emitted by a streaming parser.
|
|
||||||
// See cbor::NewCBOREncoder, cbor::ParseCBOR, json::NewJSONEncoder,
|
|
||||||
// json::ParseJSON.
|
|
||||||
class StreamingParserHandler {
|
|
||||||
public:
|
|
||||||
virtual ~StreamingParserHandler() = default;
|
|
||||||
virtual void HandleMapBegin() = 0;
|
|
||||||
virtual void HandleMapEnd() = 0;
|
|
||||||
virtual void HandleArrayBegin() = 0;
|
|
||||||
virtual void HandleArrayEnd() = 0;
|
|
||||||
virtual void HandleString8(span<uint8_t> chars) = 0;
|
|
||||||
virtual void HandleString16(span<uint16_t> chars) = 0;
|
|
||||||
virtual void HandleBinary(span<uint8_t> bytes) = 0;
|
|
||||||
virtual void HandleDouble(double value) = 0;
|
|
||||||
virtual void HandleInt32(int32_t value) = 0;
|
|
||||||
virtual void HandleBool(bool value) = 0;
|
|
||||||
virtual void HandleNull() = 0;
|
|
||||||
|
|
||||||
// The parser may send one error even after other events have already
|
|
||||||
// been received. Client code is reponsible to then discard the
|
|
||||||
// already processed events.
|
|
||||||
// |error| must be an eror, as in, |error.is_ok()| can't be true.
|
|
||||||
virtual void HandleError(Status error) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
namespace v8_crdtp {
|
||||||
namespace cbor {
|
namespace cbor {
|
||||||
// The binary encoding for the inspector protocol follows the CBOR specification
|
// The binary encoding for the inspector protocol follows the CBOR specification
|
||||||
// (RFC 7049). Additional constraints:
|
// (RFC 7049). Additional constraints:
|
||||||
@ -491,72 +312,6 @@ void WriteTokenStart(cbor::MajorType type,
|
|||||||
std::string* encoded);
|
std::string* encoded);
|
||||||
} // namespace internals
|
} // namespace internals
|
||||||
} // namespace cbor
|
} // namespace cbor
|
||||||
|
} // namespace v8_crdtp
|
||||||
|
|
||||||
namespace json {
|
#endif // V8_CRDTP_CBOR_H_
|
||||||
// Client code must provide an instance. Implementation should delegate
|
|
||||||
// to whatever is appropriate.
|
|
||||||
class Platform {
|
|
||||||
public:
|
|
||||||
virtual ~Platform() = default;
|
|
||||||
// Parses |str| into |result|. Returns false iff there are
|
|
||||||
// leftover characters or parsing errors.
|
|
||||||
virtual bool StrToD(const char* str, double* result) const = 0;
|
|
||||||
|
|
||||||
// Prints |value| in a format suitable for JSON.
|
|
||||||
virtual std::unique_ptr<char[]> DToStr(double value) const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// json::NewJSONEncoder - for encoding streaming parser events as JSON
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// Returns a handler object which will write ascii characters to |out|.
|
|
||||||
// |status->ok()| will be false iff the handler routine HandleError() is called.
|
|
||||||
// In that case, we'll stop emitting output.
|
|
||||||
// Except for calling the HandleError routine at any time, the client
|
|
||||||
// code must call the Handle* methods in an order in which they'd occur
|
|
||||||
// in valid JSON; otherwise we may crash (the code uses assert).
|
|
||||||
std::unique_ptr<StreamingParserHandler> NewJSONEncoder(
|
|
||||||
const Platform* platform,
|
|
||||||
std::vector<uint8_t>* out,
|
|
||||||
Status* status);
|
|
||||||
std::unique_ptr<StreamingParserHandler> NewJSONEncoder(const Platform* platform,
|
|
||||||
std::string* out,
|
|
||||||
Status* status);
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// json::ParseJSON - for receiving streaming parser events for JSON
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
void ParseJSON(const Platform& platform,
|
|
||||||
span<uint8_t> chars,
|
|
||||||
StreamingParserHandler* handler);
|
|
||||||
void ParseJSON(const Platform& platform,
|
|
||||||
span<uint16_t> chars,
|
|
||||||
StreamingParserHandler* handler);
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// json::ConvertCBORToJSON, json::ConvertJSONToCBOR - for transcoding
|
|
||||||
// =============================================================================
|
|
||||||
Status ConvertCBORToJSON(const Platform& platform,
|
|
||||||
span<uint8_t> cbor,
|
|
||||||
std::string* json);
|
|
||||||
Status ConvertCBORToJSON(const Platform& platform,
|
|
||||||
span<uint8_t> cbor,
|
|
||||||
std::vector<uint8_t>* json);
|
|
||||||
Status ConvertJSONToCBOR(const Platform& platform,
|
|
||||||
span<uint8_t> json,
|
|
||||||
std::vector<uint8_t>* cbor);
|
|
||||||
Status ConvertJSONToCBOR(const Platform& platform,
|
|
||||||
span<uint16_t> json,
|
|
||||||
std::vector<uint8_t>* cbor);
|
|
||||||
Status ConvertJSONToCBOR(const Platform& platform,
|
|
||||||
span<uint8_t> json,
|
|
||||||
std::string* cbor);
|
|
||||||
Status ConvertJSONToCBOR(const Platform& platform,
|
|
||||||
span<uint16_t> json,
|
|
||||||
std::string* cbor);
|
|
||||||
} // namespace json
|
|
||||||
} // namespace v8_inspector_protocol_encoding
|
|
||||||
|
|
||||||
#endif // V8_INSPECTOR_PROTOCOL_ENCODING_ENCODING_H_
|
|
@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
#include "encoding.h"
|
#include "cbor.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <clocale>
|
#include <clocale>
|
||||||
@ -14,12 +14,13 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "encoding_test_helper.h"
|
#include "json.h"
|
||||||
|
#include "test_platform.h"
|
||||||
|
|
||||||
using testing::ElementsAreArray;
|
using testing::ElementsAreArray;
|
||||||
|
|
||||||
namespace v8_inspector_protocol_encoding {
|
namespace v8_crdtp {
|
||||||
|
namespace {
|
||||||
class TestPlatform : public json::Platform {
|
class TestPlatform : public json::Platform {
|
||||||
bool StrToD(const char* str, double* result) const override {
|
bool StrToD(const char* str, double* result) const override {
|
||||||
// This is not thread-safe
|
// This is not thread-safe
|
||||||
@ -53,108 +54,7 @@ const json::Platform& GetTestPlatform() {
|
|||||||
static TestPlatform* platform = new TestPlatform;
|
static TestPlatform* platform = new TestPlatform;
|
||||||
return *platform;
|
return *platform;
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
// =============================================================================
|
|
||||||
// span - sequence of bytes
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class SpanTest : public ::testing::Test {};
|
|
||||||
|
|
||||||
using TestTypes = ::testing::Types<uint8_t, uint16_t>;
|
|
||||||
TYPED_TEST_SUITE(SpanTest, TestTypes);
|
|
||||||
|
|
||||||
TYPED_TEST(SpanTest, Empty) {
|
|
||||||
span<TypeParam> empty;
|
|
||||||
EXPECT_TRUE(empty.empty());
|
|
||||||
EXPECT_EQ(0u, empty.size());
|
|
||||||
EXPECT_EQ(0u, empty.size_bytes());
|
|
||||||
EXPECT_EQ(empty.begin(), empty.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(SpanTest, SingleItem) {
|
|
||||||
TypeParam single_item = 42;
|
|
||||||
span<TypeParam> singular(&single_item, 1);
|
|
||||||
EXPECT_FALSE(singular.empty());
|
|
||||||
EXPECT_EQ(1u, singular.size());
|
|
||||||
EXPECT_EQ(sizeof(TypeParam), singular.size_bytes());
|
|
||||||
EXPECT_EQ(singular.begin() + 1, singular.end());
|
|
||||||
EXPECT_EQ(42, singular[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(SpanTest, FiveItems) {
|
|
||||||
std::vector<TypeParam> test_input = {31, 32, 33, 34, 35};
|
|
||||||
span<TypeParam> five_items(test_input.data(), 5);
|
|
||||||
EXPECT_FALSE(five_items.empty());
|
|
||||||
EXPECT_EQ(5u, five_items.size());
|
|
||||||
EXPECT_EQ(sizeof(TypeParam) * 5, five_items.size_bytes());
|
|
||||||
EXPECT_EQ(five_items.begin() + 5, five_items.end());
|
|
||||||
EXPECT_EQ(31, five_items[0]);
|
|
||||||
EXPECT_EQ(32, five_items[1]);
|
|
||||||
EXPECT_EQ(33, five_items[2]);
|
|
||||||
EXPECT_EQ(34, five_items[3]);
|
|
||||||
EXPECT_EQ(35, five_items[4]);
|
|
||||||
span<TypeParam> three_items = five_items.subspan(2);
|
|
||||||
EXPECT_EQ(3u, three_items.size());
|
|
||||||
EXPECT_EQ(33, three_items[0]);
|
|
||||||
EXPECT_EQ(34, three_items[1]);
|
|
||||||
EXPECT_EQ(35, three_items[2]);
|
|
||||||
span<TypeParam> two_items = five_items.subspan(2, 2);
|
|
||||||
EXPECT_EQ(2u, two_items.size());
|
|
||||||
EXPECT_EQ(33, two_items[0]);
|
|
||||||
EXPECT_EQ(34, two_items[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(SpanFromTest, FromConstCharAndLiteral) {
|
|
||||||
// Testing this is useful because strlen(nullptr) is undefined.
|
|
||||||
EXPECT_EQ(nullptr, SpanFrom(nullptr).data());
|
|
||||||
EXPECT_EQ(0u, SpanFrom(nullptr).size());
|
|
||||||
|
|
||||||
const char* kEmpty = "";
|
|
||||||
EXPECT_EQ(kEmpty, reinterpret_cast<const char*>(SpanFrom(kEmpty).data()));
|
|
||||||
EXPECT_EQ(0u, SpanFrom(kEmpty).size());
|
|
||||||
|
|
||||||
const char* kFoo = "foo";
|
|
||||||
EXPECT_EQ(kFoo, reinterpret_cast<const char*>(SpanFrom(kFoo).data()));
|
|
||||||
EXPECT_EQ(3u, SpanFrom(kFoo).size());
|
|
||||||
|
|
||||||
EXPECT_EQ(3u, SpanFrom("foo").size());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(SpanComparisons, ByteWiseLexicographicalOrder) {
|
|
||||||
// Compare the empty span.
|
|
||||||
EXPECT_FALSE(SpanLessThan(span<uint8_t>(), span<uint8_t>()));
|
|
||||||
EXPECT_TRUE(SpanEquals(span<uint8_t>(), span<uint8_t>()));
|
|
||||||
|
|
||||||
// Compare message with itself.
|
|
||||||
std::string msg = "Hello, world";
|
|
||||||
EXPECT_FALSE(SpanLessThan(SpanFrom(msg), SpanFrom(msg)));
|
|
||||||
EXPECT_TRUE(SpanEquals(SpanFrom(msg), SpanFrom(msg)));
|
|
||||||
|
|
||||||
// Compare message and copy.
|
|
||||||
EXPECT_FALSE(SpanLessThan(SpanFrom(msg), SpanFrom(std::string(msg))));
|
|
||||||
EXPECT_TRUE(SpanEquals(SpanFrom(msg), SpanFrom(std::string(msg))));
|
|
||||||
|
|
||||||
// Compare two messages. |lesser_msg| < |msg| because of the first
|
|
||||||
// byte ('A' < 'H').
|
|
||||||
std::string lesser_msg = "A lesser message.";
|
|
||||||
EXPECT_TRUE(SpanLessThan(SpanFrom(lesser_msg), SpanFrom(msg)));
|
|
||||||
EXPECT_FALSE(SpanLessThan(SpanFrom(msg), SpanFrom(lesser_msg)));
|
|
||||||
EXPECT_FALSE(SpanEquals(SpanFrom(msg), SpanFrom(lesser_msg)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// Status and Error codes
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
TEST(StatusTest, StatusToASCIIString) {
|
|
||||||
Status ok_status;
|
|
||||||
EXPECT_EQ("OK", ok_status.ToASCIIString());
|
|
||||||
Status json_error(Error::JSON_PARSER_COLON_EXPECTED, 42);
|
|
||||||
EXPECT_EQ("JSON: colon expected at position 42", json_error.ToASCIIString());
|
|
||||||
Status cbor_error(Error::CBOR_TRAILING_JUNK, 21);
|
|
||||||
EXPECT_EQ("CBOR: trailing junk at position 21", cbor_error.ToASCIIString());
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace cbor {
|
namespace cbor {
|
||||||
|
|
||||||
@ -923,8 +823,8 @@ TEST(ParseCBORTest, ParseEmptyCBORMessage) {
|
|||||||
TEST(ParseCBORTest, ParseCBORHelloWorld) {
|
TEST(ParseCBORTest, ParseCBORHelloWorld) {
|
||||||
const uint8_t kPayloadLen = 27;
|
const uint8_t kPayloadLen = 27;
|
||||||
std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen};
|
std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen};
|
||||||
bytes.push_back(0xbf); // start indef length map.
|
bytes.push_back(0xbf); // start indef length map.
|
||||||
EncodeString8(SpanFrom("msg"), &bytes); // key: msg
|
EncodeString8(SpanFrom("msg"), &bytes); // key: msg
|
||||||
// Now write the value, the familiar "Hello, 🌎." where the globe is expressed
|
// Now write the value, the familiar "Hello, 🌎." where the globe is expressed
|
||||||
// as two utf16 chars.
|
// as two utf16 chars.
|
||||||
bytes.push_back(/*major type=*/2 << 5 | /*additional info=*/20);
|
bytes.push_back(/*major type=*/2 << 5 | /*additional info=*/20);
|
||||||
@ -1490,623 +1390,4 @@ TYPED_TEST(AppendString8EntryToMapTest, InvalidEnvelope_Error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace cbor
|
} // namespace cbor
|
||||||
|
} // namespace v8_crdtp
|
||||||
namespace json {
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// json::NewJSONEncoder - for encoding streaming parser events as JSON
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
void WriteUTF8AsUTF16(StreamingParserHandler* writer, const std::string& utf8) {
|
|
||||||
writer->HandleString16(SpanFrom(UTF8ToUTF16(SpanFrom(utf8))));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(JsonEncoder, OverlongEncodings) {
|
|
||||||
std::string out;
|
|
||||||
Status status;
|
|
||||||
std::unique_ptr<StreamingParserHandler> writer =
|
|
||||||
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
|
||||||
|
|
||||||
// We encode 0x7f, which is the DEL ascii character, as a 4 byte UTF8
|
|
||||||
// sequence. This is called an overlong encoding, because only 1 byte
|
|
||||||
// is needed to represent 0x7f as UTF8.
|
|
||||||
std::vector<uint8_t> chars = {
|
|
||||||
0xf0, // Starts 4 byte utf8 sequence
|
|
||||||
0x80, // continuation byte
|
|
||||||
0x81, // continuation byte w/ payload bit 7 set to 1.
|
|
||||||
0xbf, // continuation byte w/ payload bits 0-6 set to 11111.
|
|
||||||
};
|
|
||||||
writer->HandleString8(SpanFrom(chars));
|
|
||||||
EXPECT_EQ("\"\"", out); // Empty string means that 0x7f was rejected (good).
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(JsonEncoder, IncompleteUtf8Sequence) {
|
|
||||||
std::string out;
|
|
||||||
Status status;
|
|
||||||
std::unique_ptr<StreamingParserHandler> writer =
|
|
||||||
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
|
||||||
|
|
||||||
writer->HandleArrayBegin(); // This emits [, which starts an array.
|
|
||||||
|
|
||||||
{ // 🌎 takes four bytes to encode in UTF-8. We test with the first three;
|
|
||||||
// This means we're trying to emit a string that consists solely of an
|
|
||||||
// incomplete UTF-8 sequence. So the string in the JSON output is empty.
|
|
||||||
std::string world_utf8 = "🌎";
|
|
||||||
ASSERT_EQ(4u, world_utf8.size());
|
|
||||||
std::vector<uint8_t> chars(world_utf8.begin(), world_utf8.begin() + 3);
|
|
||||||
writer->HandleString8(SpanFrom(chars));
|
|
||||||
EXPECT_EQ("[\"\"", out); // Incomplete sequence rejected: empty string.
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // This time, the incomplete sequence is at the end of the string.
|
|
||||||
std::string msg = "Hello, \xF0\x9F\x8C";
|
|
||||||
std::vector<uint8_t> chars(msg.begin(), msg.end());
|
|
||||||
writer->HandleString8(SpanFrom(chars));
|
|
||||||
EXPECT_EQ("[\"\",\"Hello, \"", out); // Incomplete sequence dropped at end.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(JsonStdStringWriterTest, HelloWorld) {
|
|
||||||
std::string out;
|
|
||||||
Status status;
|
|
||||||
std::unique_ptr<StreamingParserHandler> writer =
|
|
||||||
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
|
||||||
writer->HandleMapBegin();
|
|
||||||
WriteUTF8AsUTF16(writer.get(), "msg1");
|
|
||||||
WriteUTF8AsUTF16(writer.get(), "Hello, 🌎.");
|
|
||||||
std::string key = "msg1-as-utf8";
|
|
||||||
std::string value = "Hello, 🌎.";
|
|
||||||
writer->HandleString8(SpanFrom(key));
|
|
||||||
writer->HandleString8(SpanFrom(value));
|
|
||||||
WriteUTF8AsUTF16(writer.get(), "msg2");
|
|
||||||
WriteUTF8AsUTF16(writer.get(), "\\\b\r\n\t\f\"");
|
|
||||||
WriteUTF8AsUTF16(writer.get(), "nested");
|
|
||||||
writer->HandleMapBegin();
|
|
||||||
WriteUTF8AsUTF16(writer.get(), "double");
|
|
||||||
writer->HandleDouble(3.1415);
|
|
||||||
WriteUTF8AsUTF16(writer.get(), "int");
|
|
||||||
writer->HandleInt32(-42);
|
|
||||||
WriteUTF8AsUTF16(writer.get(), "bool");
|
|
||||||
writer->HandleBool(false);
|
|
||||||
WriteUTF8AsUTF16(writer.get(), "null");
|
|
||||||
writer->HandleNull();
|
|
||||||
writer->HandleMapEnd();
|
|
||||||
WriteUTF8AsUTF16(writer.get(), "array");
|
|
||||||
writer->HandleArrayBegin();
|
|
||||||
writer->HandleInt32(1);
|
|
||||||
writer->HandleInt32(2);
|
|
||||||
writer->HandleInt32(3);
|
|
||||||
writer->HandleArrayEnd();
|
|
||||||
writer->HandleMapEnd();
|
|
||||||
EXPECT_TRUE(status.ok());
|
|
||||||
EXPECT_EQ(
|
|
||||||
"{\"msg1\":\"Hello, \\ud83c\\udf0e.\","
|
|
||||||
"\"msg1-as-utf8\":\"Hello, \\ud83c\\udf0e.\","
|
|
||||||
"\"msg2\":\"\\\\\\b\\r\\n\\t\\f\\\"\","
|
|
||||||
"\"nested\":{\"double\":3.1415,\"int\":-42,"
|
|
||||||
"\"bool\":false,\"null\":null},\"array\":[1,2,3]}",
|
|
||||||
out);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(JsonStdStringWriterTest, RepresentingNonFiniteValuesAsNull) {
|
|
||||||
// JSON can't represent +Infinity, -Infinity, or NaN.
|
|
||||||
// So in practice it's mapped to null.
|
|
||||||
std::string out;
|
|
||||||
Status status;
|
|
||||||
std::unique_ptr<StreamingParserHandler> writer =
|
|
||||||
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
|
||||||
writer->HandleMapBegin();
|
|
||||||
writer->HandleString8(SpanFrom("Infinity"));
|
|
||||||
writer->HandleDouble(std::numeric_limits<double>::infinity());
|
|
||||||
writer->HandleString8(SpanFrom("-Infinity"));
|
|
||||||
writer->HandleDouble(-std::numeric_limits<double>::infinity());
|
|
||||||
writer->HandleString8(SpanFrom("NaN"));
|
|
||||||
writer->HandleDouble(std::numeric_limits<double>::quiet_NaN());
|
|
||||||
writer->HandleMapEnd();
|
|
||||||
EXPECT_TRUE(status.ok());
|
|
||||||
EXPECT_EQ("{\"Infinity\":null,\"-Infinity\":null,\"NaN\":null}", out);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(JsonStdStringWriterTest, BinaryEncodedAsJsonString) {
|
|
||||||
// The encoder emits binary submitted to StreamingParserHandler::HandleBinary
|
|
||||||
// as base64. The following three examples are taken from
|
|
||||||
// https://en.wikipedia.org/wiki/Base64.
|
|
||||||
{
|
|
||||||
std::string out;
|
|
||||||
Status status;
|
|
||||||
std::unique_ptr<StreamingParserHandler> writer =
|
|
||||||
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
|
||||||
writer->HandleBinary(SpanFrom(std::vector<uint8_t>({'M', 'a', 'n'})));
|
|
||||||
EXPECT_TRUE(status.ok());
|
|
||||||
EXPECT_EQ("\"TWFu\"", out);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
std::string out;
|
|
||||||
Status status;
|
|
||||||
std::unique_ptr<StreamingParserHandler> writer =
|
|
||||||
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
|
||||||
writer->HandleBinary(SpanFrom(std::vector<uint8_t>({'M', 'a'})));
|
|
||||||
EXPECT_TRUE(status.ok());
|
|
||||||
EXPECT_EQ("\"TWE=\"", out);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
std::string out;
|
|
||||||
Status status;
|
|
||||||
std::unique_ptr<StreamingParserHandler> writer =
|
|
||||||
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
|
||||||
writer->HandleBinary(SpanFrom(std::vector<uint8_t>({'M'})));
|
|
||||||
EXPECT_TRUE(status.ok());
|
|
||||||
EXPECT_EQ("\"TQ==\"", out);
|
|
||||||
}
|
|
||||||
{ // "Hello, world.", verified with base64decode.org.
|
|
||||||
std::string out;
|
|
||||||
Status status;
|
|
||||||
std::unique_ptr<StreamingParserHandler> writer =
|
|
||||||
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
|
||||||
writer->HandleBinary(SpanFrom(std::vector<uint8_t>(
|
|
||||||
{'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.'})));
|
|
||||||
EXPECT_TRUE(status.ok());
|
|
||||||
EXPECT_EQ("\"SGVsbG8sIHdvcmxkLg==\"", out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(JsonStdStringWriterTest, HandlesErrors) {
|
|
||||||
// When an error is sent via HandleError, it saves it in the provided
|
|
||||||
// status and clears the output.
|
|
||||||
std::string out;
|
|
||||||
Status status;
|
|
||||||
std::unique_ptr<StreamingParserHandler> writer =
|
|
||||||
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
|
||||||
writer->HandleMapBegin();
|
|
||||||
WriteUTF8AsUTF16(writer.get(), "msg1");
|
|
||||||
writer->HandleError(Status{Error::JSON_PARSER_VALUE_EXPECTED, 42});
|
|
||||||
EXPECT_EQ(Error::JSON_PARSER_VALUE_EXPECTED, status.error);
|
|
||||||
EXPECT_EQ(42u, status.pos);
|
|
||||||
EXPECT_EQ("", out);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We'd use Gmock but unfortunately it only handles copyable return types.
|
|
||||||
class MockPlatform : public Platform {
|
|
||||||
public:
|
|
||||||
// Not implemented.
|
|
||||||
bool StrToD(const char* str, double* result) const override { return false; }
|
|
||||||
|
|
||||||
// A map with pre-registered responses for DToSTr.
|
|
||||||
std::map<double, std::string> dtostr_responses_;
|
|
||||||
|
|
||||||
std::unique_ptr<char[]> DToStr(double value) const override {
|
|
||||||
auto it = dtostr_responses_.find(value);
|
|
||||||
CHECK(it != dtostr_responses_.end());
|
|
||||||
const std::string& str = it->second;
|
|
||||||
std::unique_ptr<char[]> response(new char[str.size() + 1]);
|
|
||||||
memcpy(response.get(), str.c_str(), str.size() + 1);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(JsonStdStringWriterTest, DoubleToString) {
|
|
||||||
// This "broken" platform responds without the leading 0 before the
|
|
||||||
// decimal dot, so it'd be invalid JSON.
|
|
||||||
MockPlatform platform;
|
|
||||||
platform.dtostr_responses_[.1] = ".1";
|
|
||||||
platform.dtostr_responses_[-.7] = "-.7";
|
|
||||||
|
|
||||||
std::string out;
|
|
||||||
Status status;
|
|
||||||
std::unique_ptr<StreamingParserHandler> writer =
|
|
||||||
NewJSONEncoder(&platform, &out, &status);
|
|
||||||
writer->HandleArrayBegin();
|
|
||||||
writer->HandleDouble(.1);
|
|
||||||
writer->HandleDouble(-.7);
|
|
||||||
writer->HandleArrayEnd();
|
|
||||||
EXPECT_EQ("[0.1,-0.7]", out);
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// json::ParseJSON - for receiving streaming parser events for JSON
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
class Log : public StreamingParserHandler {
|
|
||||||
public:
|
|
||||||
void HandleMapBegin() override { log_ << "map begin\n"; }
|
|
||||||
|
|
||||||
void HandleMapEnd() override { log_ << "map end\n"; }
|
|
||||||
|
|
||||||
void HandleArrayBegin() override { log_ << "array begin\n"; }
|
|
||||||
|
|
||||||
void HandleArrayEnd() override { log_ << "array end\n"; }
|
|
||||||
|
|
||||||
void HandleString8(span<uint8_t> chars) override {
|
|
||||||
log_ << "string8: " << std::string(chars.begin(), chars.end()) << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
void HandleString16(span<uint16_t> chars) override {
|
|
||||||
log_ << "string16: " << UTF16ToUTF8(chars) << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
void HandleBinary(span<uint8_t> bytes) override {
|
|
||||||
// JSON doesn't have native support for arbitrary bytes, so our parser will
|
|
||||||
// never call this.
|
|
||||||
CHECK(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HandleDouble(double value) override {
|
|
||||||
log_ << "double: " << value << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
void HandleInt32(int32_t value) override { log_ << "int: " << value << "\n"; }
|
|
||||||
|
|
||||||
void HandleBool(bool value) override { log_ << "bool: " << value << "\n"; }
|
|
||||||
|
|
||||||
void HandleNull() override { log_ << "null\n"; }
|
|
||||||
|
|
||||||
void HandleError(Status status) override { status_ = status; }
|
|
||||||
|
|
||||||
std::string str() const { return status_.ok() ? log_.str() : ""; }
|
|
||||||
|
|
||||||
Status status() const { return status_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::ostringstream log_;
|
|
||||||
Status status_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class JsonParserTest : public ::testing::Test {
|
|
||||||
protected:
|
|
||||||
Log log_;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, SimpleDictionary) {
|
|
||||||
std::string json = "{\"foo\": 42}";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_TRUE(log_.status().ok());
|
|
||||||
EXPECT_EQ(
|
|
||||||
"map begin\n"
|
|
||||||
"string16: foo\n"
|
|
||||||
"int: 42\n"
|
|
||||||
"map end\n",
|
|
||||||
log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, UsAsciiDelCornerCase) {
|
|
||||||
// DEL (0x7f) is a 7 bit US-ASCII character, and while it is a control
|
|
||||||
// character according to Unicode, it's not considered a control
|
|
||||||
// character in https://tools.ietf.org/html/rfc7159#section-7, so
|
|
||||||
// it can be placed directly into the JSON string, without JSON escaping.
|
|
||||||
std::string json = "{\"foo\": \"a\x7f\"}";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_TRUE(log_.status().ok());
|
|
||||||
EXPECT_EQ(
|
|
||||||
"map begin\n"
|
|
||||||
"string16: foo\n"
|
|
||||||
"string16: a\x7f\n"
|
|
||||||
"map end\n",
|
|
||||||
log_.str());
|
|
||||||
|
|
||||||
// We've seen an implementation of UTF16ToUTF8 which would replace the DEL
|
|
||||||
// character with ' ', so this simple roundtrip tests the routines in
|
|
||||||
// encoding_test_helper.h, to make test failures of the above easier to
|
|
||||||
// diagnose.
|
|
||||||
std::vector<uint16_t> utf16 = UTF8ToUTF16(SpanFrom(json));
|
|
||||||
EXPECT_EQ(json, UTF16ToUTF8(SpanFrom(utf16)));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, Whitespace) {
|
|
||||||
std::string json = "\n {\n\"msg\"\n: \v\"Hello, world.\"\t\r}\t";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_TRUE(log_.status().ok());
|
|
||||||
EXPECT_EQ(
|
|
||||||
"map begin\n"
|
|
||||||
"string16: msg\n"
|
|
||||||
"string16: Hello, world.\n"
|
|
||||||
"map end\n",
|
|
||||||
log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, NestedDictionary) {
|
|
||||||
std::string json = "{\"foo\": {\"bar\": {\"baz\": 1}, \"bar2\": 2}}";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_TRUE(log_.status().ok());
|
|
||||||
EXPECT_EQ(
|
|
||||||
"map begin\n"
|
|
||||||
"string16: foo\n"
|
|
||||||
"map begin\n"
|
|
||||||
"string16: bar\n"
|
|
||||||
"map begin\n"
|
|
||||||
"string16: baz\n"
|
|
||||||
"int: 1\n"
|
|
||||||
"map end\n"
|
|
||||||
"string16: bar2\n"
|
|
||||||
"int: 2\n"
|
|
||||||
"map end\n"
|
|
||||||
"map end\n",
|
|
||||||
log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, Doubles) {
|
|
||||||
std::string json = "{\"foo\": 3.1415, \"bar\": 31415e-4}";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_TRUE(log_.status().ok());
|
|
||||||
EXPECT_EQ(
|
|
||||||
"map begin\n"
|
|
||||||
"string16: foo\n"
|
|
||||||
"double: 3.1415\n"
|
|
||||||
"string16: bar\n"
|
|
||||||
"double: 3.1415\n"
|
|
||||||
"map end\n",
|
|
||||||
log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, Unicode) {
|
|
||||||
// Globe character. 0xF0 0x9F 0x8C 0x8E in utf8, 0xD83C 0xDF0E in utf16.
|
|
||||||
std::string json = "{\"msg\": \"Hello, \\uD83C\\uDF0E.\"}";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_TRUE(log_.status().ok());
|
|
||||||
EXPECT_EQ(
|
|
||||||
"map begin\n"
|
|
||||||
"string16: msg\n"
|
|
||||||
"string16: Hello, 🌎.\n"
|
|
||||||
"map end\n",
|
|
||||||
log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, Unicode_ParseUtf16) {
|
|
||||||
// Globe character. utf8: 0xF0 0x9F 0x8C 0x8E; utf16: 0xD83C 0xDF0E.
|
|
||||||
// Crescent moon character. utf8: 0xF0 0x9F 0x8C 0x99; utf16: 0xD83C 0xDF19.
|
|
||||||
|
|
||||||
// We provide the moon with json escape, but the earth as utf16 input.
|
|
||||||
// Either way they arrive as utf8 (after decoding in log_.str()).
|
|
||||||
std::vector<uint16_t> json =
|
|
||||||
UTF8ToUTF16(SpanFrom("{\"space\": \"🌎 \\uD83C\\uDF19.\"}"));
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_TRUE(log_.status().ok());
|
|
||||||
EXPECT_EQ(
|
|
||||||
"map begin\n"
|
|
||||||
"string16: space\n"
|
|
||||||
"string16: 🌎 🌙.\n"
|
|
||||||
"map end\n",
|
|
||||||
log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, Unicode_ParseUtf8) {
|
|
||||||
// Used below:
|
|
||||||
// гласность - example for 2 byte utf8, Russian word "glasnost"
|
|
||||||
// 屋 - example for 3 byte utf8, Chinese word for "house"
|
|
||||||
// 🌎 - example for 4 byte utf8: 0xF0 0x9F 0x8C 0x8E; utf16: 0xD83C 0xDF0E.
|
|
||||||
// 🌙 - example for escapes: utf8: 0xF0 0x9F 0x8C 0x99; utf16: 0xD83C 0xDF19.
|
|
||||||
|
|
||||||
// We provide the moon with json escape, but the earth as utf8 input.
|
|
||||||
// Either way they arrive as utf8 (after decoding in log_.str()).
|
|
||||||
std::string json =
|
|
||||||
"{"
|
|
||||||
"\"escapes\": \"\\uD83C\\uDF19\","
|
|
||||||
"\"2 byte\":\"гласность\","
|
|
||||||
"\"3 byte\":\"屋\","
|
|
||||||
"\"4 byte\":\"🌎\""
|
|
||||||
"}";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_TRUE(log_.status().ok());
|
|
||||||
EXPECT_EQ(
|
|
||||||
"map begin\n"
|
|
||||||
"string16: escapes\n"
|
|
||||||
"string16: 🌙\n"
|
|
||||||
"string16: 2 byte\n"
|
|
||||||
"string16: гласность\n"
|
|
||||||
"string16: 3 byte\n"
|
|
||||||
"string16: 屋\n"
|
|
||||||
"string16: 4 byte\n"
|
|
||||||
"string16: 🌎\n"
|
|
||||||
"map end\n",
|
|
||||||
log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, UnprocessedInputRemainsError) {
|
|
||||||
// Trailing junk after the valid JSON.
|
|
||||||
std::string json = "{\"foo\": 3.1415} junk";
|
|
||||||
size_t junk_idx = json.find("junk");
|
|
||||||
EXPECT_NE(junk_idx, std::string::npos);
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_EQ(Error::JSON_PARSER_UNPROCESSED_INPUT_REMAINS, log_.status().error);
|
|
||||||
EXPECT_EQ(junk_idx, log_.status().pos);
|
|
||||||
EXPECT_EQ("", log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string MakeNestedJson(int depth) {
|
|
||||||
std::string json;
|
|
||||||
for (int ii = 0; ii < depth; ++ii)
|
|
||||||
json += "{\"foo\":";
|
|
||||||
json += "42";
|
|
||||||
for (int ii = 0; ii < depth; ++ii)
|
|
||||||
json += "}";
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, StackLimitExceededError_BelowLimit) {
|
|
||||||
// kStackLimit is 300 (see json_parser.cc). First let's
|
|
||||||
// try with a small nested example.
|
|
||||||
std::string json_3 = MakeNestedJson(3);
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json_3), &log_);
|
|
||||||
EXPECT_TRUE(log_.status().ok());
|
|
||||||
EXPECT_EQ(
|
|
||||||
"map begin\n"
|
|
||||||
"string16: foo\n"
|
|
||||||
"map begin\n"
|
|
||||||
"string16: foo\n"
|
|
||||||
"map begin\n"
|
|
||||||
"string16: foo\n"
|
|
||||||
"int: 42\n"
|
|
||||||
"map end\n"
|
|
||||||
"map end\n"
|
|
||||||
"map end\n",
|
|
||||||
log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, StackLimitExceededError_AtLimit) {
|
|
||||||
// Now with kStackLimit (300).
|
|
||||||
std::string json_limit = MakeNestedJson(300);
|
|
||||||
ParseJSON(GetTestPlatform(),
|
|
||||||
span<uint8_t>(reinterpret_cast<const uint8_t*>(json_limit.data()),
|
|
||||||
json_limit.size()),
|
|
||||||
&log_);
|
|
||||||
EXPECT_TRUE(log_.status().ok());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, StackLimitExceededError_AboveLimit) {
|
|
||||||
// Now with kStackLimit + 1 (301) - it exceeds in the innermost instance.
|
|
||||||
std::string exceeded = MakeNestedJson(301);
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(exceeded), &log_);
|
|
||||||
EXPECT_EQ(Error::JSON_PARSER_STACK_LIMIT_EXCEEDED, log_.status().error);
|
|
||||||
EXPECT_EQ(strlen("{\"foo\":") * 301, log_.status().pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, StackLimitExceededError_WayAboveLimit) {
|
|
||||||
// Now way past the limit. Still, the point of exceeding is 301.
|
|
||||||
std::string far_out = MakeNestedJson(320);
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(far_out), &log_);
|
|
||||||
EXPECT_EQ(Error::JSON_PARSER_STACK_LIMIT_EXCEEDED, log_.status().error);
|
|
||||||
EXPECT_EQ(strlen("{\"foo\":") * 301, log_.status().pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, NoInputError) {
|
|
||||||
std::string json = "";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_EQ(Error::JSON_PARSER_NO_INPUT, log_.status().error);
|
|
||||||
EXPECT_EQ(0u, log_.status().pos);
|
|
||||||
EXPECT_EQ("", log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, InvalidTokenError) {
|
|
||||||
std::string json = "|";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_EQ(Error::JSON_PARSER_INVALID_TOKEN, log_.status().error);
|
|
||||||
EXPECT_EQ(0u, log_.status().pos);
|
|
||||||
EXPECT_EQ("", log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, InvalidNumberError) {
|
|
||||||
// Mantissa exceeds max (the constant used here is int64_t max).
|
|
||||||
std::string json = "1E9223372036854775807";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_EQ(Error::JSON_PARSER_INVALID_NUMBER, log_.status().error);
|
|
||||||
EXPECT_EQ(0u, log_.status().pos);
|
|
||||||
EXPECT_EQ("", log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, InvalidStringError) {
|
|
||||||
// \x22 is an unsupported escape sequence
|
|
||||||
std::string json = "\"foo\\x22\"";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_EQ(Error::JSON_PARSER_INVALID_STRING, log_.status().error);
|
|
||||||
EXPECT_EQ(0u, log_.status().pos);
|
|
||||||
EXPECT_EQ("", log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, UnexpectedArrayEndError) {
|
|
||||||
std::string json = "[1,2,]";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_EQ(Error::JSON_PARSER_UNEXPECTED_ARRAY_END, log_.status().error);
|
|
||||||
EXPECT_EQ(5u, log_.status().pos);
|
|
||||||
EXPECT_EQ("", log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, CommaOrArrayEndExpectedError) {
|
|
||||||
std::string json = "[1,2 2";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_EQ(Error::JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED,
|
|
||||||
log_.status().error);
|
|
||||||
EXPECT_EQ(5u, log_.status().pos);
|
|
||||||
EXPECT_EQ("", log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, StringLiteralExpectedError) {
|
|
||||||
// There's an error because the key bar, a string, is not terminated.
|
|
||||||
std::string json = "{\"foo\": 3.1415, \"bar: 31415e-4}";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_EQ(Error::JSON_PARSER_STRING_LITERAL_EXPECTED, log_.status().error);
|
|
||||||
EXPECT_EQ(16u, log_.status().pos);
|
|
||||||
EXPECT_EQ("", log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, ColonExpectedError) {
|
|
||||||
std::string json = "{\"foo\", 42}";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_EQ(Error::JSON_PARSER_COLON_EXPECTED, log_.status().error);
|
|
||||||
EXPECT_EQ(6u, log_.status().pos);
|
|
||||||
EXPECT_EQ("", log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, UnexpectedMapEndError) {
|
|
||||||
std::string json = "{\"foo\": 42, }";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_EQ(Error::JSON_PARSER_UNEXPECTED_MAP_END, log_.status().error);
|
|
||||||
EXPECT_EQ(12u, log_.status().pos);
|
|
||||||
EXPECT_EQ("", log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, CommaOrMapEndExpectedError) {
|
|
||||||
// The second separator should be a comma.
|
|
||||||
std::string json = "{\"foo\": 3.1415: \"bar\": 0}";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_EQ(Error::JSON_PARSER_COMMA_OR_MAP_END_EXPECTED, log_.status().error);
|
|
||||||
EXPECT_EQ(14u, log_.status().pos);
|
|
||||||
EXPECT_EQ("", log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(JsonParserTest, ValueExpectedError) {
|
|
||||||
std::string json = "}";
|
|
||||||
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
|
||||||
EXPECT_EQ(Error::JSON_PARSER_VALUE_EXPECTED, log_.status().error);
|
|
||||||
EXPECT_EQ(0u, log_.status().pos);
|
|
||||||
EXPECT_EQ("", log_.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class ConvertJSONToCBORTest : public ::testing::Test {};
|
|
||||||
|
|
||||||
using ContainerTestTypes = ::testing::Types<std::vector<uint8_t>, std::string>;
|
|
||||||
TYPED_TEST_SUITE(ConvertJSONToCBORTest, ContainerTestTypes);
|
|
||||||
|
|
||||||
TYPED_TEST(ConvertJSONToCBORTest, RoundTripValidJson) {
|
|
||||||
std::string json_in = "{\"msg\":\"Hello, world.\",\"lst\":[1,2,3]}";
|
|
||||||
TypeParam json(json_in.begin(), json_in.end());
|
|
||||||
TypeParam cbor;
|
|
||||||
{
|
|
||||||
Status status = ConvertJSONToCBOR(GetTestPlatform(), SpanFrom(json), &cbor);
|
|
||||||
EXPECT_EQ(Error::OK, status.error);
|
|
||||||
EXPECT_EQ(Status::npos(), status.pos);
|
|
||||||
}
|
|
||||||
TypeParam roundtrip_json;
|
|
||||||
{
|
|
||||||
Status status =
|
|
||||||
ConvertCBORToJSON(GetTestPlatform(), SpanFrom(cbor), &roundtrip_json);
|
|
||||||
EXPECT_EQ(Error::OK, status.error);
|
|
||||||
EXPECT_EQ(Status::npos(), status.pos);
|
|
||||||
}
|
|
||||||
EXPECT_EQ(json, roundtrip_json);
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(ConvertJSONToCBORTest, RoundTripValidJson16) {
|
|
||||||
std::vector<uint16_t> json16 = {
|
|
||||||
'{', '"', 'm', 's', 'g', '"', ':', '"', 'H', 'e', 'l', 'l',
|
|
||||||
'o', ',', ' ', 0xd83c, 0xdf0e, '.', '"', ',', '"', 'l', 's', 't',
|
|
||||||
'"', ':', '[', '1', ',', '2', ',', '3', ']', '}'};
|
|
||||||
TypeParam cbor;
|
|
||||||
{
|
|
||||||
Status status = ConvertJSONToCBOR(
|
|
||||||
GetTestPlatform(), span<uint16_t>(json16.data(), json16.size()), &cbor);
|
|
||||||
EXPECT_EQ(Error::OK, status.error);
|
|
||||||
EXPECT_EQ(Status::npos(), status.pos);
|
|
||||||
}
|
|
||||||
TypeParam roundtrip_json;
|
|
||||||
{
|
|
||||||
Status status =
|
|
||||||
ConvertCBORToJSON(GetTestPlatform(), SpanFrom(cbor), &roundtrip_json);
|
|
||||||
EXPECT_EQ(Error::OK, status.error);
|
|
||||||
EXPECT_EQ(Status::npos(), status.pos);
|
|
||||||
}
|
|
||||||
std::string json = "{\"msg\":\"Hello, \\ud83c\\udf0e.\",\"lst\":[1,2,3]}";
|
|
||||||
TypeParam expected_json(json.begin(), json.end());
|
|
||||||
EXPECT_EQ(expected_json, roundtrip_json);
|
|
||||||
}
|
|
||||||
} // namespace json
|
|
||||||
} // namespace v8_inspector_protocol_encoding
|
|
@ -2,4 +2,6 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
#include "bindings.h"
|
// This file is V8 specific.
|
||||||
|
// It is not rolled from the upstream project.
|
||||||
|
// CRDTP doesn't export symbols from V8, so it's empty.
|
@ -2,13 +2,13 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
#ifndef V8_INSPECTOR_PROTOCOL_BINDINGS_BINDINGS_H_
|
#ifndef V8_CRDTP_GLUE_H_
|
||||||
#define V8_INSPECTOR_PROTOCOL_BINDINGS_BINDINGS_H_
|
#define V8_CRDTP_GLUE_H_
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace v8_inspector_protocol_bindings {
|
namespace v8_crdtp {
|
||||||
namespace glue {
|
namespace glue {
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// glue::detail::PtrMaybe, glue::detail::ValueMaybe, templates for optional
|
// glue::detail::PtrMaybe, glue::detail::ValueMaybe, templates for optional
|
||||||
@ -70,11 +70,11 @@ class ValueMaybe {
|
|||||||
};
|
};
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace glue
|
} // namespace glue
|
||||||
} // namespace v8_inspector_protocol_bindings
|
} // namespace v8_crdtp
|
||||||
|
|
||||||
#define PROTOCOL_DISALLOW_COPY(ClassName) \
|
#define PROTOCOL_DISALLOW_COPY(ClassName) \
|
||||||
private: \
|
private: \
|
||||||
ClassName(const ClassName&) = delete; \
|
ClassName(const ClassName&) = delete; \
|
||||||
ClassName& operator=(const ClassName&) = delete
|
ClassName& operator=(const ClassName&) = delete
|
||||||
|
|
||||||
#endif // V8_INSPECTOR_PROTOCOL_BINDINGS_BINDINGS_H_
|
#endif // V8_CRDTP_GLUE_H_
|
@ -2,14 +2,14 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
#include "bindings.h"
|
#include "glue.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "bindings_test_helper.h"
|
#include "test_platform.h"
|
||||||
|
|
||||||
namespace v8_inspector_protocol_bindings {
|
namespace v8_crdtp {
|
||||||
namespace glue {
|
namespace glue {
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// glue::detail::PtrMaybe, glue::detail::ValueMaybe, templates for optional
|
// glue::detail::PtrMaybe, glue::detail::ValueMaybe, templates for optional
|
||||||
@ -41,4 +41,4 @@ TEST(PtrValueTest, SmokeTest) {
|
|||||||
EXPECT_EQ(out, 42);
|
EXPECT_EQ(out, 42);
|
||||||
}
|
}
|
||||||
} // namespace glue
|
} // namespace glue
|
||||||
} // namespace v8_inspector_protocol_bindings
|
} // namespace v8_crdtp
|
1048
third_party/inspector_protocol/crdtp/json.cc
vendored
Normal file
1048
third_party/inspector_protocol/crdtp/json.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
76
third_party/inspector_protocol/crdtp/json.h
vendored
Normal file
76
third_party/inspector_protocol/crdtp/json.h
vendored
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef V8_CRDTP_JSON_H_
|
||||||
|
#define V8_CRDTP_JSON_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <limits>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "export.h"
|
||||||
|
#include "json_platform.h"
|
||||||
|
#include "parser_handler.h"
|
||||||
|
|
||||||
|
namespace v8_crdtp {
|
||||||
|
namespace json {
|
||||||
|
// =============================================================================
|
||||||
|
// json::NewJSONEncoder - for encoding streaming parser events as JSON
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// Returns a handler object which will write ascii characters to |out|.
|
||||||
|
// |status->ok()| will be false iff the handler routine HandleError() is called.
|
||||||
|
// In that case, we'll stop emitting output.
|
||||||
|
// Except for calling the HandleError routine at any time, the client
|
||||||
|
// code must call the Handle* methods in an order in which they'd occur
|
||||||
|
// in valid JSON; otherwise we may crash (the code uses assert).
|
||||||
|
std::unique_ptr<StreamingParserHandler> NewJSONEncoder(
|
||||||
|
const Platform* platform,
|
||||||
|
std::vector<uint8_t>* out,
|
||||||
|
Status* status);
|
||||||
|
std::unique_ptr<StreamingParserHandler> NewJSONEncoder(const Platform* platform,
|
||||||
|
std::string* out,
|
||||||
|
Status* status);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// json::ParseJSON - for receiving streaming parser events for JSON
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
void ParseJSON(const Platform& platform,
|
||||||
|
span<uint8_t> chars,
|
||||||
|
StreamingParserHandler* handler);
|
||||||
|
void ParseJSON(const Platform& platform,
|
||||||
|
span<uint16_t> chars,
|
||||||
|
StreamingParserHandler* handler);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// json::ConvertCBORToJSON, json::ConvertJSONToCBOR - for transcoding
|
||||||
|
// =============================================================================
|
||||||
|
Status ConvertCBORToJSON(const Platform& platform,
|
||||||
|
span<uint8_t> cbor,
|
||||||
|
std::string* json);
|
||||||
|
Status ConvertCBORToJSON(const Platform& platform,
|
||||||
|
span<uint8_t> cbor,
|
||||||
|
std::vector<uint8_t>* json);
|
||||||
|
Status ConvertJSONToCBOR(const Platform& platform,
|
||||||
|
span<uint8_t> json,
|
||||||
|
std::vector<uint8_t>* cbor);
|
||||||
|
Status ConvertJSONToCBOR(const Platform& platform,
|
||||||
|
span<uint16_t> json,
|
||||||
|
std::vector<uint8_t>* cbor);
|
||||||
|
Status ConvertJSONToCBOR(const Platform& platform,
|
||||||
|
span<uint8_t> json,
|
||||||
|
std::string* cbor);
|
||||||
|
Status ConvertJSONToCBOR(const Platform& platform,
|
||||||
|
span<uint16_t> json,
|
||||||
|
std::string* cbor);
|
||||||
|
} // namespace json
|
||||||
|
} // namespace v8_crdtp
|
||||||
|
|
||||||
|
#endif // V8_CRDTP_JSON_H_
|
36
third_party/inspector_protocol/crdtp/json_platform.h
vendored
Normal file
36
third_party/inspector_protocol/crdtp/json_platform.h
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef V8_CRDTP_JSON_PLATFORM_H_
|
||||||
|
#define V8_CRDTP_JSON_PLATFORM_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <limits>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "export.h"
|
||||||
|
|
||||||
|
namespace v8_crdtp {
|
||||||
|
namespace json {
|
||||||
|
// Client code must provide an instance. Implementation should delegate
|
||||||
|
// to whatever is appropriate.
|
||||||
|
class Platform {
|
||||||
|
public:
|
||||||
|
virtual ~Platform() = default;
|
||||||
|
// Parses |str| into |result|. Returns false iff there are
|
||||||
|
// leftover characters or parsing errors.
|
||||||
|
virtual bool StrToD(const char* str, double* result) const = 0;
|
||||||
|
|
||||||
|
// Prints |value| in a format suitable for JSON.
|
||||||
|
virtual std::unique_ptr<char[]> DToStr(double value) const = 0;
|
||||||
|
};
|
||||||
|
} // namespace json
|
||||||
|
} // namespace v8_crdtp
|
||||||
|
|
||||||
|
#endif // V8_CRDTP_JSON_PLATFORM_H_
|
676
third_party/inspector_protocol/crdtp/json_test.cc
vendored
Normal file
676
third_party/inspector_protocol/crdtp/json_test.cc
vendored
Normal file
@ -0,0 +1,676 @@
|
|||||||
|
// Copyright 2018 The Chromium 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 "json.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <clocale>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "test_platform.h"
|
||||||
|
|
||||||
|
using testing::ElementsAreArray;
|
||||||
|
|
||||||
|
namespace v8_crdtp {
|
||||||
|
namespace {
|
||||||
|
class TestPlatform : public json::Platform {
|
||||||
|
bool StrToD(const char* str, double* result) const override {
|
||||||
|
// This is not thread-safe
|
||||||
|
// (see https://en.cppreference.com/w/cpp/locale/setlocale)
|
||||||
|
// but good enough for a unittest.
|
||||||
|
const char* saved_locale = std::setlocale(LC_NUMERIC, nullptr);
|
||||||
|
char* end;
|
||||||
|
*result = std::strtod(str, &end);
|
||||||
|
std::setlocale(LC_NUMERIC, saved_locale);
|
||||||
|
if (errno == ERANGE) {
|
||||||
|
// errno must be reset, e.g. see the example here:
|
||||||
|
// https://en.cppreference.com/w/cpp/string/byte/strtof
|
||||||
|
errno = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return end == str + strlen(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<char[]> DToStr(double value) const override {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss.imbue(std::locale("C"));
|
||||||
|
ss << value;
|
||||||
|
std::string str = ss.str();
|
||||||
|
std::unique_ptr<char[]> result(new char[str.size() + 1]);
|
||||||
|
memcpy(result.get(), str.c_str(), str.size() + 1);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const json::Platform& GetTestPlatform() {
|
||||||
|
static TestPlatform* platform = new TestPlatform;
|
||||||
|
return *platform;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace json {
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// json::NewJSONEncoder - for encoding streaming parser events as JSON
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
void WriteUTF8AsUTF16(StreamingParserHandler* writer, const std::string& utf8) {
|
||||||
|
writer->HandleString16(SpanFrom(UTF8ToUTF16(SpanFrom(utf8))));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(JsonEncoder, OverlongEncodings) {
|
||||||
|
std::string out;
|
||||||
|
Status status;
|
||||||
|
std::unique_ptr<StreamingParserHandler> writer =
|
||||||
|
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
||||||
|
|
||||||
|
// We encode 0x7f, which is the DEL ascii character, as a 4 byte UTF8
|
||||||
|
// sequence. This is called an overlong encoding, because only 1 byte
|
||||||
|
// is needed to represent 0x7f as UTF8.
|
||||||
|
std::vector<uint8_t> chars = {
|
||||||
|
0xf0, // Starts 4 byte utf8 sequence
|
||||||
|
0x80, // continuation byte
|
||||||
|
0x81, // continuation byte w/ payload bit 7 set to 1.
|
||||||
|
0xbf, // continuation byte w/ payload bits 0-6 set to 11111.
|
||||||
|
};
|
||||||
|
writer->HandleString8(SpanFrom(chars));
|
||||||
|
EXPECT_EQ("\"\"", out); // Empty string means that 0x7f was rejected (good).
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(JsonEncoder, IncompleteUtf8Sequence) {
|
||||||
|
std::string out;
|
||||||
|
Status status;
|
||||||
|
std::unique_ptr<StreamingParserHandler> writer =
|
||||||
|
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
||||||
|
|
||||||
|
writer->HandleArrayBegin(); // This emits [, which starts an array.
|
||||||
|
|
||||||
|
{ // 🌎 takes four bytes to encode in UTF-8. We test with the first three;
|
||||||
|
// This means we're trying to emit a string that consists solely of an
|
||||||
|
// incomplete UTF-8 sequence. So the string in the JSON output is empty.
|
||||||
|
std::string world_utf8 = "🌎";
|
||||||
|
ASSERT_EQ(4u, world_utf8.size());
|
||||||
|
std::vector<uint8_t> chars(world_utf8.begin(), world_utf8.begin() + 3);
|
||||||
|
writer->HandleString8(SpanFrom(chars));
|
||||||
|
EXPECT_EQ("[\"\"", out); // Incomplete sequence rejected: empty string.
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // This time, the incomplete sequence is at the end of the string.
|
||||||
|
std::string msg = "Hello, \xF0\x9F\x8C";
|
||||||
|
std::vector<uint8_t> chars(msg.begin(), msg.end());
|
||||||
|
writer->HandleString8(SpanFrom(chars));
|
||||||
|
EXPECT_EQ("[\"\",\"Hello, \"", out); // Incomplete sequence dropped at end.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(JsonStdStringWriterTest, HelloWorld) {
|
||||||
|
std::string out;
|
||||||
|
Status status;
|
||||||
|
std::unique_ptr<StreamingParserHandler> writer =
|
||||||
|
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
||||||
|
writer->HandleMapBegin();
|
||||||
|
WriteUTF8AsUTF16(writer.get(), "msg1");
|
||||||
|
WriteUTF8AsUTF16(writer.get(), "Hello, 🌎.");
|
||||||
|
std::string key = "msg1-as-utf8";
|
||||||
|
std::string value = "Hello, 🌎.";
|
||||||
|
writer->HandleString8(SpanFrom(key));
|
||||||
|
writer->HandleString8(SpanFrom(value));
|
||||||
|
WriteUTF8AsUTF16(writer.get(), "msg2");
|
||||||
|
WriteUTF8AsUTF16(writer.get(), "\\\b\r\n\t\f\"");
|
||||||
|
WriteUTF8AsUTF16(writer.get(), "nested");
|
||||||
|
writer->HandleMapBegin();
|
||||||
|
WriteUTF8AsUTF16(writer.get(), "double");
|
||||||
|
writer->HandleDouble(3.1415);
|
||||||
|
WriteUTF8AsUTF16(writer.get(), "int");
|
||||||
|
writer->HandleInt32(-42);
|
||||||
|
WriteUTF8AsUTF16(writer.get(), "bool");
|
||||||
|
writer->HandleBool(false);
|
||||||
|
WriteUTF8AsUTF16(writer.get(), "null");
|
||||||
|
writer->HandleNull();
|
||||||
|
writer->HandleMapEnd();
|
||||||
|
WriteUTF8AsUTF16(writer.get(), "array");
|
||||||
|
writer->HandleArrayBegin();
|
||||||
|
writer->HandleInt32(1);
|
||||||
|
writer->HandleInt32(2);
|
||||||
|
writer->HandleInt32(3);
|
||||||
|
writer->HandleArrayEnd();
|
||||||
|
writer->HandleMapEnd();
|
||||||
|
EXPECT_TRUE(status.ok());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"{\"msg1\":\"Hello, \\ud83c\\udf0e.\","
|
||||||
|
"\"msg1-as-utf8\":\"Hello, \\ud83c\\udf0e.\","
|
||||||
|
"\"msg2\":\"\\\\\\b\\r\\n\\t\\f\\\"\","
|
||||||
|
"\"nested\":{\"double\":3.1415,\"int\":-42,"
|
||||||
|
"\"bool\":false,\"null\":null},\"array\":[1,2,3]}",
|
||||||
|
out);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(JsonStdStringWriterTest, RepresentingNonFiniteValuesAsNull) {
|
||||||
|
// JSON can't represent +Infinity, -Infinity, or NaN.
|
||||||
|
// So in practice it's mapped to null.
|
||||||
|
std::string out;
|
||||||
|
Status status;
|
||||||
|
std::unique_ptr<StreamingParserHandler> writer =
|
||||||
|
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
||||||
|
writer->HandleMapBegin();
|
||||||
|
writer->HandleString8(SpanFrom("Infinity"));
|
||||||
|
writer->HandleDouble(std::numeric_limits<double>::infinity());
|
||||||
|
writer->HandleString8(SpanFrom("-Infinity"));
|
||||||
|
writer->HandleDouble(-std::numeric_limits<double>::infinity());
|
||||||
|
writer->HandleString8(SpanFrom("NaN"));
|
||||||
|
writer->HandleDouble(std::numeric_limits<double>::quiet_NaN());
|
||||||
|
writer->HandleMapEnd();
|
||||||
|
EXPECT_TRUE(status.ok());
|
||||||
|
EXPECT_EQ("{\"Infinity\":null,\"-Infinity\":null,\"NaN\":null}", out);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(JsonStdStringWriterTest, BinaryEncodedAsJsonString) {
|
||||||
|
// The encoder emits binary submitted to StreamingParserHandler::HandleBinary
|
||||||
|
// as base64. The following three examples are taken from
|
||||||
|
// https://en.wikipedia.org/wiki/Base64.
|
||||||
|
{
|
||||||
|
std::string out;
|
||||||
|
Status status;
|
||||||
|
std::unique_ptr<StreamingParserHandler> writer =
|
||||||
|
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
||||||
|
writer->HandleBinary(SpanFrom(std::vector<uint8_t>({'M', 'a', 'n'})));
|
||||||
|
EXPECT_TRUE(status.ok());
|
||||||
|
EXPECT_EQ("\"TWFu\"", out);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::string out;
|
||||||
|
Status status;
|
||||||
|
std::unique_ptr<StreamingParserHandler> writer =
|
||||||
|
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
||||||
|
writer->HandleBinary(SpanFrom(std::vector<uint8_t>({'M', 'a'})));
|
||||||
|
EXPECT_TRUE(status.ok());
|
||||||
|
EXPECT_EQ("\"TWE=\"", out);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::string out;
|
||||||
|
Status status;
|
||||||
|
std::unique_ptr<StreamingParserHandler> writer =
|
||||||
|
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
||||||
|
writer->HandleBinary(SpanFrom(std::vector<uint8_t>({'M'})));
|
||||||
|
EXPECT_TRUE(status.ok());
|
||||||
|
EXPECT_EQ("\"TQ==\"", out);
|
||||||
|
}
|
||||||
|
{ // "Hello, world.", verified with base64decode.org.
|
||||||
|
std::string out;
|
||||||
|
Status status;
|
||||||
|
std::unique_ptr<StreamingParserHandler> writer =
|
||||||
|
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
||||||
|
writer->HandleBinary(SpanFrom(std::vector<uint8_t>(
|
||||||
|
{'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.'})));
|
||||||
|
EXPECT_TRUE(status.ok());
|
||||||
|
EXPECT_EQ("\"SGVsbG8sIHdvcmxkLg==\"", out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(JsonStdStringWriterTest, HandlesErrors) {
|
||||||
|
// When an error is sent via HandleError, it saves it in the provided
|
||||||
|
// status and clears the output.
|
||||||
|
std::string out;
|
||||||
|
Status status;
|
||||||
|
std::unique_ptr<StreamingParserHandler> writer =
|
||||||
|
NewJSONEncoder(&GetTestPlatform(), &out, &status);
|
||||||
|
writer->HandleMapBegin();
|
||||||
|
WriteUTF8AsUTF16(writer.get(), "msg1");
|
||||||
|
writer->HandleError(Status{Error::JSON_PARSER_VALUE_EXPECTED, 42});
|
||||||
|
EXPECT_EQ(Error::JSON_PARSER_VALUE_EXPECTED, status.error);
|
||||||
|
EXPECT_EQ(42u, status.pos);
|
||||||
|
EXPECT_EQ("", out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We'd use Gmock but unfortunately it only handles copyable return types.
|
||||||
|
class MockPlatform : public Platform {
|
||||||
|
public:
|
||||||
|
// Not implemented.
|
||||||
|
bool StrToD(const char* str, double* result) const override { return false; }
|
||||||
|
|
||||||
|
// A map with pre-registered responses for DToSTr.
|
||||||
|
std::map<double, std::string> dtostr_responses_;
|
||||||
|
|
||||||
|
std::unique_ptr<char[]> DToStr(double value) const override {
|
||||||
|
auto it = dtostr_responses_.find(value);
|
||||||
|
CHECK(it != dtostr_responses_.end());
|
||||||
|
const std::string& str = it->second;
|
||||||
|
std::unique_ptr<char[]> response(new char[str.size() + 1]);
|
||||||
|
memcpy(response.get(), str.c_str(), str.size() + 1);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(JsonStdStringWriterTest, DoubleToString) {
|
||||||
|
// This "broken" platform responds without the leading 0 before the
|
||||||
|
// decimal dot, so it'd be invalid JSON.
|
||||||
|
MockPlatform platform;
|
||||||
|
platform.dtostr_responses_[.1] = ".1";
|
||||||
|
platform.dtostr_responses_[-.7] = "-.7";
|
||||||
|
|
||||||
|
std::string out;
|
||||||
|
Status status;
|
||||||
|
std::unique_ptr<StreamingParserHandler> writer =
|
||||||
|
NewJSONEncoder(&platform, &out, &status);
|
||||||
|
writer->HandleArrayBegin();
|
||||||
|
writer->HandleDouble(.1);
|
||||||
|
writer->HandleDouble(-.7);
|
||||||
|
writer->HandleArrayEnd();
|
||||||
|
EXPECT_EQ("[0.1,-0.7]", out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// json::ParseJSON - for receiving streaming parser events for JSON
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
class Log : public StreamingParserHandler {
|
||||||
|
public:
|
||||||
|
void HandleMapBegin() override { log_ << "map begin\n"; }
|
||||||
|
|
||||||
|
void HandleMapEnd() override { log_ << "map end\n"; }
|
||||||
|
|
||||||
|
void HandleArrayBegin() override { log_ << "array begin\n"; }
|
||||||
|
|
||||||
|
void HandleArrayEnd() override { log_ << "array end\n"; }
|
||||||
|
|
||||||
|
void HandleString8(span<uint8_t> chars) override {
|
||||||
|
log_ << "string8: " << std::string(chars.begin(), chars.end()) << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleString16(span<uint16_t> chars) override {
|
||||||
|
log_ << "string16: " << UTF16ToUTF8(chars) << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleBinary(span<uint8_t> bytes) override {
|
||||||
|
// JSON doesn't have native support for arbitrary bytes, so our parser will
|
||||||
|
// never call this.
|
||||||
|
CHECK(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleDouble(double value) override {
|
||||||
|
log_ << "double: " << value << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleInt32(int32_t value) override { log_ << "int: " << value << "\n"; }
|
||||||
|
|
||||||
|
void HandleBool(bool value) override { log_ << "bool: " << value << "\n"; }
|
||||||
|
|
||||||
|
void HandleNull() override { log_ << "null\n"; }
|
||||||
|
|
||||||
|
void HandleError(Status status) override { status_ = status; }
|
||||||
|
|
||||||
|
std::string str() const { return status_.ok() ? log_.str() : ""; }
|
||||||
|
|
||||||
|
Status status() const { return status_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::ostringstream log_;
|
||||||
|
Status status_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class JsonParserTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
Log log_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, SimpleDictionary) {
|
||||||
|
std::string json = "{\"foo\": 42}";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_TRUE(log_.status().ok());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"map begin\n"
|
||||||
|
"string16: foo\n"
|
||||||
|
"int: 42\n"
|
||||||
|
"map end\n",
|
||||||
|
log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, UsAsciiDelCornerCase) {
|
||||||
|
// DEL (0x7f) is a 7 bit US-ASCII character, and while it is a control
|
||||||
|
// character according to Unicode, it's not considered a control
|
||||||
|
// character in https://tools.ietf.org/html/rfc7159#section-7, so
|
||||||
|
// it can be placed directly into the JSON string, without JSON escaping.
|
||||||
|
std::string json = "{\"foo\": \"a\x7f\"}";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_TRUE(log_.status().ok());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"map begin\n"
|
||||||
|
"string16: foo\n"
|
||||||
|
"string16: a\x7f\n"
|
||||||
|
"map end\n",
|
||||||
|
log_.str());
|
||||||
|
|
||||||
|
// We've seen an implementation of UTF16ToUTF8 which would replace the DEL
|
||||||
|
// character with ' ', so this simple roundtrip tests the routines in
|
||||||
|
// encoding_test_helper.h, to make test failures of the above easier to
|
||||||
|
// diagnose.
|
||||||
|
std::vector<uint16_t> utf16 = UTF8ToUTF16(SpanFrom(json));
|
||||||
|
EXPECT_EQ(json, UTF16ToUTF8(SpanFrom(utf16)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, Whitespace) {
|
||||||
|
std::string json = "\n {\n\"msg\"\n: \v\"Hello, world.\"\t\r}\t";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_TRUE(log_.status().ok());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"map begin\n"
|
||||||
|
"string16: msg\n"
|
||||||
|
"string16: Hello, world.\n"
|
||||||
|
"map end\n",
|
||||||
|
log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, NestedDictionary) {
|
||||||
|
std::string json = "{\"foo\": {\"bar\": {\"baz\": 1}, \"bar2\": 2}}";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_TRUE(log_.status().ok());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"map begin\n"
|
||||||
|
"string16: foo\n"
|
||||||
|
"map begin\n"
|
||||||
|
"string16: bar\n"
|
||||||
|
"map begin\n"
|
||||||
|
"string16: baz\n"
|
||||||
|
"int: 1\n"
|
||||||
|
"map end\n"
|
||||||
|
"string16: bar2\n"
|
||||||
|
"int: 2\n"
|
||||||
|
"map end\n"
|
||||||
|
"map end\n",
|
||||||
|
log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, Doubles) {
|
||||||
|
std::string json = "{\"foo\": 3.1415, \"bar\": 31415e-4}";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_TRUE(log_.status().ok());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"map begin\n"
|
||||||
|
"string16: foo\n"
|
||||||
|
"double: 3.1415\n"
|
||||||
|
"string16: bar\n"
|
||||||
|
"double: 3.1415\n"
|
||||||
|
"map end\n",
|
||||||
|
log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, Unicode) {
|
||||||
|
// Globe character. 0xF0 0x9F 0x8C 0x8E in utf8, 0xD83C 0xDF0E in utf16.
|
||||||
|
std::string json = "{\"msg\": \"Hello, \\uD83C\\uDF0E.\"}";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_TRUE(log_.status().ok());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"map begin\n"
|
||||||
|
"string16: msg\n"
|
||||||
|
"string16: Hello, 🌎.\n"
|
||||||
|
"map end\n",
|
||||||
|
log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, Unicode_ParseUtf16) {
|
||||||
|
// Globe character. utf8: 0xF0 0x9F 0x8C 0x8E; utf16: 0xD83C 0xDF0E.
|
||||||
|
// Crescent moon character. utf8: 0xF0 0x9F 0x8C 0x99; utf16: 0xD83C 0xDF19.
|
||||||
|
|
||||||
|
// We provide the moon with json escape, but the earth as utf16 input.
|
||||||
|
// Either way they arrive as utf8 (after decoding in log_.str()).
|
||||||
|
std::vector<uint16_t> json =
|
||||||
|
UTF8ToUTF16(SpanFrom("{\"space\": \"🌎 \\uD83C\\uDF19.\"}"));
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_TRUE(log_.status().ok());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"map begin\n"
|
||||||
|
"string16: space\n"
|
||||||
|
"string16: 🌎 🌙.\n"
|
||||||
|
"map end\n",
|
||||||
|
log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, Unicode_ParseUtf8) {
|
||||||
|
// Used below:
|
||||||
|
// гласность - example for 2 byte utf8, Russian word "glasnost"
|
||||||
|
// 屋 - example for 3 byte utf8, Chinese word for "house"
|
||||||
|
// 🌎 - example for 4 byte utf8: 0xF0 0x9F 0x8C 0x8E; utf16: 0xD83C 0xDF0E.
|
||||||
|
// 🌙 - example for escapes: utf8: 0xF0 0x9F 0x8C 0x99; utf16: 0xD83C 0xDF19.
|
||||||
|
|
||||||
|
// We provide the moon with json escape, but the earth as utf8 input.
|
||||||
|
// Either way they arrive as utf8 (after decoding in log_.str()).
|
||||||
|
std::string json =
|
||||||
|
"{"
|
||||||
|
"\"escapes\": \"\\uD83C\\uDF19\","
|
||||||
|
"\"2 byte\":\"гласность\","
|
||||||
|
"\"3 byte\":\"屋\","
|
||||||
|
"\"4 byte\":\"🌎\""
|
||||||
|
"}";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_TRUE(log_.status().ok());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"map begin\n"
|
||||||
|
"string16: escapes\n"
|
||||||
|
"string16: 🌙\n"
|
||||||
|
"string16: 2 byte\n"
|
||||||
|
"string16: гласность\n"
|
||||||
|
"string16: 3 byte\n"
|
||||||
|
"string16: 屋\n"
|
||||||
|
"string16: 4 byte\n"
|
||||||
|
"string16: 🌎\n"
|
||||||
|
"map end\n",
|
||||||
|
log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, UnprocessedInputRemainsError) {
|
||||||
|
// Trailing junk after the valid JSON.
|
||||||
|
std::string json = "{\"foo\": 3.1415} junk";
|
||||||
|
size_t junk_idx = json.find("junk");
|
||||||
|
EXPECT_NE(junk_idx, std::string::npos);
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_EQ(Error::JSON_PARSER_UNPROCESSED_INPUT_REMAINS, log_.status().error);
|
||||||
|
EXPECT_EQ(junk_idx, log_.status().pos);
|
||||||
|
EXPECT_EQ("", log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MakeNestedJson(int depth) {
|
||||||
|
std::string json;
|
||||||
|
for (int ii = 0; ii < depth; ++ii)
|
||||||
|
json += "{\"foo\":";
|
||||||
|
json += "42";
|
||||||
|
for (int ii = 0; ii < depth; ++ii)
|
||||||
|
json += "}";
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, StackLimitExceededError_BelowLimit) {
|
||||||
|
// kStackLimit is 300 (see json_parser.cc). First let's
|
||||||
|
// try with a small nested example.
|
||||||
|
std::string json_3 = MakeNestedJson(3);
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json_3), &log_);
|
||||||
|
EXPECT_TRUE(log_.status().ok());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"map begin\n"
|
||||||
|
"string16: foo\n"
|
||||||
|
"map begin\n"
|
||||||
|
"string16: foo\n"
|
||||||
|
"map begin\n"
|
||||||
|
"string16: foo\n"
|
||||||
|
"int: 42\n"
|
||||||
|
"map end\n"
|
||||||
|
"map end\n"
|
||||||
|
"map end\n",
|
||||||
|
log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, StackLimitExceededError_AtLimit) {
|
||||||
|
// Now with kStackLimit (300).
|
||||||
|
std::string json_limit = MakeNestedJson(300);
|
||||||
|
ParseJSON(GetTestPlatform(),
|
||||||
|
span<uint8_t>(reinterpret_cast<const uint8_t*>(json_limit.data()),
|
||||||
|
json_limit.size()),
|
||||||
|
&log_);
|
||||||
|
EXPECT_TRUE(log_.status().ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, StackLimitExceededError_AboveLimit) {
|
||||||
|
// Now with kStackLimit + 1 (301) - it exceeds in the innermost instance.
|
||||||
|
std::string exceeded = MakeNestedJson(301);
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(exceeded), &log_);
|
||||||
|
EXPECT_EQ(Error::JSON_PARSER_STACK_LIMIT_EXCEEDED, log_.status().error);
|
||||||
|
EXPECT_EQ(strlen("{\"foo\":") * 301, log_.status().pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, StackLimitExceededError_WayAboveLimit) {
|
||||||
|
// Now way past the limit. Still, the point of exceeding is 301.
|
||||||
|
std::string far_out = MakeNestedJson(320);
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(far_out), &log_);
|
||||||
|
EXPECT_EQ(Error::JSON_PARSER_STACK_LIMIT_EXCEEDED, log_.status().error);
|
||||||
|
EXPECT_EQ(strlen("{\"foo\":") * 301, log_.status().pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, NoInputError) {
|
||||||
|
std::string json = "";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_EQ(Error::JSON_PARSER_NO_INPUT, log_.status().error);
|
||||||
|
EXPECT_EQ(0u, log_.status().pos);
|
||||||
|
EXPECT_EQ("", log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, InvalidTokenError) {
|
||||||
|
std::string json = "|";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_EQ(Error::JSON_PARSER_INVALID_TOKEN, log_.status().error);
|
||||||
|
EXPECT_EQ(0u, log_.status().pos);
|
||||||
|
EXPECT_EQ("", log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, InvalidNumberError) {
|
||||||
|
// Mantissa exceeds max (the constant used here is int64_t max).
|
||||||
|
std::string json = "1E9223372036854775807";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_EQ(Error::JSON_PARSER_INVALID_NUMBER, log_.status().error);
|
||||||
|
EXPECT_EQ(0u, log_.status().pos);
|
||||||
|
EXPECT_EQ("", log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, InvalidStringError) {
|
||||||
|
// \x22 is an unsupported escape sequence
|
||||||
|
std::string json = "\"foo\\x22\"";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_EQ(Error::JSON_PARSER_INVALID_STRING, log_.status().error);
|
||||||
|
EXPECT_EQ(0u, log_.status().pos);
|
||||||
|
EXPECT_EQ("", log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, UnexpectedArrayEndError) {
|
||||||
|
std::string json = "[1,2,]";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_EQ(Error::JSON_PARSER_UNEXPECTED_ARRAY_END, log_.status().error);
|
||||||
|
EXPECT_EQ(5u, log_.status().pos);
|
||||||
|
EXPECT_EQ("", log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, CommaOrArrayEndExpectedError) {
|
||||||
|
std::string json = "[1,2 2";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_EQ(Error::JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED,
|
||||||
|
log_.status().error);
|
||||||
|
EXPECT_EQ(5u, log_.status().pos);
|
||||||
|
EXPECT_EQ("", log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, StringLiteralExpectedError) {
|
||||||
|
// There's an error because the key bar, a string, is not terminated.
|
||||||
|
std::string json = "{\"foo\": 3.1415, \"bar: 31415e-4}";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_EQ(Error::JSON_PARSER_STRING_LITERAL_EXPECTED, log_.status().error);
|
||||||
|
EXPECT_EQ(16u, log_.status().pos);
|
||||||
|
EXPECT_EQ("", log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, ColonExpectedError) {
|
||||||
|
std::string json = "{\"foo\", 42}";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_EQ(Error::JSON_PARSER_COLON_EXPECTED, log_.status().error);
|
||||||
|
EXPECT_EQ(6u, log_.status().pos);
|
||||||
|
EXPECT_EQ("", log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, UnexpectedMapEndError) {
|
||||||
|
std::string json = "{\"foo\": 42, }";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_EQ(Error::JSON_PARSER_UNEXPECTED_MAP_END, log_.status().error);
|
||||||
|
EXPECT_EQ(12u, log_.status().pos);
|
||||||
|
EXPECT_EQ("", log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, CommaOrMapEndExpectedError) {
|
||||||
|
// The second separator should be a comma.
|
||||||
|
std::string json = "{\"foo\": 3.1415: \"bar\": 0}";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_EQ(Error::JSON_PARSER_COMMA_OR_MAP_END_EXPECTED, log_.status().error);
|
||||||
|
EXPECT_EQ(14u, log_.status().pos);
|
||||||
|
EXPECT_EQ("", log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParserTest, ValueExpectedError) {
|
||||||
|
std::string json = "}";
|
||||||
|
ParseJSON(GetTestPlatform(), SpanFrom(json), &log_);
|
||||||
|
EXPECT_EQ(Error::JSON_PARSER_VALUE_EXPECTED, log_.status().error);
|
||||||
|
EXPECT_EQ(0u, log_.status().pos);
|
||||||
|
EXPECT_EQ("", log_.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class ConvertJSONToCBORTest : public ::testing::Test {};
|
||||||
|
|
||||||
|
using ContainerTestTypes = ::testing::Types<std::vector<uint8_t>, std::string>;
|
||||||
|
TYPED_TEST_SUITE(ConvertJSONToCBORTest, ContainerTestTypes);
|
||||||
|
|
||||||
|
TYPED_TEST(ConvertJSONToCBORTest, RoundTripValidJson) {
|
||||||
|
std::string json_in = "{\"msg\":\"Hello, world.\",\"lst\":[1,2,3]}";
|
||||||
|
TypeParam json(json_in.begin(), json_in.end());
|
||||||
|
TypeParam cbor;
|
||||||
|
{
|
||||||
|
Status status = ConvertJSONToCBOR(GetTestPlatform(), SpanFrom(json), &cbor);
|
||||||
|
EXPECT_EQ(Error::OK, status.error);
|
||||||
|
EXPECT_EQ(Status::npos(), status.pos);
|
||||||
|
}
|
||||||
|
TypeParam roundtrip_json;
|
||||||
|
{
|
||||||
|
Status status =
|
||||||
|
ConvertCBORToJSON(GetTestPlatform(), SpanFrom(cbor), &roundtrip_json);
|
||||||
|
EXPECT_EQ(Error::OK, status.error);
|
||||||
|
EXPECT_EQ(Status::npos(), status.pos);
|
||||||
|
}
|
||||||
|
EXPECT_EQ(json, roundtrip_json);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(ConvertJSONToCBORTest, RoundTripValidJson16) {
|
||||||
|
std::vector<uint16_t> json16 = {
|
||||||
|
'{', '"', 'm', 's', 'g', '"', ':', '"', 'H', 'e', 'l', 'l',
|
||||||
|
'o', ',', ' ', 0xd83c, 0xdf0e, '.', '"', ',', '"', 'l', 's', 't',
|
||||||
|
'"', ':', '[', '1', ',', '2', ',', '3', ']', '}'};
|
||||||
|
TypeParam cbor;
|
||||||
|
{
|
||||||
|
Status status = ConvertJSONToCBOR(
|
||||||
|
GetTestPlatform(), span<uint16_t>(json16.data(), json16.size()), &cbor);
|
||||||
|
EXPECT_EQ(Error::OK, status.error);
|
||||||
|
EXPECT_EQ(Status::npos(), status.pos);
|
||||||
|
}
|
||||||
|
TypeParam roundtrip_json;
|
||||||
|
{
|
||||||
|
Status status =
|
||||||
|
ConvertCBORToJSON(GetTestPlatform(), SpanFrom(cbor), &roundtrip_json);
|
||||||
|
EXPECT_EQ(Error::OK, status.error);
|
||||||
|
EXPECT_EQ(Status::npos(), status.pos);
|
||||||
|
}
|
||||||
|
std::string json = "{\"msg\":\"Hello, \\ud83c\\udf0e.\",\"lst\":[1,2,3]}";
|
||||||
|
TypeParam expected_json(json.begin(), json.end());
|
||||||
|
EXPECT_EQ(expected_json, roundtrip_json);
|
||||||
|
}
|
||||||
|
} // namespace json
|
||||||
|
} // namespace v8_crdtp
|
48
third_party/inspector_protocol/crdtp/parser_handler.h
vendored
Normal file
48
third_party/inspector_protocol/crdtp/parser_handler.h
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef V8_CRDTP_PARSER_HANDLER_H_
|
||||||
|
#define V8_CRDTP_PARSER_HANDLER_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <limits>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "export.h"
|
||||||
|
#include "span.h"
|
||||||
|
#include "status.h"
|
||||||
|
|
||||||
|
namespace v8_crdtp {
|
||||||
|
// Handler interface for parser events emitted by a streaming parser.
|
||||||
|
// See cbor::NewCBOREncoder, cbor::ParseCBOR, json::NewJSONEncoder,
|
||||||
|
// json::ParseJSON.
|
||||||
|
class StreamingParserHandler {
|
||||||
|
public:
|
||||||
|
virtual ~StreamingParserHandler() = default;
|
||||||
|
virtual void HandleMapBegin() = 0;
|
||||||
|
virtual void HandleMapEnd() = 0;
|
||||||
|
virtual void HandleArrayBegin() = 0;
|
||||||
|
virtual void HandleArrayEnd() = 0;
|
||||||
|
virtual void HandleString8(span<uint8_t> chars) = 0;
|
||||||
|
virtual void HandleString16(span<uint16_t> chars) = 0;
|
||||||
|
virtual void HandleBinary(span<uint8_t> bytes) = 0;
|
||||||
|
virtual void HandleDouble(double value) = 0;
|
||||||
|
virtual void HandleInt32(int32_t value) = 0;
|
||||||
|
virtual void HandleBool(bool value) = 0;
|
||||||
|
virtual void HandleNull() = 0;
|
||||||
|
|
||||||
|
// The parser may send one error even after other events have already
|
||||||
|
// been received. Client code is reponsible to then discard the
|
||||||
|
// already processed events.
|
||||||
|
// |error| must be an eror, as in, |error.is_ok()| can't be true.
|
||||||
|
virtual void HandleError(Status error) = 0;
|
||||||
|
};
|
||||||
|
} // namespace v8_crdtp
|
||||||
|
|
||||||
|
#endif // V8_CRDTP_PARSER_HANDLER_H_
|
94
third_party/inspector_protocol/crdtp/span.h
vendored
Normal file
94
third_party/inspector_protocol/crdtp/span.h
vendored
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef V8_CRDTP_SPAN_H_
|
||||||
|
#define V8_CRDTP_SPAN_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <limits>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "export.h"
|
||||||
|
|
||||||
|
namespace v8_crdtp {
|
||||||
|
// =============================================================================
|
||||||
|
// span - sequence of bytes
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// This template is similar to std::span, which will be included in C++20.
|
||||||
|
template <typename T>
|
||||||
|
class span {
|
||||||
|
public:
|
||||||
|
using index_type = size_t;
|
||||||
|
|
||||||
|
span() : data_(nullptr), size_(0) {}
|
||||||
|
span(const T* data, index_type size) : data_(data), size_(size) {}
|
||||||
|
|
||||||
|
const T* data() const { return data_; }
|
||||||
|
|
||||||
|
const T* begin() const { return data_; }
|
||||||
|
const T* end() const { return data_ + size_; }
|
||||||
|
|
||||||
|
const T& operator[](index_type idx) const { return data_[idx]; }
|
||||||
|
|
||||||
|
span<T> subspan(index_type offset, index_type count) const {
|
||||||
|
return span(data_ + offset, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
span<T> subspan(index_type offset) const {
|
||||||
|
return span(data_ + offset, size_ - offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const { return size_ == 0; }
|
||||||
|
|
||||||
|
index_type size() const { return size_; }
|
||||||
|
index_type size_bytes() const { return size_ * sizeof(T); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const T* data_;
|
||||||
|
index_type size_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
span<T> SpanFrom(const std::vector<T>& v) {
|
||||||
|
return span<T>(v.data(), v.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
span<uint8_t> SpanFrom(const char (&str)[N]) {
|
||||||
|
return span<uint8_t>(reinterpret_cast<const uint8_t*>(str), N - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline span<uint8_t> SpanFrom(const char* str) {
|
||||||
|
return str ? span<uint8_t>(reinterpret_cast<const uint8_t*>(str), strlen(str))
|
||||||
|
: span<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline span<uint8_t> SpanFrom(const std::string& v) {
|
||||||
|
return span<uint8_t>(reinterpret_cast<const uint8_t*>(v.data()), v.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Less than / equality comparison functions for sorting / searching for byte
|
||||||
|
// spans. These are similar to absl::string_view's < and == operators.
|
||||||
|
inline bool SpanLessThan(span<uint8_t> x, span<uint8_t> y) noexcept {
|
||||||
|
auto min_size = std::min(x.size(), y.size());
|
||||||
|
const int r = min_size == 0 ? 0 : memcmp(x.data(), y.data(), min_size);
|
||||||
|
return (r < 0) || (r == 0 && x.size() < y.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool SpanEquals(span<uint8_t> x, span<uint8_t> y) noexcept {
|
||||||
|
auto len = x.size();
|
||||||
|
if (len != y.size())
|
||||||
|
return false;
|
||||||
|
return x.data() == y.data() || len == 0 ||
|
||||||
|
std::memcmp(x.data(), y.data(), len) == 0;
|
||||||
|
}
|
||||||
|
} // namespace v8_crdtp
|
||||||
|
|
||||||
|
#endif // V8_CRDTP_SPAN_H_
|
110
third_party/inspector_protocol/crdtp/span_test.cc
vendored
Normal file
110
third_party/inspector_protocol/crdtp/span_test.cc
vendored
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// Copyright 2018 The Chromium 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 "span.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <clocale>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "test_platform.h"
|
||||||
|
|
||||||
|
using testing::ElementsAreArray;
|
||||||
|
|
||||||
|
namespace v8_crdtp {
|
||||||
|
// =============================================================================
|
||||||
|
// span - sequence of bytes
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class SpanTest : public ::testing::Test {};
|
||||||
|
|
||||||
|
using TestTypes = ::testing::Types<uint8_t, uint16_t>;
|
||||||
|
TYPED_TEST_SUITE(SpanTest, TestTypes);
|
||||||
|
|
||||||
|
TYPED_TEST(SpanTest, Empty) {
|
||||||
|
span<TypeParam> empty;
|
||||||
|
EXPECT_TRUE(empty.empty());
|
||||||
|
EXPECT_EQ(0u, empty.size());
|
||||||
|
EXPECT_EQ(0u, empty.size_bytes());
|
||||||
|
EXPECT_EQ(empty.begin(), empty.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(SpanTest, SingleItem) {
|
||||||
|
TypeParam single_item = 42;
|
||||||
|
span<TypeParam> singular(&single_item, 1);
|
||||||
|
EXPECT_FALSE(singular.empty());
|
||||||
|
EXPECT_EQ(1u, singular.size());
|
||||||
|
EXPECT_EQ(sizeof(TypeParam), singular.size_bytes());
|
||||||
|
EXPECT_EQ(singular.begin() + 1, singular.end());
|
||||||
|
EXPECT_EQ(42, singular[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(SpanTest, FiveItems) {
|
||||||
|
std::vector<TypeParam> test_input = {31, 32, 33, 34, 35};
|
||||||
|
span<TypeParam> five_items(test_input.data(), 5);
|
||||||
|
EXPECT_FALSE(five_items.empty());
|
||||||
|
EXPECT_EQ(5u, five_items.size());
|
||||||
|
EXPECT_EQ(sizeof(TypeParam) * 5, five_items.size_bytes());
|
||||||
|
EXPECT_EQ(five_items.begin() + 5, five_items.end());
|
||||||
|
EXPECT_EQ(31, five_items[0]);
|
||||||
|
EXPECT_EQ(32, five_items[1]);
|
||||||
|
EXPECT_EQ(33, five_items[2]);
|
||||||
|
EXPECT_EQ(34, five_items[3]);
|
||||||
|
EXPECT_EQ(35, five_items[4]);
|
||||||
|
span<TypeParam> three_items = five_items.subspan(2);
|
||||||
|
EXPECT_EQ(3u, three_items.size());
|
||||||
|
EXPECT_EQ(33, three_items[0]);
|
||||||
|
EXPECT_EQ(34, three_items[1]);
|
||||||
|
EXPECT_EQ(35, three_items[2]);
|
||||||
|
span<TypeParam> two_items = five_items.subspan(2, 2);
|
||||||
|
EXPECT_EQ(2u, two_items.size());
|
||||||
|
EXPECT_EQ(33, two_items[0]);
|
||||||
|
EXPECT_EQ(34, two_items[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SpanFromTest, FromConstCharAndLiteral) {
|
||||||
|
// Testing this is useful because strlen(nullptr) is undefined.
|
||||||
|
EXPECT_EQ(nullptr, SpanFrom(nullptr).data());
|
||||||
|
EXPECT_EQ(0u, SpanFrom(nullptr).size());
|
||||||
|
|
||||||
|
const char* kEmpty = "";
|
||||||
|
EXPECT_EQ(kEmpty, reinterpret_cast<const char*>(SpanFrom(kEmpty).data()));
|
||||||
|
EXPECT_EQ(0u, SpanFrom(kEmpty).size());
|
||||||
|
|
||||||
|
const char* kFoo = "foo";
|
||||||
|
EXPECT_EQ(kFoo, reinterpret_cast<const char*>(SpanFrom(kFoo).data()));
|
||||||
|
EXPECT_EQ(3u, SpanFrom(kFoo).size());
|
||||||
|
|
||||||
|
EXPECT_EQ(3u, SpanFrom("foo").size());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SpanComparisons, ByteWiseLexicographicalOrder) {
|
||||||
|
// Compare the empty span.
|
||||||
|
EXPECT_FALSE(SpanLessThan(span<uint8_t>(), span<uint8_t>()));
|
||||||
|
EXPECT_TRUE(SpanEquals(span<uint8_t>(), span<uint8_t>()));
|
||||||
|
|
||||||
|
// Compare message with itself.
|
||||||
|
std::string msg = "Hello, world";
|
||||||
|
EXPECT_FALSE(SpanLessThan(SpanFrom(msg), SpanFrom(msg)));
|
||||||
|
EXPECT_TRUE(SpanEquals(SpanFrom(msg), SpanFrom(msg)));
|
||||||
|
|
||||||
|
// Compare message and copy.
|
||||||
|
EXPECT_FALSE(SpanLessThan(SpanFrom(msg), SpanFrom(std::string(msg))));
|
||||||
|
EXPECT_TRUE(SpanEquals(SpanFrom(msg), SpanFrom(std::string(msg))));
|
||||||
|
|
||||||
|
// Compare two messages. |lesser_msg| < |msg| because of the first
|
||||||
|
// byte ('A' < 'H').
|
||||||
|
std::string lesser_msg = "A lesser message.";
|
||||||
|
EXPECT_TRUE(SpanLessThan(SpanFrom(lesser_msg), SpanFrom(msg)));
|
||||||
|
EXPECT_FALSE(SpanLessThan(SpanFrom(msg), SpanFrom(lesser_msg)));
|
||||||
|
EXPECT_FALSE(SpanEquals(SpanFrom(msg), SpanFrom(lesser_msg)));
|
||||||
|
}
|
||||||
|
} // namespace v8_crdtp
|
115
third_party/inspector_protocol/crdtp/status.cc
vendored
Normal file
115
third_party/inspector_protocol/crdtp/status.cc
vendored
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
// Copyright 2019 The Chromium 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 "status.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstring>
|
||||||
|
#include <limits>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
|
namespace v8_crdtp {
|
||||||
|
// =============================================================================
|
||||||
|
// Status and Error codes
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
std::string Status::ToASCIIString() const {
|
||||||
|
switch (error) {
|
||||||
|
case Error::OK:
|
||||||
|
return "OK";
|
||||||
|
case Error::JSON_PARSER_UNPROCESSED_INPUT_REMAINS:
|
||||||
|
return ToASCIIString("JSON: unprocessed input remains");
|
||||||
|
case Error::JSON_PARSER_STACK_LIMIT_EXCEEDED:
|
||||||
|
return ToASCIIString("JSON: stack limit exceeded");
|
||||||
|
case Error::JSON_PARSER_NO_INPUT:
|
||||||
|
return ToASCIIString("JSON: no input");
|
||||||
|
case Error::JSON_PARSER_INVALID_TOKEN:
|
||||||
|
return ToASCIIString("JSON: invalid token");
|
||||||
|
case Error::JSON_PARSER_INVALID_NUMBER:
|
||||||
|
return ToASCIIString("JSON: invalid number");
|
||||||
|
case Error::JSON_PARSER_INVALID_STRING:
|
||||||
|
return ToASCIIString("JSON: invalid string");
|
||||||
|
case Error::JSON_PARSER_UNEXPECTED_ARRAY_END:
|
||||||
|
return ToASCIIString("JSON: unexpected array end");
|
||||||
|
case Error::JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED:
|
||||||
|
return ToASCIIString("JSON: comma or array end expected");
|
||||||
|
case Error::JSON_PARSER_STRING_LITERAL_EXPECTED:
|
||||||
|
return ToASCIIString("JSON: string literal expected");
|
||||||
|
case Error::JSON_PARSER_COLON_EXPECTED:
|
||||||
|
return ToASCIIString("JSON: colon expected");
|
||||||
|
case Error::JSON_PARSER_UNEXPECTED_MAP_END:
|
||||||
|
return ToASCIIString("JSON: unexpected map end");
|
||||||
|
case Error::JSON_PARSER_COMMA_OR_MAP_END_EXPECTED:
|
||||||
|
return ToASCIIString("JSON: comma or map end expected");
|
||||||
|
case Error::JSON_PARSER_VALUE_EXPECTED:
|
||||||
|
return ToASCIIString("JSON: value expected");
|
||||||
|
|
||||||
|
case Error::CBOR_INVALID_INT32:
|
||||||
|
return ToASCIIString("CBOR: invalid int32");
|
||||||
|
case Error::CBOR_INVALID_DOUBLE:
|
||||||
|
return ToASCIIString("CBOR: invalid double");
|
||||||
|
case Error::CBOR_INVALID_ENVELOPE:
|
||||||
|
return ToASCIIString("CBOR: invalid envelope");
|
||||||
|
case Error::CBOR_ENVELOPE_CONTENTS_LENGTH_MISMATCH:
|
||||||
|
return ToASCIIString("CBOR: envelope contents length mismatch");
|
||||||
|
case Error::CBOR_MAP_OR_ARRAY_EXPECTED_IN_ENVELOPE:
|
||||||
|
return ToASCIIString("CBOR: map or array expected in envelope");
|
||||||
|
case Error::CBOR_INVALID_STRING8:
|
||||||
|
return ToASCIIString("CBOR: invalid string8");
|
||||||
|
case Error::CBOR_INVALID_STRING16:
|
||||||
|
return ToASCIIString("CBOR: invalid string16");
|
||||||
|
case Error::CBOR_INVALID_BINARY:
|
||||||
|
return ToASCIIString("CBOR: invalid binary");
|
||||||
|
case Error::CBOR_UNSUPPORTED_VALUE:
|
||||||
|
return ToASCIIString("CBOR: unsupported value");
|
||||||
|
case Error::CBOR_NO_INPUT:
|
||||||
|
return ToASCIIString("CBOR: no input");
|
||||||
|
case Error::CBOR_INVALID_START_BYTE:
|
||||||
|
return ToASCIIString("CBOR: invalid start byte");
|
||||||
|
case Error::CBOR_UNEXPECTED_EOF_EXPECTED_VALUE:
|
||||||
|
return ToASCIIString("CBOR: unexpected eof expected value");
|
||||||
|
case Error::CBOR_UNEXPECTED_EOF_IN_ARRAY:
|
||||||
|
return ToASCIIString("CBOR: unexpected eof in array");
|
||||||
|
case Error::CBOR_UNEXPECTED_EOF_IN_MAP:
|
||||||
|
return ToASCIIString("CBOR: unexpected eof in map");
|
||||||
|
case Error::CBOR_INVALID_MAP_KEY:
|
||||||
|
return ToASCIIString("CBOR: invalid map key");
|
||||||
|
case Error::CBOR_STACK_LIMIT_EXCEEDED:
|
||||||
|
return ToASCIIString("CBOR: stack limit exceeded");
|
||||||
|
case Error::CBOR_TRAILING_JUNK:
|
||||||
|
return ToASCIIString("CBOR: trailing junk");
|
||||||
|
case Error::CBOR_MAP_START_EXPECTED:
|
||||||
|
return ToASCIIString("CBOR: map start expected");
|
||||||
|
case Error::CBOR_MAP_STOP_EXPECTED:
|
||||||
|
return ToASCIIString("CBOR: map stop expected");
|
||||||
|
case Error::CBOR_ARRAY_START_EXPECTED:
|
||||||
|
return ToASCIIString("CBOR: array start expected");
|
||||||
|
case Error::CBOR_ENVELOPE_SIZE_LIMIT_EXCEEDED:
|
||||||
|
return ToASCIIString("CBOR: envelope size limit exceeded");
|
||||||
|
|
||||||
|
case Error::BINDINGS_MANDATORY_FIELD_MISSING:
|
||||||
|
return ToASCIIString("BINDINGS: mandatory field missing");
|
||||||
|
case Error::BINDINGS_BOOL_VALUE_EXPECTED:
|
||||||
|
return ToASCIIString("BINDINGS: bool value expected");
|
||||||
|
case Error::BINDINGS_INT32_VALUE_EXPECTED:
|
||||||
|
return ToASCIIString("BINDINGS: int32 value expected");
|
||||||
|
case Error::BINDINGS_DOUBLE_VALUE_EXPECTED:
|
||||||
|
return ToASCIIString("BINDINGS: double value expected");
|
||||||
|
case Error::BINDINGS_STRING_VALUE_EXPECTED:
|
||||||
|
return ToASCIIString("BINDINGS: string value expected");
|
||||||
|
case Error::BINDINGS_STRING8_VALUE_EXPECTED:
|
||||||
|
return ToASCIIString("BINDINGS: string8 value expected");
|
||||||
|
case Error::BINDINGS_BINARY_VALUE_EXPECTED:
|
||||||
|
return ToASCIIString("BINDINGS: binary value expected");
|
||||||
|
}
|
||||||
|
// Some compilers can't figure out that we can't get here.
|
||||||
|
return "INVALID ERROR CODE";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Status::ToASCIIString(const char* msg) const {
|
||||||
|
return std::string(msg) + " at position " + std::to_string(pos);
|
||||||
|
}
|
||||||
|
} // namespace v8_crdtp
|
92
third_party/inspector_protocol/crdtp/status.h
vendored
Normal file
92
third_party/inspector_protocol/crdtp/status.h
vendored
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef V8_CRDTP_ENCODING_H_
|
||||||
|
#define V8_CRDTP_ENCODING_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <limits>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "export.h"
|
||||||
|
|
||||||
|
namespace v8_crdtp {
|
||||||
|
// =============================================================================
|
||||||
|
// Status and Error codes
|
||||||
|
// =============================================================================
|
||||||
|
enum class Error {
|
||||||
|
OK = 0,
|
||||||
|
// JSON parsing errors - json_parser.{h,cc}.
|
||||||
|
JSON_PARSER_UNPROCESSED_INPUT_REMAINS = 0x01,
|
||||||
|
JSON_PARSER_STACK_LIMIT_EXCEEDED = 0x02,
|
||||||
|
JSON_PARSER_NO_INPUT = 0x03,
|
||||||
|
JSON_PARSER_INVALID_TOKEN = 0x04,
|
||||||
|
JSON_PARSER_INVALID_NUMBER = 0x05,
|
||||||
|
JSON_PARSER_INVALID_STRING = 0x06,
|
||||||
|
JSON_PARSER_UNEXPECTED_ARRAY_END = 0x07,
|
||||||
|
JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED = 0x08,
|
||||||
|
JSON_PARSER_STRING_LITERAL_EXPECTED = 0x09,
|
||||||
|
JSON_PARSER_COLON_EXPECTED = 0x0a,
|
||||||
|
JSON_PARSER_UNEXPECTED_MAP_END = 0x0b,
|
||||||
|
JSON_PARSER_COMMA_OR_MAP_END_EXPECTED = 0x0c,
|
||||||
|
JSON_PARSER_VALUE_EXPECTED = 0x0d,
|
||||||
|
|
||||||
|
CBOR_INVALID_INT32 = 0x0e,
|
||||||
|
CBOR_INVALID_DOUBLE = 0x0f,
|
||||||
|
CBOR_INVALID_ENVELOPE = 0x10,
|
||||||
|
CBOR_ENVELOPE_CONTENTS_LENGTH_MISMATCH = 0x11,
|
||||||
|
CBOR_MAP_OR_ARRAY_EXPECTED_IN_ENVELOPE = 0x12,
|
||||||
|
CBOR_INVALID_STRING8 = 0x13,
|
||||||
|
CBOR_INVALID_STRING16 = 0x14,
|
||||||
|
CBOR_INVALID_BINARY = 0x15,
|
||||||
|
CBOR_UNSUPPORTED_VALUE = 0x16,
|
||||||
|
CBOR_NO_INPUT = 0x17,
|
||||||
|
CBOR_INVALID_START_BYTE = 0x18,
|
||||||
|
CBOR_UNEXPECTED_EOF_EXPECTED_VALUE = 0x19,
|
||||||
|
CBOR_UNEXPECTED_EOF_IN_ARRAY = 0x1a,
|
||||||
|
CBOR_UNEXPECTED_EOF_IN_MAP = 0x1b,
|
||||||
|
CBOR_INVALID_MAP_KEY = 0x1c,
|
||||||
|
CBOR_STACK_LIMIT_EXCEEDED = 0x1d,
|
||||||
|
CBOR_TRAILING_JUNK = 0x1e,
|
||||||
|
CBOR_MAP_START_EXPECTED = 0x1f,
|
||||||
|
CBOR_MAP_STOP_EXPECTED = 0x20,
|
||||||
|
CBOR_ARRAY_START_EXPECTED = 0x21,
|
||||||
|
CBOR_ENVELOPE_SIZE_LIMIT_EXCEEDED = 0x22,
|
||||||
|
|
||||||
|
BINDINGS_MANDATORY_FIELD_MISSING = 0x23,
|
||||||
|
BINDINGS_BOOL_VALUE_EXPECTED = 0x24,
|
||||||
|
BINDINGS_INT32_VALUE_EXPECTED = 0x25,
|
||||||
|
BINDINGS_DOUBLE_VALUE_EXPECTED = 0x26,
|
||||||
|
BINDINGS_STRING_VALUE_EXPECTED = 0x27,
|
||||||
|
BINDINGS_STRING8_VALUE_EXPECTED = 0x28,
|
||||||
|
BINDINGS_BINARY_VALUE_EXPECTED = 0x29,
|
||||||
|
};
|
||||||
|
|
||||||
|
// A status value with position that can be copied. The default status
|
||||||
|
// is OK. Usually, error status values should come with a valid position.
|
||||||
|
struct Status {
|
||||||
|
static constexpr size_t npos() { return std::numeric_limits<size_t>::max(); }
|
||||||
|
|
||||||
|
bool ok() const { return error == Error::OK; }
|
||||||
|
|
||||||
|
Error error = Error::OK;
|
||||||
|
size_t pos = npos();
|
||||||
|
Status(Error error, size_t pos) : error(error), pos(pos) {}
|
||||||
|
Status() = default;
|
||||||
|
|
||||||
|
// Returns a 7 bit US-ASCII string, either "OK" or an error message
|
||||||
|
// that includes the position.
|
||||||
|
std::string ToASCIIString() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string ToASCIIString(const char* msg) const;
|
||||||
|
};
|
||||||
|
} // namespace v8_crdtp
|
||||||
|
|
||||||
|
#endif // V8_CRDTP_ENCODING_H_
|
34
third_party/inspector_protocol/crdtp/status_test.cc
vendored
Normal file
34
third_party/inspector_protocol/crdtp/status_test.cc
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright 2018 The Chromium 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 "status.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <clocale>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "test_platform.h"
|
||||||
|
|
||||||
|
using testing::ElementsAreArray;
|
||||||
|
|
||||||
|
namespace v8_crdtp {
|
||||||
|
// =============================================================================
|
||||||
|
// Status and Error codes
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
TEST(StatusTest, StatusToASCIIString) {
|
||||||
|
Status ok_status;
|
||||||
|
EXPECT_EQ("OK", ok_status.ToASCIIString());
|
||||||
|
Status json_error(Error::JSON_PARSER_COLON_EXPECTED, 42);
|
||||||
|
EXPECT_EQ("JSON: colon expected at position 42", json_error.ToASCIIString());
|
||||||
|
Status cbor_error(Error::CBOR_TRAILING_JUNK, 21);
|
||||||
|
EXPECT_EQ("CBOR: trailing junk at position 21", cbor_error.ToASCIIString());
|
||||||
|
}
|
||||||
|
} // namespace v8_crdtp
|
@ -5,18 +5,11 @@
|
|||||||
// This file is V8 specific, to make encoding_test.cc work.
|
// This file is V8 specific, to make encoding_test.cc work.
|
||||||
// It is not rolled from the upstream project.
|
// It is not rolled from the upstream project.
|
||||||
|
|
||||||
#ifndef V8_INSPECTOR_PROTOCOL_ENCODING_ENCODING_TEST_HELPER_H_
|
#include "test_platform.h"
|
||||||
#define V8_INSPECTOR_PROTOCOL_ENCODING_ENCODING_TEST_HELPER_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "src/base/logging.h"
|
|
||||||
#include "src/inspector/v8-string-conversions.h"
|
#include "src/inspector/v8-string-conversions.h"
|
||||||
#include "testing/gmock/include/gmock/gmock.h"
|
|
||||||
#include "testing/gtest/include/gtest/gtest.h"
|
|
||||||
|
|
||||||
namespace v8_inspector_protocol_encoding {
|
namespace v8_crdtp {
|
||||||
|
|
||||||
std::string UTF16ToUTF8(span<uint16_t> in) {
|
std::string UTF16ToUTF8(span<uint16_t> in) {
|
||||||
return v8_inspector::UTF16ToUTF8(in.data(), in.size());
|
return v8_inspector::UTF16ToUTF8(in.data(), in.size());
|
||||||
@ -28,6 +21,4 @@ std::vector<uint16_t> UTF8ToUTF16(span<uint8_t> in) {
|
|||||||
return std::vector<uint16_t>(utf16.begin(), utf16.end());
|
return std::vector<uint16_t>(utf16.begin(), utf16.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace v8_inspector_protocol_encoding
|
} // namespace v8_crdtp
|
||||||
|
|
||||||
#endif // V8_INSPECTOR_PROTOCOL_ENCODING_ENCODING_TEST_HELPER_H_
|
|
27
third_party/inspector_protocol/crdtp/test_platform.h
vendored
Normal file
27
third_party/inspector_protocol/crdtp/test_platform.h
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2019 The V8 Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// This file is V8 specific, to make encoding_test.cc work.
|
||||||
|
// It is not rolled from the upstream project.
|
||||||
|
|
||||||
|
#ifndef V8_INSPECTOR_PROTOCOL_CRDTP_TEST_PLATFORM_H_
|
||||||
|
#define V8_INSPECTOR_PROTOCOL_CRDTP_TEST_PLATFORM_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "span.h"
|
||||||
|
#include "src/base/logging.h"
|
||||||
|
#include "testing/gmock/include/gmock/gmock.h"
|
||||||
|
#include "testing/gtest/include/gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace v8_crdtp {
|
||||||
|
|
||||||
|
std::string UTF16ToUTF8(span<uint16_t> in);
|
||||||
|
|
||||||
|
std::vector<uint16_t> UTF8ToUTF16(span<uint8_t> in);
|
||||||
|
|
||||||
|
} // namespace v8_crdtp
|
||||||
|
|
||||||
|
#endif // V8_INSPECTOR_PROTOCOL_CRDTP_TEST_PLATFORM_H_
|
@ -316,10 +316,10 @@ std::unique_ptr<Serializable> InternalResponse::createErrorResponse(int callId,
|
|||||||
|
|
||||||
void InternalResponse::AppendSerialized(std::vector<uint8_t>* out) const
|
void InternalResponse::AppendSerialized(std::vector<uint8_t>* out) const
|
||||||
{
|
{
|
||||||
using {{config.encoding_lib.namespace}}::cbor::NewCBOREncoder;
|
using {{config.crdtp.namespace}}::cbor::NewCBOREncoder;
|
||||||
using {{config.encoding_lib.namespace}}::StreamingParserHandler;
|
using {{config.crdtp.namespace}}::StreamingParserHandler;
|
||||||
using {{config.encoding_lib.namespace}}::Status;
|
using {{config.crdtp.namespace}}::Status;
|
||||||
using {{config.encoding_lib.namespace}}::SpanFrom;
|
using {{config.crdtp.namespace}}::SpanFrom;
|
||||||
|
|
||||||
Status status;
|
Status status;
|
||||||
std::unique_ptr<StreamingParserHandler> encoder =
|
std::unique_ptr<StreamingParserHandler> encoder =
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
#include "{{config.bindings_lib.header}}"
|
#include "{{config.crdtp.dir}}/glue.h"
|
||||||
|
|
||||||
{% for namespace in config.protocol.namespace %}
|
{% for namespace in config.protocol.namespace %}
|
||||||
namespace {{namespace}} {
|
namespace {{namespace}} {
|
||||||
@ -57,8 +57,8 @@ template <typename T>
|
|||||||
using Array = typename detail::ArrayTypedef<T>::type;
|
using Array = typename detail::ArrayTypedef<T>::type;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
using {{config.bindings_lib.namespace}}::glue::detail::PtrMaybe;
|
using {{config.crdtp.namespace}}::glue::detail::PtrMaybe;
|
||||||
using {{config.bindings_lib.namespace}}::glue::detail::ValueMaybe;
|
using {{config.crdtp.namespace}}::glue::detail::ValueMaybe;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct MaybeTypedef { typedef PtrMaybe<T> type; };
|
struct MaybeTypedef { typedef PtrMaybe<T> type; };
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
//#include "Values.h"
|
//#include "Values.h"
|
||||||
|
|
||||||
#include "{{config.encoding_lib.header}}"
|
#include "{{config.crdtp.dir}}/cbor.h"
|
||||||
|
|
||||||
{% for namespace in config.protocol.namespace %}
|
{% for namespace in config.protocol.namespace %}
|
||||||
namespace {{namespace}} {
|
namespace {{namespace}} {
|
||||||
@ -66,26 +66,26 @@ void escapeStringForJSONInternal(const Char* str, unsigned len,
|
|||||||
// to this constant.
|
// to this constant.
|
||||||
static constexpr int kStackLimitValues = 1000;
|
static constexpr int kStackLimitValues = 1000;
|
||||||
|
|
||||||
using {{config.encoding_lib.namespace}}::Error;
|
using {{config.crdtp.namespace}}::Error;
|
||||||
using {{config.encoding_lib.namespace}}::Status;
|
using {{config.crdtp.namespace}}::Status;
|
||||||
using {{config.encoding_lib.namespace}}::span;
|
using {{config.crdtp.namespace}}::span;
|
||||||
namespace cbor {
|
namespace cbor {
|
||||||
using {{config.encoding_lib.namespace}}::cbor::CBORTokenTag;
|
using {{config.crdtp.namespace}}::cbor::CBORTokenTag;
|
||||||
using {{config.encoding_lib.namespace}}::cbor::CBORTokenizer;
|
using {{config.crdtp.namespace}}::cbor::CBORTokenizer;
|
||||||
using {{config.encoding_lib.namespace}}::cbor::EncodeBinary;
|
using {{config.crdtp.namespace}}::cbor::EncodeBinary;
|
||||||
using {{config.encoding_lib.namespace}}::cbor::EncodeDouble;
|
using {{config.crdtp.namespace}}::cbor::EncodeDouble;
|
||||||
using {{config.encoding_lib.namespace}}::cbor::EncodeFalse;
|
using {{config.crdtp.namespace}}::cbor::EncodeFalse;
|
||||||
using {{config.encoding_lib.namespace}}::cbor::EncodeFromLatin1;
|
using {{config.crdtp.namespace}}::cbor::EncodeFromLatin1;
|
||||||
using {{config.encoding_lib.namespace}}::cbor::EncodeFromUTF16;
|
using {{config.crdtp.namespace}}::cbor::EncodeFromUTF16;
|
||||||
using {{config.encoding_lib.namespace}}::cbor::EncodeIndefiniteLengthArrayStart;
|
using {{config.crdtp.namespace}}::cbor::EncodeIndefiniteLengthArrayStart;
|
||||||
using {{config.encoding_lib.namespace}}::cbor::EncodeIndefiniteLengthMapStart;
|
using {{config.crdtp.namespace}}::cbor::EncodeIndefiniteLengthMapStart;
|
||||||
using {{config.encoding_lib.namespace}}::cbor::EncodeInt32;
|
using {{config.crdtp.namespace}}::cbor::EncodeInt32;
|
||||||
using {{config.encoding_lib.namespace}}::cbor::EncodeNull;
|
using {{config.crdtp.namespace}}::cbor::EncodeNull;
|
||||||
using {{config.encoding_lib.namespace}}::cbor::EncodeStop;
|
using {{config.crdtp.namespace}}::cbor::EncodeStop;
|
||||||
using {{config.encoding_lib.namespace}}::cbor::EncodeString8;
|
using {{config.crdtp.namespace}}::cbor::EncodeString8;
|
||||||
using {{config.encoding_lib.namespace}}::cbor::EncodeTrue;
|
using {{config.crdtp.namespace}}::cbor::EncodeTrue;
|
||||||
using {{config.encoding_lib.namespace}}::cbor::EnvelopeEncoder;
|
using {{config.crdtp.namespace}}::cbor::EnvelopeEncoder;
|
||||||
using {{config.encoding_lib.namespace}}::cbor::InitialByteForEnvelope;
|
using {{config.crdtp.namespace}}::cbor::InitialByteForEnvelope;
|
||||||
} // namespace cbor
|
} // namespace cbor
|
||||||
|
|
||||||
// Below are three parsing routines for CBOR, which cover enough
|
// Below are three parsing routines for CBOR, which cover enough
|
||||||
|
36
third_party/inspector_protocol/roll.py
vendored
36
third_party/inspector_protocol/roll.py
vendored
@ -18,12 +18,21 @@ FILES_TO_SYNC = [
|
|||||||
'code_generator.py',
|
'code_generator.py',
|
||||||
'concatenate_protocols.py',
|
'concatenate_protocols.py',
|
||||||
'convert_protocol_to_json.py',
|
'convert_protocol_to_json.py',
|
||||||
'encoding/encoding.h',
|
'crdtp/cbor.cc',
|
||||||
'encoding/encoding.cc',
|
'crdtp/cbor.h',
|
||||||
'encoding/encoding_test.cc',
|
'crdtp/cbor_test.cc',
|
||||||
'bindings/bindings.h',
|
'crdtp/glue.h',
|
||||||
'bindings/bindings.cc',
|
'crdtp/glue_test.cc',
|
||||||
'bindings/bindings_test.cc',
|
'crdtp/json.cc',
|
||||||
|
'crdtp/json.h',
|
||||||
|
'crdtp/json_platform.h',
|
||||||
|
'crdtp/json_test.cc',
|
||||||
|
'crdtp/parser_handler.h',
|
||||||
|
'crdtp/span.h',
|
||||||
|
'crdtp/span_test.cc',
|
||||||
|
'crdtp/status.cc',
|
||||||
|
'crdtp/status.h',
|
||||||
|
'crdtp/status_test.cc',
|
||||||
'inspector_protocol.gni',
|
'inspector_protocol.gni',
|
||||||
'inspector_protocol.gypi',
|
'inspector_protocol.gypi',
|
||||||
'lib/*',
|
'lib/*',
|
||||||
@ -140,18 +149,13 @@ def main(argv):
|
|||||||
print('You said --force ... as you wish, modifying the destination.')
|
print('You said --force ... as you wish, modifying the destination.')
|
||||||
for f in to_add + to_copy:
|
for f in to_add + to_copy:
|
||||||
contents = open(os.path.join(src_dir, f)).read()
|
contents = open(os.path.join(src_dir, f)).read()
|
||||||
|
contents = contents.replace('CRDTP_EXPORT ', '')
|
||||||
contents = contents.replace(
|
contents = contents.replace(
|
||||||
'INSPECTOR_PROTOCOL_ENCODING_ENCODING_H_',
|
'CRDTP_',
|
||||||
'V8_INSPECTOR_PROTOCOL_ENCODING_ENCODING_H_')
|
'V8_CRDTP_')
|
||||||
contents = contents.replace(
|
contents = contents.replace(
|
||||||
'namespace inspector_protocol_encoding',
|
'namespace crdtp',
|
||||||
'namespace v8_inspector_protocol_encoding')
|
'namespace v8_crdtp')
|
||||||
contents = contents.replace(
|
|
||||||
'INSPECTOR_PROTOCOL_BINDINGS_BINDINGS_H_',
|
|
||||||
'V8_INSPECTOR_PROTOCOL_BINDINGS_BINDINGS_H_')
|
|
||||||
contents = contents.replace(
|
|
||||||
'namespace inspector_protocol_bindings',
|
|
||||||
'namespace v8_inspector_protocol_bindings')
|
|
||||||
open(os.path.join(dest_dir, f), 'w').write(contents)
|
open(os.path.join(dest_dir, f), 'w').write(contents)
|
||||||
shutil.copymode(os.path.join(src_dir, f), os.path.join(dest_dir, f))
|
shutil.copymode(os.path.join(src_dir, f), os.path.join(dest_dir, f))
|
||||||
for f in to_delete:
|
for f in to_delete:
|
||||||
|
Loading…
Reference in New Issue
Block a user