diff --git a/test/resource/tooling/ohos_test.xml b/test/resource/tooling/ohos_test.xml
index 9e668cf91476ec7e3abeefa3b4793ebfc5b9c077..d46d0c77bef28eb4be034256b9ed7c5ad73a99e3 100755
--- a/test/resource/tooling/ohos_test.xml
+++ b/test/resource/tooling/ohos_test.xml
@@ -24,6 +24,7 @@
+
diff --git a/tooling/agent/debugger_impl.cpp b/tooling/agent/debugger_impl.cpp
index 48f066f3e72092f7a1b74da210a2d62855ffcae9..654bfab21662c65149d86319bd82a83e3b0a889a 100644
--- a/tooling/agent/debugger_impl.cpp
+++ b/tooling/agent/debugger_impl.cpp
@@ -1040,17 +1040,17 @@ void DebuggerImpl::GetLocalVariables(const FrameHandler *frameHandler, panda_fil
bool hasThis = false;
for (const auto &[varName, regIndex] : extractor->GetLocalVariableTable(methodId)) {
value = DebuggerApi::GetVRegValue(vm_, frameHandler, regIndex);
- if (varName == "4newTarget" || varName == "=nt") {
+ if (varName == "4newTarget") {
continue;
}
- if (varName == "this" || varName == "=t") {
+ if (varName == "this") {
thisVal = value;
hasThis = true;
continue;
}
Local name = JSValueRef::Undefined(vm_);
- if (varName == "4funcObj" || varName == "=f") {
+ if (varName == "4funcObj") {
if (value->IsFunction()) {
auto funcName = Local(value)->GetName(vm_)->ToString();
name = StringRef::NewFromUtf8(vm_, funcName.c_str());
@@ -1076,12 +1076,12 @@ void DebuggerImpl::GetLocalVariables(const FrameHandler *frameHandler, panda_fil
JSThread *thread = vm_->GetJSThread();
for (const auto &[varName, slot] : scopeDebugInfo->scopeInfo) {
// skip possible duplicate variables both in local variable table and env
- if (varName == "4newTarget" || varName == "=nt") {
+ if (varName == "4newTarget") {
continue;
}
value = JSNApiHelper::ToLocal(
JSHandle(thread, lexEnv->GetProperties(slot)));
- if (varName == "this" || varName == "=t") {
+ if (varName == "this") {
if (!hasThis) {
thisVal = value;
}
diff --git a/tooling/test/BUILD.gn b/tooling/test/BUILD.gn
index c4da48d65699fdb71248224ff56e36c16da7b1a3..c1dc84dd0afe36c80fcd1b334024b235378da95a 100644
--- a/tooling/test/BUILD.gn
+++ b/tooling/test/BUILD.gn
@@ -45,6 +45,7 @@ test_js_files = [
"syntax_exception",
"throw_exception",
"variable",
+ "module_variable",
]
foreach(file, test_js_files) {
@@ -57,6 +58,10 @@ foreach(file, test_js_files) {
src_js = rebase_path(test_js)
dst_file = rebase_path(test_abc)
extra_args = [ "--debug" ]
+ if (file == "module_variable") {
+ extra_args += [ "--module" ]
+ extra_args += [ "--merge-abc" ]
+ }
in_puts = [ test_js ]
out_puts = [ test_abc ]
diff --git a/tooling/test/testcases/js/module_variable.js b/tooling/test/testcases/js/module_variable.js
new file mode 100644
index 0000000000000000000000000000000000000000..39952581901200aa9a4fbf43b78ecb156f102e4a
--- /dev/null
+++ b/tooling/test/testcases/js/module_variable.js
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+export var number0 = 1;
+export var count1 = 30;
+export var number5 = 10;
+export var elemnt = 50;
+export var count = 80;
+export var high = 110;
+
+export function foo() {
+ var number1 = count;
+ var number2 = number5;
+ var number3 = elemnt;
+ var number4 = 50;
+}
+
+foo();
\ No newline at end of file
diff --git a/tooling/test/testcases/js_module_variable_test.h b/tooling/test/testcases/js_module_variable_test.h
new file mode 100644
index 0000000000000000000000000000000000000000..45be22597e46923d901651e826ab49ddfcd2090d
--- /dev/null
+++ b/tooling/test/testcases/js_module_variable_test.h
@@ -0,0 +1,245 @@
+/*
+ * 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_TEST_UTILS_TESTCASES_JS_MODULE_VARIABLE_TEST_H
+#define ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_MODULE_VARIABLE_TEST_H
+
+#include "test/utils/test_util.h"
+
+namespace panda::ecmascript::tooling::test {
+std::string gg_pandaFile = DEBUGGER_ABC_DIR "module_variable.abc";
+std::string gg_sourceFile = DEBUGGER_JS_DIR "module_variable.js";
+std::string_view gg_entry = "module_variable";
+
+class JsModuleVariableTest : public TestEvents {
+public:
+ JsModuleVariableTest()
+ {
+ breakpoint = [this](const JSPtLocation &location) {
+ ASSERT_TRUE(location.GetMethodId().IsValid());
+ ASSERT_LOCATION_EQ(location, location_);
+ ++breakpointCounter_;
+ debugger_->NotifyPaused(location, PauseReason::INSTRUMENTATION);
+ TestUtil::SuspendUntilContinue(DebugEvent::BREAKPOINT, location);
+ return true;
+ };
+
+ loadModule = [this](std::string_view moduleName) {
+ static_cast(channel_)->Initial(vm_, runtime_);
+ // 25: breakpointer line
+ location_ = TestUtil::GetLocation(gg_sourceFile.c_str(), 25, 0, gg_pandaFile.c_str());
+ ASSERT_TRUE(location_.GetMethodId().IsValid());
+ TestUtil::SuspendUntilContinue(DebugEvent::LOAD_MODULE);
+ ASSERT_EQ(moduleName, gg_pandaFile);
+ ASSERT_TRUE(debugger_->NotifyScriptParsed(0, gg_pandaFile, gg_entry));
+ auto condFuncRef = FunctionRef::Undefined(vm_);
+ auto ret = debugInterface_->SetBreakpoint(location_, condFuncRef);
+ ASSERT_TRUE(ret);
+ return true;
+ };
+
+ scenario = [this]() {
+ TestUtil::WaitForLoadModule();
+ TestUtil::Continue();
+ TestUtil::WaitForBreakpoint(location_);
+ TestUtil::Continue();
+ auto ret = debugInterface_->RemoveBreakpoint(location_);
+ ASSERT_TRUE(ret);
+ ASSERT_EXITED();
+ return true;
+ };
+
+ vmDeath = [this]() {
+ ASSERT_EQ(breakpointCounter_, 1U); // 1: break point counter
+ return true;
+ };
+
+ channel_ = new JsModuleVariableTestChannel();
+ }
+
+ std::pair GetEntryPoint() override
+ {
+ return {gg_pandaFile, entryPoint_};
+ }
+ ~JsModuleVariableTest()
+ {
+ delete channel_;
+ channel_ = nullptr;
+ }
+
+private:
+ class JsModuleVariableTestChannel : public TestChannel {
+ public:
+ JsModuleVariableTestChannel() = default;
+ ~JsModuleVariableTestChannel() = default;
+ void Initial(const EcmaVM *vm, RuntimeImpl *runtime)
+ {
+ vm_ = vm;
+ runtime_ = runtime;
+ }
+
+ void SendNotification(const PtBaseEvents &events) override
+ {
+ const static std::vector> eventList = {
+ [](const PtBaseEvents &events) -> bool {
+ auto parsed = static_cast(&events);
+ std::string str = parsed->ToJson()->Stringify();
+ std::cout << "JsModuleVariableTestChannel: SendNotification 0:\n" << str << std::endl;
+
+ ASSERT_EQ(parsed->GetName(), "Debugger.scriptParsed");
+ ASSERT_EQ(parsed->GetUrl(), gg_sourceFile);
+ return true;
+ },
+ [this](const PtBaseEvents &events) -> bool {
+ auto paused = static_cast(&events);
+ std::string str = paused->ToJson()->Stringify();
+ std::cout << "JsModuleVariableTestChannel: SendNotification 1:\n" << str << std::endl;
+
+ ASSERT_EQ(paused->GetName(), "Debugger.paused");
+ auto frame = paused->GetCallFrames()->at(0).get();
+ ASSERT_EQ(frame->GetFunctionName(), "foo");
+ auto scopes = frame->GetScopeChain();
+ ASSERT_EQ(scopes->size(), 3U); // 2: contain local and global
+ for (uint32_t i = 0; i < scopes->size(); i++) {
+ auto scope = scopes->at(i).get();
+ if (scope->GetType() != Scope::Type::Module()) {
+ continue;
+ }
+ GetModuleProperties(scope);
+ }
+ return true;
+ }
+ };
+
+ ASSERT_TRUE(eventList[index_](events));
+ index_++;
+ }
+
+ void GetModuleProperties(panda::ecmascript::tooling::Scope *scope)
+ {
+ auto localId = scope->GetObject()->GetObjectId();
+ GetPropertiesParams params;
+ params.SetObjectId(localId).SetOwnProperties(true);
+ std::vector> outPropertyDesc;
+ runtime_->GetProperties(params, &outPropertyDesc, {}, {}, {});
+ for (const auto &property : outPropertyDesc) {
+ std::cout << "=====================================" << std::endl;
+ std::cout << property->GetName() << std::endl;
+ auto value = property->GetValue();
+ std::vector infos;
+ PushValueInfo(value, infos);
+ if (value->GetType() == RemoteObject::TypeName::Object) {
+ std::vector> outPropertyDescInner;
+ ASSERT_TRUE(value->HasObjectId());
+ params.SetObjectId(value->GetObjectId()).SetOwnProperties(true);
+ runtime_->GetProperties(params, &outPropertyDescInner, {}, {}, {});
+ if (outPropertyDescInner.size() == 0) {
+ infos.push_back("none");
+ }
+ for (const auto &propertyInner : outPropertyDescInner) {
+ std::cout << "###########################################" << std::endl;
+ std::cout << propertyInner->GetName() << std::endl;
+ infos.push_back(propertyInner->GetName());
+ auto innerValue = propertyInner->GetValue();
+ PushValueInfo(innerValue, infos);
+ }
+ }
+ ASSERT_EQ(infos.size(), moduleVariableMap_.at(property->GetName()).size());
+ for (uint32_t j = 0; j < infos.size(); j++) {
+ ASSERT_EQ(infos[j], moduleVariableMap_.at(property->GetName())[j]);
+ }
+ }
+ }
+
+ private:
+ NO_COPY_SEMANTIC(JsModuleVariableTestChannel);
+ NO_MOVE_SEMANTIC(JsModuleVariableTestChannel);
+
+ void PushValueInfo(RemoteObject *value, std::vector &infos)
+ {
+ std::cout << "type: " << value->GetType() << std::endl;
+ infos.push_back(value->GetType());
+ if (value->HasObjectId()) {
+ std::cout << "id: " << value->GetObjectId() << std::endl;
+ }
+ if (value->HasSubType()) {
+ std::cout << "sub type: " << value->GetSubType() << std::endl;
+ infos.push_back(value->GetSubType());
+ }
+ if (value->HasClassName()) {
+ std::cout << "class name: " << value->GetClassName() << std::endl;
+ infos.push_back(value->GetClassName());
+ }
+ if (value->HasDescription()) {
+ std::cout << "desc: " << value->GetDescription() << std::endl;
+ infos.push_back(value->GetDescription());
+ }
+ if (value->HasValue()) {
+ std::cout << "type: " <<
+ value->GetValue()->Typeof(vm_)->ToString() << std::endl;
+ std::cout << "tostring: " <<
+ value->GetValue()->ToString(vm_)->ToString() << std::endl;
+ infos.push_back(value->GetValue()->ToString(vm_)->ToString());
+ }
+ }
+
+ /*
+ * Expect map type: map
+ * value list (optional):
+ * type
+ * subType
+ * className
+ * description
+ * value tostring
+ *
+ * if is object value, will push back key and value.
+ *
+ * for example:
+ * var abc = 1
+ * { "abc", { "number", "1", "1" } }
+ * var obj = { "key": "2" }
+ * { "obj0", { "object", "Object", "Object", "[object Object]", "key", "string", "2", "2" } }
+ */
+ const std::map> moduleVariableMap_ = {
+ { "number0", { "number", "1", "1" } },
+ { "count1", { "number", "30", "30" } },
+ { "number5", { "number", "10", "10" } },
+ { "elemnt", { "number", "50", "50" } },
+ { "count", { "number", "80", "80" } },
+ { "high", { "number", "110", "110" } },
+ { "foo", { "function", "Function", "function foo( { [js code] }", "Cannot get source code of funtion"} },
+ { "number1", { "number", "80", "80" } },
+ { "number2", { "number", "10", "10" } },
+ { "number3", { "number", "50", "50" } },
+ { "number4", { "number", "50", "50" } },
+ };
+
+ int32_t index_ {0};
+ const EcmaVM *vm_ {nullptr};
+ RuntimeImpl *runtime_ {nullptr};
+ };
+
+ std::string entryPoint_ = "module_variable";
+ JSPtLocation location_ {nullptr, JSPtLocation::EntityId(0), 0};
+ size_t breakpointCounter_ = 0;
+};
+
+std::unique_ptr GetJsModuleVariableTest()
+{
+ return std::make_unique();
+}
+} // namespace panda::ecmascript::tooling::test
+
+#endif // ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_VARIABLE_TEST_H
diff --git a/tooling/test/utils/test_list.cpp b/tooling/test/utils/test_list.cpp
index 954c48e4d5238cbd6ae8e6aa5b2c55b5c29a73ec..0ae76e84f7e3e27ec3b0a0fb14e868925e0e7fa4 100644
--- a/tooling/test/utils/test_list.cpp
+++ b/tooling/test/utils/test_list.cpp
@@ -30,6 +30,7 @@
#include "test/testcases/js_syntax_exception_test.h"
#include "test/testcases/js_throw_exception_test.h"
#include "test/testcases/js_variable_test.h"
+#include "test/testcases/js_module_variable_test.h"
namespace panda::ecmascript::tooling::test {
static std::string g_currentTestName = "";
@@ -49,6 +50,7 @@ static void RegisterTests()
TestUtil::RegisterTest("JsStepOverTest", GetJsStepOverTest());
TestUtil::RegisterTest("JsStepOutTest", GetJsStepOutTest());
TestUtil::RegisterTest("JsVariableTest", GetJsVariableTest());
+ TestUtil::RegisterTest("JsModuleVariableTest", GetJsModuleVariableTest());
}
std::vector GetTestList()