• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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_TESTCASES_JS_ASYNC_STACK_TEST_H
17 #define ECMASCRIPT_TOOLING_TEST_TESTCASES_JS_ASYNC_STACK_TEST_H
18 
19 #include "tooling/dynamic/test/client_utils/test_util.h"
20 
21 namespace panda::ecmascript::tooling::test {
22 class JsAsynStackTest : public TestActions {
23 public:
JsAsynStackTest()24     JsAsynStackTest()
25     {
26         testAction = {
27             {SocketAction::SEND, "enable"},
28             {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
29             // open stack trace
30             {SocketAction::SEND, "setAsyncStackDepth"},
31             {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
32             {SocketAction::SEND, "runtime-enable"},
33             {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
34             {SocketAction::SEND, "run"},
35             {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
36             // load promise.js
37             {SocketAction::RECV, "Debugger.scriptParsed", ActionRule::STRING_CONTAIN},
38             // break on start
39             {SocketAction::RECV, "Debugger.paused", ActionRule::STRING_CONTAIN},
40             // set breakpoint
41             {SocketAction::SEND, "b " DEBUGGER_JS_DIR "promise.js 21"},
42             {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
43             {SocketAction::SEND, "b " DEBUGGER_JS_DIR "promise.js 24"},
44             {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
45             {SocketAction::SEND, "b " DEBUGGER_JS_DIR "promise.js 32"},
46             {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
47             {SocketAction::SEND, "b " DEBUGGER_JS_DIR "promise.js 35"},
48             {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
49             {SocketAction::SEND, "b " DEBUGGER_JS_DIR "promise.js 50"},
50             {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
51             {SocketAction::SEND, "b " DEBUGGER_JS_DIR "promise.js 69"},
52             // hit breakpoint
53             {SocketAction::SEND, "resume"},
54             {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
55             {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
56             {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
57             {SocketAction::RECV, "Debugger.paused", ActionRule::CUSTOM_RULE,
58                 [this](auto recv, auto, auto) -> bool { return RecvAsyncMessageInfo(recv, 20, 19); }},
59             // hit breakpoint
60             {SocketAction::SEND, "resume"},
61             {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
62             {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
63             {SocketAction::RECV, "Debugger.paused", ActionRule::CUSTOM_RULE,
64                 [this](auto recv, auto, auto) -> bool { return RecvAsyncMessageInfo(recv, 23, 22); }},
65             // hit breakpoint
66             {SocketAction::SEND, "resume"},
67             {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
68             {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
69             {SocketAction::RECV, "Debugger.paused", ActionRule::CUSTOM_RULE,
70                 [this](auto recv, auto, auto) -> bool { return RecvAsyncMessageInfo(recv, 31, 30); }},
71             // hit breakpoint
72             {SocketAction::SEND, "resume"},
73             {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
74             {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
75             {SocketAction::RECV, "Debugger.paused", ActionRule::CUSTOM_RULE,
76                 [this](auto recv, auto, auto) -> bool { return RecvAsyncMessageInfo(recv, 34, 33); }},
77             // hit breakpoint
78             {SocketAction::SEND, "resume"},
79             {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
80             {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
81             {SocketAction::RECV, "Debugger.paused", ActionRule::CUSTOM_RULE,
82                 [this](auto recv, auto, auto) -> bool { return RecvAsyncMessageInfo(recv, 68, 61); }},
83             // hit breakpoint
84             {SocketAction::SEND, "resume"},
85             {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
86             {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
87             // promise2.then -> promise3.then
88             // 46: promise2.then
89             // 48: promise3.then
90             // 49: current location
91             {SocketAction::RECV, "Debugger.paused", ActionRule::CUSTOM_RULE,
92                 [this](auto recv, auto, auto) -> bool { return RecvMultipleAsyncMessageInfo(recv, 49, 48, 46); }},
93             // reply success and run
94             {SocketAction::SEND, "success"},
95             {SocketAction::SEND, "resume"},
96             {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
97             {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
98         };
99     }
100 
RecvAsyncMessageInfo(std::string recv,int line,int asyncLine)101     bool RecvAsyncMessageInfo(std::string recv, int line, int asyncLine)
102     {
103         std::unique_ptr<PtJson> json = PtJson::Parse(recv);
104         Result ret;
105         std::string method = "";
106         ret = json->GetString("method", &method);
107         if (ret != Result::SUCCESS || method != "Debugger.paused") {
108             return false;
109         }
110 
111         std::unique_ptr<PtJson> params = nullptr;
112         ret = json->GetObject("params", &params);
113         if (ret != Result::SUCCESS) {
114             return false;
115         }
116 
117         std::unique_ptr<PtJson> hitBreakpoints = nullptr;
118         ret = params->GetArray("hitBreakpoints", &hitBreakpoints);
119         if (ret != Result::SUCCESS) {
120             return false;
121         }
122 
123         std::string breakpoint = "";
124         breakpoint = hitBreakpoints->Get(0)->GetString();
125         if (ret != Result::SUCCESS || breakpoint.find(sourceFile_) == std::string::npos ||
126             breakpoint.find(std::to_string(line)) == std::string::npos) {
127             std::cout << breakpoint << std::endl;
128             LOG_DEBUGGER(ERROR) << breakpoint;
129             return false;
130         }
131 
132         std::unique_ptr<PtJson> asyncStackTrace = nullptr;
133         ret = params->GetObject("asyncStackTrace", &asyncStackTrace);
134         if (ret != Result::SUCCESS) {
135             return false;
136         }
137 
138         std::unique_ptr<PtJson> callFrames = nullptr;
139         ret = asyncStackTrace->GetArray("callFrames", &callFrames);
140         if (ret != Result::SUCCESS) {
141             return false;
142         }
143 
144         std::unique_ptr<PtJson> callFrame = nullptr;
145         callFrame = callFrames->Get(0);
146         if (ret != Result::SUCCESS) {
147             return false;
148         }
149 
150         int lineNumber = 0;
151         callFrame->GetInt("lineNumber", &lineNumber);
152         if (ret != Result::SUCCESS) {
153             return false;
154         }
155         std::string sourceFile;
156         ret = callFrame->GetString("url", &sourceFile);
157         if (ret != Result::SUCCESS) {
158             return false;
159         }
160         if (ret != Result::SUCCESS || sourceFile.find(sourceFile_) == std::string::npos || lineNumber != asyncLine) {
161             return false;
162         }
163 
164         std::unique_ptr<PtJson> asyncParent = nullptr;
165 
166         return true;
167     }
168 
RecvMultipleAsyncMessageInfo(std::string recv,int line,int asyncLine,int asyncParentLine)169     bool RecvMultipleAsyncMessageInfo(std::string recv, int line, int asyncLine, int asyncParentLine)
170     {
171         std::unique_ptr<PtJson> json = PtJson::Parse(recv);
172         Result ret;
173         std::string method = "";
174         ret = json->GetString("method", &method);
175         if (ret != Result::SUCCESS || method != "Debugger.paused") {
176             return false;
177         }
178 
179         std::unique_ptr<PtJson> params = nullptr;
180         ret = json->GetObject("params", &params);
181         if (ret != Result::SUCCESS) {
182             return false;
183         }
184 
185         std::unique_ptr<PtJson> hitBreakpoints = nullptr;
186         ret = params->GetArray("hitBreakpoints", &hitBreakpoints);
187         if (ret != Result::SUCCESS) {
188             return false;
189         }
190 
191         std::string breakpoint = "";
192         breakpoint = hitBreakpoints->Get(0)->GetString();
193         if (ret != Result::SUCCESS || breakpoint.find(sourceFile_) == std::string::npos ||
194             breakpoint.find(std::to_string(line)) == std::string::npos) {
195             std::cout << breakpoint << std::endl;
196             LOG_DEBUGGER(ERROR) << breakpoint;
197             return false;
198         }
199 
200         // test promise3.then
201         std::unique_ptr<PtJson> asyncStackTrace = nullptr;
202         ret = params->GetObject("asyncStackTrace", &asyncStackTrace);
203         if (ret != Result::SUCCESS) {
204             return false;
205         }
206 
207         std::unique_ptr<PtJson> callFrames = nullptr;
208         ret = asyncStackTrace->GetArray("callFrames", &callFrames);
209         if (ret != Result::SUCCESS) {
210             return false;
211         }
212 
213         ret = asyncStackTrace->GetArray("callFrames", &callFrames);
214         if (ret != Result::SUCCESS) {
215             return false;
216         }
217 
218         std::unique_ptr<PtJson> callFrame = nullptr;
219         callFrame = callFrames->Get(0);
220         if (ret != Result::SUCCESS) {
221             return false;
222         }
223 
224         int lineNumber = 0;
225         ret = callFrame->GetInt("lineNumber", &lineNumber);
226         if (ret != Result::SUCCESS) {
227             return false;
228         }
229         std::string sourceFile;
230         ret = callFrame->GetString("url", &sourceFile);
231         if (ret != Result::SUCCESS) {
232             return false;
233         }
234 
235         if (ret != Result::SUCCESS || sourceFile.find(sourceFile_) == std::string::npos ||
236             lineNumber != asyncLine) {
237             return false;
238         }
239 
240         // test promise2.then
241         std::unique_ptr<PtJson> asyncParent = nullptr;
242         ret = asyncStackTrace->GetObject("parent", &asyncParent);
243         if (ret != Result::SUCCESS) {
244             return false;
245         }
246 
247         ret = asyncParent->GetArray("callFrames", &callFrames);
248         if (ret != Result::SUCCESS) {
249             return false;
250         }
251 
252         callFrame = callFrames->Get(0);
253         if (ret != Result::SUCCESS) {
254             return false;
255         }
256 
257         ret = callFrame->GetInt("lineNumber", &lineNumber);
258         if (ret != Result::SUCCESS) {
259             return false;
260         }
261 
262         ret = callFrame->GetString("url", &sourceFile);
263         if (ret != Result::SUCCESS) {
264             return false;
265         }
266 
267         if (ret != Result::SUCCESS || sourceFile.find(sourceFile_) == std::string::npos ||
268             lineNumber != asyncParentLine) {
269             return false;
270         }
271         return true;
272     }
273 
GetEntryPoint()274     std::pair<std::string, std::string> GetEntryPoint() override
275     {
276         return {pandaFile_, entryPoint_};
277     }
278     ~JsAsynStackTest() = default;
279 
280 private:
281     std::string pandaFile_ = DEBUGGER_ABC_DIR "promise.abc";
282     std::string sourceFile_ = DEBUGGER_JS_DIR "promise.js";
283     std::string entryPoint_ = "promise";
284 };
285 
GetJsAsynStackTest()286 std::unique_ptr<TestActions> GetJsAsynStackTest()
287 {
288     return std::make_unique<JsAsynStackTest>();
289 }
290 } // namespace panda::ecmascript::tooling::test
291 
292 #endif // ECMASCRIPT_TOOLING_TEST_TESTCASES_JS_ASYNC_STACK_TEST_H
293