• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_CONTAINER_TEST_H
17 #define ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_CONTAINER_TEST_H
18 
19 #include "test/utils/test_util.h"
20 
21 namespace panda::ecmascript::tooling::test {
22 class JsContainerTest : public TestEvents {
23 public:
JsContainerTest()24     JsContainerTest()
25     {
26         breakpoint = [this](const JSPtLocation &location) {
27             ASSERT_TRUE(location.GetMethodId().IsValid());
28             ASSERT_LOCATION_EQ(location, location_);
29             ++breakpointCounter_;
30             debugger_->NotifyPaused(location, PauseReason::INSTRUMENTATION);
31             TestUtil::SuspendUntilContinue(DebugEvent::BREAKPOINT, location);
32             return true;
33         };
34 
35         loadModule = [this](std::string_view moduleName) {
36             std::string pandaFile = DEBUGGER_ABC_DIR "container.abc";
37             std::string sourceFile = DEBUGGER_JS_DIR "container.js";
38             static_cast<JsContainerTestChannel *>(channel_)->Initial(vm_, runtime_);
39             runtime_->Enable();
40             // 348: breakpointer line
41             location_ = TestUtil::GetLocation(sourceFile.c_str(), 348, 0, pandaFile.c_str());
42             ASSERT_TRUE(location_.GetMethodId().IsValid());
43             TestUtil::SuspendUntilContinue(DebugEvent::LOAD_MODULE);
44             ASSERT_EQ(moduleName, pandaFile);
45             ASSERT_TRUE(debugger_->NotifyScriptParsed(0, pandaFile));
46             auto condFuncRef = FunctionRef::Undefined(vm_);
47             auto ret = debugInterface_->SetBreakpoint(location_, condFuncRef);
48 
49             ASSERT_TRUE(ret);
50             return true;
51         };
52 
53         scenario = [this]() {
54             TestUtil::WaitForLoadModule();
55             TestUtil::Continue();
56             TestUtil::WaitForBreakpoint(location_);
57             TestUtil::Continue();
58             auto ret = debugInterface_->RemoveBreakpoint(location_);
59             ASSERT_TRUE(ret);
60             ASSERT_EXITED();
61             return true;
62         };
63 
64         vmDeath = [this]() {
65             ASSERT_EQ(breakpointCounter_, 1U);  // 1: break point counter
66             return true;
67         };
68 
69         channel_ = new JsContainerTestChannel();
70     }
71 
GetEntryPoint()72     std::pair<std::string, std::string> GetEntryPoint() override
73     {
74         std::string pandaFile = DEBUGGER_ABC_DIR "container.abc";
75         return {pandaFile, entryPoint_};
76     }
~JsContainerTest()77     ~JsContainerTest()
78     {
79         delete channel_;
80         channel_ = nullptr;
81     }
82 
83 private:
84     class JsContainerTestChannel : public TestChannel {
85     public:
86         JsContainerTestChannel() = default;
87         ~JsContainerTestChannel() = default;
Initial(const EcmaVM * vm,RuntimeImpl * runtime)88         void Initial(const EcmaVM *vm, RuntimeImpl *runtime)
89         {
90             vm_ = vm;
91             runtime_ = runtime;
92         }
93 
SendNotification(const PtBaseEvents & events)94         void SendNotification(const PtBaseEvents &events) override
95         {
96             const static std::vector<std::function<bool(const PtBaseEvents &events)>> eventList = {
97                 [](const PtBaseEvents &events) -> bool {
98                     std::string sourceFile = DEBUGGER_JS_DIR "container.js";
99                     auto parsed = static_cast<const ScriptParsed *>(&events);
100                     std::string str = parsed->ToJson()->Stringify();
101                     std::cout << "JsModuleVariableTestChannel: SendNotification 0:\n" << str << std::endl;
102 
103                     ASSERT_EQ(parsed->GetName(), "Debugger.scriptParsed");
104                     ASSERT_EQ(parsed->GetUrl(), sourceFile);
105                     return true;
106                 },
107                 [this](const PtBaseEvents &events) -> bool {
108                     auto paused = static_cast<const Paused *>(&events);
109                     std::string str = paused->ToJson()->Stringify();
110                     std::cout << "JsModuleVariableTestChannel: SendNotification 1:\n" << str << std::endl;
111 
112                     ASSERT_EQ(paused->GetName(), "Debugger.paused");
113                     auto frame = paused->GetCallFrames()->at(0).get();
114                     ASSERT_EQ(frame->GetFunctionName(), "foo");
115                     auto scopes = frame->GetScopeChain();
116                     ASSERT_EQ(scopes->size(), 2U);  // 2: contain local and global
117                     for (uint32_t i = 0; i < scopes->size(); i++) {
118                         auto scope = scopes->at(i).get();
119                         if (scope->GetType() != Scope::Type::Module()) {
120                             continue;
121                         }
122                         GetProperties(scope);
123                     }
124                     return true;
125                 }
126             };
127 
128             ASSERT_TRUE(eventList[index_](events));
129             index_++;
130         }
131 
GetProperties(panda::ecmascript::tooling::Scope * scope)132         void GetProperties(panda::ecmascript::tooling::Scope *scope)
133         {
134             auto localId = scope->GetObject()->GetObjectId();
135             GetPropertiesParams params;
136             params.SetObjectId(localId).SetOwnProperties(true);
137             std::vector<std::unique_ptr<PropertyDescriptor>> outPropertyDesc;
138             runtime_->GetProperties(params, &outPropertyDesc, {}, {}, {});
139             for (const auto &property : outPropertyDesc) {
140                 std::cout << "=====================================" << std::endl;
141                 std::cout << property->GetName() << std::endl;
142                 auto value = property->GetValue();
143                 std::vector<std::string> infos;
144                 PushValueInfo(value, infos);
145                 if (value->GetType() == RemoteObject::TypeName::Object) {
146                     std::vector<std::unique_ptr<PropertyDescriptor>> outPropertyDescInner;
147                     ASSERT_TRUE(value->HasObjectId());
148                     params.SetObjectId(value->GetObjectId()).SetOwnProperties(true);
149                     runtime_->GetProperties(params, &outPropertyDescInner, {}, {}, {});
150                     if (outPropertyDescInner.size() == 0) {
151                         infos.push_back("none");
152                     }
153                     for (const auto &propertyInner : outPropertyDescInner) {
154                         std::cout << "###########################################" << std::endl;
155                         std::cout << propertyInner->GetName() << std::endl;
156                         infos.push_back(propertyInner->GetName());
157                         auto innerValue = propertyInner->GetValue();
158                         PushValueInfo(innerValue, infos);
159                     }
160                 }
161                 ASSERT_EQ(infos.size(), variableMap_.at(property->GetName()).size());
162                 for (uint32_t j = 0; j < infos.size(); j++) {
163                     ASSERT_EQ(infos[j], variableMap_.at(property->GetName())[j]);
164                 }
165             }
166         }
167 
168     private:
169         NO_COPY_SEMANTIC(JsContainerTestChannel);
170         NO_MOVE_SEMANTIC(JsContainerTestChannel);
171 
PushValueInfo(RemoteObject * value,std::vector<std::string> & infos)172         void PushValueInfo(RemoteObject *value, std::vector<std::string> &infos)
173         {
174             std::cout << "type: " << value->GetType() << std::endl;
175             infos.push_back(value->GetType());
176             if (value->HasObjectId()) {
177                 std::cout << "id: " << value->GetObjectId() << std::endl;
178             }
179             if (value->HasSubType()) {
180                 std::cout << "sub type: " << value->GetSubType() << std::endl;
181                 infos.push_back(value->GetSubType());
182             }
183             if (value->HasClassName()) {
184                 std::cout << "class name: " << value->GetClassName() << std::endl;
185                 infos.push_back(value->GetClassName());
186             }
187             if (value->HasDescription()) {
188                 std::cout << "desc: " << value->GetDescription() << std::endl;
189                 infos.push_back(value->GetDescription());
190             }
191             if (value->HasValue()) {
192                 std::cout << "type: " <<
193                     value->GetValue()->Typeof(vm_)->ToString() << std::endl;
194                 std::cout << "tostring: " <<
195                     value->GetValue()->ToString(vm_)->ToString() << std::endl;
196                 infos.push_back(value->GetValue()->ToString(vm_)->ToString());
197             }
198         }
199 
200         /*
201         * Expect map type: map<name, value list>
202         * value list (optional):
203         *    type
204         *    subType
205         *    className
206         *    description
207         *    value tostring
208         *
209         * if is object value, will push back key and value.
210         *
211         * for example:
212         * var abc = 1
213         *     { "abc", { "number", "1", "1" } }
214         * var obj = { "key": "2" }
215         *     { "obj0", { "object", "Object", "Object", "[object Object]", "key", "string", "2", "2" } }
216         */
217         const std::map<std::string, std::vector<std::string>> variableMap_ = {
218             { "nop", { "undefined" } },
219             { "foo", { "function", "Function", "function foo( { [js code] }",
220                        "Cannot get source code of funtion" } },
221             { "ArrayList", { "function", "Function", "function ArrayList( { [native code] }",
222                              "function ArrayList() { [native code] }" } },
223             { "Deque", { "function", "Function", "function Deque( { [native code] }",
224                          "function Deque() { [native code] }" } },
225             { "HashMap", { "function", "Function", "function HashMap( { [native code] }",
226                            "function HashMap() { [native code] }" } },
227             { "HashSet", { "function", "Function", "function HashSet( { [native code] }",
228                            "function HashSet() { [native code] }" } },
229             { "LightWeightMap", { "function", "Function", "function LightWeightMap( { [native code] }",
230                                   "function LightWeightMap() { [native code] }" } },
231             { "LightWeightSet", { "function", "Function", "function LightWeightSet( { [native code] }",
232                                   "function LightWeightSet() { [native code] }" } },
233             { "LinkedList", { "function", "Function", "function LinkedList( { [native code] }",
234                               "function LinkedList() { [native code] }" } },
235             { "List", { "function", "Function", "function List( { [native code] }",
236                         "function List() { [native code] }" } },
237             { "PlainArray", { "function", "Function", "function PlainArray( { [native code] }",
238                               "function PlainArray() { [native code] }" } },
239             { "Queue", { "function", "Function", "function Queue( { [native code] }",
240                          "function Queue() { [native code] }" } },
241             { "Stack", { "function", "Function", "function Stack( { [native code] }",
242                          "function Stack() { [native code] }" } },
243             { "TreeMap", { "function", "Function", "function TreeMap( { [native code] }",
244                            "function TreeMap() { [native code] }" } },
245             { "TreeSet", { "function", "Function", "function TreeSet( { [native code] }",
246                            "function TreeSet() { [native code] }" } },
247             { "Vector", { "function", "Function", "function Vector( { [native code] }",
248                           "function Vector() { [native code] }" } },
249             { "arrayList", { "object", "Object", "ArrayList", "[object ArrayList]", "size", "number", "6", "6",
250                              "[[ArrayList]]", "object", "array", "Array", "Array(6)", "8,15,3,10,288,188" } },
251             { "deque", { "object", "Object", "Deque", "[object Deque]", "size", "number", "10", "10", "[[Deque]]",
252                          "object", "array", "Array", "Array(10)", "1888,5,3,13,1888,17,888,387,666,177" } },
253             { "hashMap", { "object", "Object", "HashMap", "[object HashMap]", "size", "number", "1", "1",
254                            "[[HashMap]]", "object", "array", "Array", "Array(1)", "[object Object]" } },
255             { "hashSet", { "object", "Object", "HashSet", "[object HashSet]", "size", "number", "14",
256                            "14", "[[HashSet]]", "object", "array", "Array", "Array(14)",
257                            "17,1888,0,99,one,four,433,5,18,112,8,38,537,three" } },
258             { "lightWeightMap", { "object", "Object", "LightWeightMap", "0:0", "size", "number", "1", "1",
259                                   "[[LightWeightMap]]", "object", "array", "Array", "Array(1)", "[object Object]" } },
260             { "lightWeightSet", { "object", "Object", "LightWeightSet", "4,66,388,566,578,593,855,100,one,four,three",
261                                   "size", "number", "11", "11", "[[LightWeightSet]]", "object", "array", "Array",
262                                   "Array(11)", "4,66,388,566,578,593,855,100,one,four,three" } },
263             { "linkedList", { "object", "Object", "LinkedList", "[object Object]", "size", "number",
264                               "9", "9", "[[LinkedList]]", "object", "array", "Array", "Array(9)",
265                               "588,388,one,88,3989,1888,888,187,two" } },
266             { "list", { "object", "Object", "List", "[object Object]", "size", "number",
267                         "12", "12", "[[List]]", "object", "array", "Array", "Array(12)",
268                         "18,changge,2,527,0,changge,three,88,changge,18,100,322" } },
269             { "plainArray", { "object", "Object", "PlainArray", "8:8", "size", "number", "1", "1",
270                               "[[PlainArray]]", "object", "array", "Array", "Array(1)", "[object Object]" } },
271             { "queue", { "object", "Object", "Queue", "[object Queue]", "size", "number", "8", "8", "[[Queue]]",
272                          "object", "array", "Array", "Array(8)", "3,2888,1,555,857,eleven,999,male" } },
273             { "stack", { "object", "Object", "Stack", "[object Stack]", "size", "number", "7", "7", "[[Stack]]",
274                          "object", "array", "Array", "Array(7)", "5,18,3,28,1,one,888" } },
275             { "treeMap", { "object", "Object", "TreeMap", "[object TreeMap]", "size", "number", "1", "1",
276                            "[[TreeMap]]", "object", "array", "Array", "Array(1)", "[object Object]" } },
277             { "treeSet", { "object", "Object", "TreeSet", "[object TreeSet]", "size", "number",
278                            "9", "9", "[[TreeSet]]", "object", "array", "Array", "Array(9)",
279                            "5,18,99,377,588,888,1388,11199,array" } },
280             { "vector", { "object", "Object", "Vector", "857,33,change,male,999,change,999,one", "size",
281                           "number", "8", "8", "[[Vector]]", "object", "array", "Array", "Array(8)",
282                           "857,33,change,male,999,change,999,one" } },
283             { "boolean0", { "boolean", "false", "false" } },
284             { "boolean1", { "boolean", "true", "true" } },
285             { "boolean2", { "boolean", "false", "false" } },
286             { "boolean3", { "boolean", "true", "true" } },
287             { "number0", { "number", "1888", "1888" } },
288             { "number1", { "number", "177", "177" } },
289             { "number2", { "number", "-1", "-1" } },
290             { "number3", { "number", "-1", "-1" } },
291             { "number4", { "number", "222", "222" } },
292             { "number5", { "number", "-2", "-2" } },
293             { "number6", { "number", "566", "566" } },
294             { "number7", { "number", "588", "588" } },
295             { "number8", { "number", "588", "588" } },
296             { "number9", { "number", "0", "0" } },
297             { "number10", { "number", "-1", "-1" } },
298             { "number11", { "number", "88", "88" } },
299             { "number12", { "number", "18", "18" } },
300             { "number13", { "number", "322", "322" } },
301             { "number14", { "number", "8", "8" } },
302             { "number15", { "number", "4", "4" } },
303             { "number16", { "number", "8", "8" } },
304             { "number17", { "number", "5", "5" } },
305             { "number18", { "number", "188", "188" } },
306             { "number19", { "number", "8", "8" } },
307             { "number20", { "number", "388", "388" } },
308             { "number21", { "number", "0", "0" } },
309             { "number22", { "number", "5", "5" } },
310             { "number23", { "number", "18", "18" } },
311             { "number24", { "number", "1388", "1388" } },
312             { "number25", { "number", "6", "6" } },
313             { "number26", { "number", "0", "0" } },
314             { "number27", { "number", "857", "857" } },
315             { "string0", { "string", "two", "two" } },
316             { "string1", { "string", "change", "change" } },
317             { "string2", { "string", "three", "three" } },
318             { "string3", { "string", "array", "array" } },
319             { "string4", { "string", "male", "male" } },
320             { "string5", { "string", "one", "one" } },
321         };
322 
323         int32_t index_ {0};
324         const EcmaVM *vm_ {nullptr};
325         RuntimeImpl *runtime_ {nullptr};
326     };
327 
328     std::string entryPoint_ = "_GLOBAL::func_main_0";
329     JSPtLocation location_ {nullptr, JSPtLocation::EntityId(0), 0};
330     size_t breakpointCounter_ = 0;
331 };
332 
GetJsContainerTest()333 std::unique_ptr<TestEvents> GetJsContainerTest()
334 {
335     return std::make_unique<JsContainerTest>();
336 }
337 }  // namespace panda::ecmascript::tooling::test
338 
339 #endif  // ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_CONTAINER_TEST_H
340