From 8567586730981d96cc1423d2cd9e38744b8dbb16 Mon Sep 17 00:00:00 2001 From: wengchangcheng Date: Mon, 6 Jun 2022 00:26:32 +0800 Subject: [PATCH] add json utils for debugger add json util of cJSON issue: https://gitee.com/openharmony/ark_js_runtime/issues/I5AQMM Signed-off-by: wengchangcheng Change-Id: Ie582ceb8ee3c5b9bd8024c25063a9b4a645792ac --- ecmascript/tooling/BUILD.gn | 6 +- ecmascript/tooling/base/pt_json.cpp | 401 +++++++++++++++++++++++ ecmascript/tooling/base/pt_json.h | 102 ++++++ ecmascript/tooling/test/BUILD.gn | 1 + ecmascript/tooling/test/pt_json_test.cpp | 163 +++++++++ 5 files changed, 672 insertions(+), 1 deletion(-) create mode 100644 ecmascript/tooling/base/pt_json.cpp create mode 100644 ecmascript/tooling/base/pt_json.h create mode 100644 ecmascript/tooling/test/pt_json_test.cpp diff --git a/ecmascript/tooling/BUILD.gn b/ecmascript/tooling/BUILD.gn index f829fc4f63..01fb896b0e 100644 --- a/ecmascript/tooling/BUILD.gn +++ b/ecmascript/tooling/BUILD.gn @@ -21,8 +21,9 @@ config("ark_ecma_debugger_config") { ] include_dirs = [ - "//ark/js_runtime/ecmascript/tooling", + ".", "//third_party/boost", + "//third_party/cJSON", ] } @@ -35,6 +36,7 @@ debugger_sources = [ "backend/js_pt_extractor.cpp", "backend/js_pt_hooks.cpp", "base/pt_events.cpp", + "base/pt_json.cpp", "base/pt_params.cpp", "base/pt_returns.cpp", "base/pt_script.cpp", @@ -52,6 +54,7 @@ source_set("libark_ecma_debugger_set") { deps = [ "$ark_root/libpandabase:libarkbase", "$ark_root/libpandafile:libarkfile", + "//third_party/cJSON:cjson_static", ] cflags_cc = [ "-fvisibility=hidden" ] @@ -83,6 +86,7 @@ source_set("libark_ecma_debugger_test_set") { deps = [ "$ark_root/libpandabase:libarkbase", "$ark_root/libpandafile:libarkfile", + "//third_party/cJSON:cjson_static", ] } diff --git a/ecmascript/tooling/base/pt_json.cpp b/ecmascript/tooling/base/pt_json.cpp new file mode 100644 index 0000000000..b790854142 --- /dev/null +++ b/ecmascript/tooling/base/pt_json.cpp @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecmascript/tooling/base/pt_json.h" + +#include "libpandabase/macros.h" + +namespace panda::ecmascript::tooling { +std::unique_ptr PtJson::CreateObject() +{ + return std::make_unique(cJSON_CreateObject()); +} + +std::unique_ptr PtJson::CreateArray() +{ + return std::make_unique(cJSON_CreateArray()); +} + +void PtJson::ReleaseRoot() +{ + if (object_ != nullptr) { + cJSON_Delete(object_); + object_ = nullptr; + } +} + +std::unique_ptr PtJson::Parse(const char *data) +{ + cJSON *value = cJSON_ParseWithOpts(data, nullptr, true); + return std::make_unique(value); +} + +std::string PtJson::Stringify() const +{ + if (object_ == nullptr) { + return ""; + } + + char *str = cJSON_PrintUnformatted(object_); + if (str == nullptr) { + return ""; + } + + std::string result(str); + cJSON_free(str); + return result; +} + +bool PtJson::Add(const char *key, bool value) const +{ + ASSERT(key != nullptr && !Contains(key)); + + cJSON *node = cJSON_CreateBool(value); + if (node == nullptr) { + return false; + } + + cJSON_bool ret = cJSON_AddItemToObject(object_, key, node); + if (ret == 0) { + cJSON_Delete(node); + return false; + } + + return true; +} + +bool PtJson::Add(const char *key, int32_t value) const +{ + return Add(key, static_cast(value)); +} + +bool PtJson::Add(const char *key, int64_t value) const +{ + return Add(key, static_cast(value)); +} + +bool PtJson::Add(const char *key, double value) const +{ + ASSERT(key != nullptr && !Contains(key)); + + cJSON *node = cJSON_CreateNumber(value); + if (node == nullptr) { + return false; + } + + cJSON_bool ret = cJSON_AddItemToObject(object_, key, node); + if (ret == 0) { + cJSON_Delete(node); + return false; + } + + return true; +} + +bool PtJson::Add(const char *key, const char *value) const +{ + ASSERT(key != nullptr && !Contains(key)); + + cJSON *node = cJSON_CreateString(value); + if (node == nullptr) { + return false; + } + + cJSON_bool ret = cJSON_AddItemToObject(object_, key, node); + if (ret == 0) { + cJSON_Delete(node); + return false; + } + + return true; +} + +bool PtJson::Add(const char *key, const std::unique_ptr &value) const +{ + ASSERT(key != nullptr && !Contains(key)); + + cJSON *node = value->GetJson(); + if (node == nullptr) { + return false; + } + + cJSON_bool ret = cJSON_AddItemToObject(object_, key, node); + if (ret == 0) { + return false; + } + + return true; +} + +bool PtJson::Push(bool value) const +{ + cJSON *node = cJSON_CreateBool(value); + if (node == nullptr) { + return false; + } + + cJSON_bool ret = cJSON_AddItemToArray(object_, node); + if (ret == 0) { + cJSON_Delete(node); + return false; + } + + return true; +} + +bool PtJson::Push(int32_t value) const +{ + return Push(static_cast(value)); +} + +bool PtJson::Push(int64_t value) const +{ + return Push(static_cast(value)); +} + +bool PtJson::Push(double value) const +{ + cJSON *node = cJSON_CreateNumber(value); + if (node == nullptr) { + return false; + } + + cJSON_bool ret = cJSON_AddItemToArray(object_, node); + if (ret == 0) { + cJSON_Delete(node); + return false; + } + + return true; +} + +bool PtJson::Push(const char *value) const +{ + cJSON *node = cJSON_CreateString(value); + if (node == nullptr) { + return false; + } + + cJSON_bool ret = cJSON_AddItemToArray(object_, node); + if (ret == 0) { + cJSON_Delete(node); + return false; + } + + return true; +} + +bool PtJson::Push(const std::unique_ptr &value) const +{ + if (value == nullptr) { + return false; + } + + cJSON *node = value->GetJson(); + if (node == nullptr) { + return false; + } + + cJSON_bool ret = cJSON_AddItemToArray(object_, node); + if (ret == 0) { + return false; + } + + return true; +} + +bool PtJson::Remove(const char *key) const +{ + ASSERT(key != nullptr && Contains(key)); + + cJSON_DeleteItemFromObject(object_, key); + return true; +} + +bool PtJson::Contains(const char *key) const +{ + cJSON *node = cJSON_GetObjectItemCaseSensitive(object_, key); + return node != nullptr; +} + +std::string PtJson::GetKey() const +{ + if (object_ == nullptr || object_->string == nullptr) { + return ""; + } + + return std::string(object_->string); +} + +cJSON *PtJson::GetJson() const +{ + return object_; +} + +bool PtJson::IsBool() const +{ + return cJSON_IsBool(object_) != 0; +} + +bool PtJson::IsNumber() const +{ + return cJSON_IsNumber(object_) != 0; +} + +bool PtJson::IsString() const +{ + return cJSON_IsString(object_) != 0; +} + +bool PtJson::IsObject() const +{ + return cJSON_IsObject(object_) != 0; +} + +bool PtJson::IsArray() const +{ + return cJSON_IsArray(object_) != 0; +} + +bool PtJson::IsNull() const +{ + return cJSON_IsNull(object_) != 0; +} + +bool PtJson::GetBool(bool defaultValue) const +{ + if (!IsBool()) { + return defaultValue; + } + + return cJSON_IsTrue(object_) != 0; +} + +int32_t PtJson::GetInt(int32_t defaultValue) const +{ + if (!IsNumber()) { + return defaultValue; + } + + return static_cast(object_->valuedouble); +} + +int64_t PtJson::GetInt64(int64_t defaultValue) const +{ + if (!IsNumber()) { + return defaultValue; + } + + return static_cast(object_->valuedouble); +} + +double PtJson::GetDouble(double defaultValue) const +{ + if (!IsNumber()) { + return defaultValue; + } + + return object_->valuedouble; +} + +std::string PtJson::GetString() const +{ + if (!IsString()) { + return ""; + } + + return std::string(object_->valuestring); +} + +int32_t PtJson::GetSize() const +{ + return cJSON_GetArraySize(object_); +} + +std::unique_ptr PtJson::Get(int32_t index) const +{ + return std::make_unique(cJSON_GetArrayItem(object_, index)); +} + +bool PtJson::GetBool(const char *key, bool defaultValue) const +{ + cJSON *value = cJSON_GetObjectItem(object_, key); + if (value == nullptr || cJSON_IsBool(value) == 0) { + return defaultValue; + } + + return cJSON_IsTrue(value) != 0; +} + +int32_t PtJson::GetInt(const char *key, int32_t defaultValue) const +{ + cJSON *value = cJSON_GetObjectItem(object_, key); + if (value == nullptr || cJSON_IsNumber(value) == 0) { + return defaultValue; + } + + return static_cast(value->valuedouble); +} + +int64_t PtJson::GetInt64(const char *key, int64_t defaultValue) const +{ + cJSON *value = cJSON_GetObjectItem(object_, key); + if (value == nullptr || cJSON_IsNumber(value) == 0) { + return defaultValue; + } + + return static_cast(value->valuedouble); +} + +double PtJson::GetDouble(const char *key, double defaultValue) const +{ + cJSON *value = cJSON_GetObjectItem(object_, key); + if (value == nullptr || cJSON_IsNumber(value) == 0) { + return defaultValue; + } + + return value->valuedouble; +} + +std::string PtJson::GetString(const char *key, std::string defaultValue) const +{ + cJSON *value = cJSON_GetObjectItem(object_, key); + if (value == nullptr || cJSON_IsString(value) == 0) { + return defaultValue; + } + + return value->valuestring; +} + +std::unique_ptr PtJson::GetObject(const char *key) const +{ + cJSON *value = cJSON_GetObjectItem(object_, key); + if (value == nullptr || cJSON_IsObject(value) == 0) { + return std::make_unique(); + } + + return std::make_unique(value); +} + +std::unique_ptr PtJson::GetArray(const char *key) const +{ + cJSON *value = cJSON_GetObjectItem(object_, key); + if (value == nullptr || cJSON_IsArray(value) == 0) { + return std::make_unique(); + } + + return std::make_unique(value); +} +} // namespace panda::ecmascript diff --git a/ecmascript/tooling/base/pt_json.h b/ecmascript/tooling/base/pt_json.h new file mode 100644 index 0000000000..7b376ea194 --- /dev/null +++ b/ecmascript/tooling/base/pt_json.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMASCRIPT_TOOLING_BASE_PT_JSON_H +#define ECMASCRIPT_TOOLING_BASE_PT_JSON_H + +#include +#include + +#include "cJSON.h" + +namespace panda::ecmascript::tooling { +class PtJson { +public: + PtJson() = default; + explicit PtJson(cJSON *object) : object_(object) {} + ~PtJson() = default; + + // Create empty json object + static std::unique_ptr CreateObject(); + static std::unique_ptr CreateArray(); + + // Release cJSON object memory + void ReleaseRoot(); + + // String parse to json + static std::unique_ptr Parse(const char *data); + + // To string + std::string Stringify() const; + + // Add Json child + bool Add(const char *key, bool value) const; + bool Add(const char *key, int32_t value) const; + bool Add(const char *key, int64_t value) const; + bool Add(const char *key, double value) const; + bool Add(const char *key, const char *value) const; + bool Add(const char *key, const std::unique_ptr &value) const; + + // Push back to array + bool Push(bool value) const; + bool Push(int32_t value) const; + bool Push(int64_t value) const; + bool Push(double value) const; + bool Push(const char *value) const; + bool Push(const std::unique_ptr &value) const; + + // Remove Json child + bool Remove(const char *key) const; + + bool Contains(const char *key) const; + + std::string GetKey() const; + + cJSON *GetJson() const; + + // Type check + bool IsBool() const; + bool IsNumber() const; + bool IsString() const; + bool IsObject() const; + bool IsArray() const; + bool IsNull() const; + + // Object accessor + bool GetBool(bool defaultValue = false) const; + int32_t GetInt(int32_t defaultValue = 0) const; + int64_t GetInt64(int64_t defaultValue = 0) const; + double GetDouble(double defaultValue = 0.0) const; + std::string GetString() const; + + // Array accessor + int32_t GetSize() const; + std::unique_ptr Get(int32_t index) const; + + // Child item accessor + bool GetBool(const char *key, bool defaultValue = false) const; + int32_t GetInt(const char *key, int32_t defaultValue = 0) const; + int64_t GetInt64(const char *key, int64_t defaultValue = 0) const; + double GetDouble(const char *key, double defaultValue = 0.0) const; + std::string GetString(const char *key, std::string defaultValue = "") const; + std::unique_ptr GetObject(const char *key) const; + std::unique_ptr GetArray(const char *key) const; + +private: + cJSON *object_ = nullptr; +}; +} // namespace panda::ecmascript + +#endif // ECMASCRIPT_TOOLING_BASE_PT_JSON_H diff --git a/ecmascript/tooling/test/BUILD.gn b/ecmascript/tooling/test/BUILD.gn index ce45a1e016..356de4942c 100644 --- a/ecmascript/tooling/test/BUILD.gn +++ b/ecmascript/tooling/test/BUILD.gn @@ -181,6 +181,7 @@ host_unittest_action("DebuggerTest") { "debugger_script_test.cpp", "debugger_types_test.cpp", "js_pt_hooks_test.cpp", + "pt_json_test.cpp", ] configs = [ "//ark/js_runtime:ecma_test_config" ] diff --git a/ecmascript/tooling/test/pt_json_test.cpp b/ecmascript/tooling/test/pt_json_test.cpp new file mode 100644 index 0000000000..0698a1653a --- /dev/null +++ b/ecmascript/tooling/test/pt_json_test.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecmascript/tests/test_helper.h" +#include "ecmascript/tooling/base/pt_json.h" + +using namespace panda::ecmascript::tooling; + +namespace panda::test { +class PtJsonTest : public testing::Test { +public: + static void SetUpTestCase() + { + GTEST_LOG_(INFO) << "SetUpTestCase"; + } + + static void TearDownTestCase() + { + GTEST_LOG_(INFO) << "TearDownCase"; + } + + void SetUp() override + { + } + + void TearDown() override + { + } +}; + +HWTEST_F_L0(PtJsonTest, FalseTest) +{ + std::string str = "false"; + std::unique_ptr json = PtJson::Parse(str.c_str()); + ASSERT_TRUE(json->IsBool()); + EXPECT_FALSE(json->GetBool()); + EXPECT_EQ(json->Stringify(), str); + json->ReleaseRoot(); +} + +HWTEST_F_L0(PtJsonTest, TrueTest) +{ + std::string str = "true"; + std::unique_ptr json = PtJson::Parse(str.c_str()); + ASSERT_TRUE(json->IsBool()); + EXPECT_TRUE(json->GetBool()); + EXPECT_EQ(json->Stringify(), str); + json->ReleaseRoot(); +} + +HWTEST_F_L0(PtJsonTest, IntTest) +{ + std::string str = "100"; + std::unique_ptr json = PtJson::Parse(str.c_str()); + ASSERT_TRUE(json->IsNumber()); + EXPECT_EQ(json->GetInt(), 100); + EXPECT_EQ(json->Stringify(), str); + json->ReleaseRoot(); +} + +HWTEST_F_L0(PtJsonTest, Int64Test) +{ + std::string str = "123456789012345"; + std::unique_ptr json = PtJson::Parse(str.c_str()); + ASSERT_TRUE(json->IsNumber()); + EXPECT_EQ(json->GetInt64(), 123456789012345); + EXPECT_EQ(json->Stringify(), str); + json->ReleaseRoot(); +} + +HWTEST_F_L0(PtJsonTest, DoubleTest) +{ + std::string str = "12345.6789"; + std::unique_ptr json = PtJson::Parse(str.c_str()); + ASSERT_TRUE(json->IsNumber()); + EXPECT_EQ(json->GetDouble(), 12345.6789); + EXPECT_EQ(json->Stringify(), str); + json->ReleaseRoot(); +} + +HWTEST_F_L0(PtJsonTest, StringTest) +{ + std::string str = "\"abcdefg\""; + std::unique_ptr json = PtJson::Parse(str.c_str()); + ASSERT_TRUE(json->IsString()); + EXPECT_EQ(json->GetString(), "abcdefg"); + EXPECT_EQ(json->Stringify(), str); + json->ReleaseRoot(); +} + +HWTEST_F_L0(PtJsonTest, ArrayTest) +{ + std::string str = "[\"a\",\"b\",200]"; + std::unique_ptr json = PtJson::Parse(str.c_str()); + ASSERT_TRUE(json->IsArray()); + EXPECT_EQ(json->GetSize(), 3); + EXPECT_EQ(json->Get(0)->GetString(), "a"); + EXPECT_EQ(json->Get(1)->GetString(), "b"); + EXPECT_EQ(json->Get(2)->GetInt(), 200); + EXPECT_EQ(json->Stringify(), str); + json->ReleaseRoot(); +} + +HWTEST_F_L0(PtJsonTest, ObjectTest) +{ + auto child1 = PtJson::CreateObject(); + child1->Add("ch", "child_1"); + ASSERT_TRUE(child1->Contains("ch")); + + auto child2 = PtJson::CreateObject(); + child2->Add("ch", "child_2"); + ASSERT_TRUE(child2->Contains("ch")); + + auto arr = PtJson::CreateArray(); + arr->Push(false); + arr->Push(100); + arr->Push(100.2); + arr->Push(static_cast(200)); + arr->Push("abc"); + arr->Push(child1); + EXPECT_EQ(arr->GetSize(), 6); + + auto root = PtJson::CreateObject(); + root->Add("a", false); + root->Add("b", 100); + root->Add("c", 100.2); + root->Add("d", static_cast(200)); + root->Add("e", "abc"); + root->Add("f", child2); + root->Add("g", arr); + + EXPECT_FALSE(root->GetBool("a")); + EXPECT_EQ(root->GetInt("b"), 100); + EXPECT_EQ(root->GetDouble("c"), 100.2); + EXPECT_EQ(root->GetInt64("d"), static_cast(200)); + EXPECT_EQ(root->GetString("e"), "abc"); + EXPECT_EQ(root->GetObject("f")->GetString("ch"), "child_2"); + ASSERT_TRUE(root->GetArray("g")->IsArray()); + EXPECT_FALSE(root->GetArray("g")->Get(0)->GetBool()); + EXPECT_EQ(root->GetArray("g")->Get(1)->GetInt(), 100); + EXPECT_EQ(root->GetArray("g")->Get(2)->GetDouble(), 100.2); + EXPECT_EQ(root->GetArray("g")->Get(3)->GetInt64(), static_cast(200)); + EXPECT_EQ(root->GetArray("g")->Get(4)->GetString(), "abc"); + EXPECT_EQ(root->GetArray("g")->Get(5)->GetString("ch"), "child_1"); + + EXPECT_EQ(root->Stringify(), + "{\"a\":false,\"b\":100,\"c\":100.2,\"d\":200,\"e\":\"abc\",\"f\":{\"ch\":\"child_2\"}," + "\"g\":[false,100,100.2,200,\"abc\",{\"ch\":\"child_1\"}]}"); + root->ReleaseRoot(); +} +} \ No newline at end of file -- Gitee