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_SYMBOLICBREAKPOINT_LOOP_TEST_H
17 #define ECMASCRIPT_TOOLING_TEST_TESTCASES_JS_SYMBOLICBREAKPOINT_LOOP_TEST_H
18
19 #include "tooling/dynamic/test/client_utils/test_util.h"
20
21 namespace panda::ecmascript::tooling::test {
22 class JsSymbolicBreakpointTest : public TestActions {
23 public:
JsSymbolicBreakpointTest()24 JsSymbolicBreakpointTest()
25 {
26 testAction = {
27 {SocketAction::SEND, "enable"},
28 {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
29 {SocketAction::SEND, "runtime-enable"},
30 {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
31 {SocketAction::SEND, "run"},
32 {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
33 // load common_func.js
34 {SocketAction::RECV, "Debugger.scriptParsed", ActionRule::STRING_CONTAIN},
35 // break on start
36 {SocketAction::RECV, "Debugger.paused", ActionRule::STRING_CONTAIN},
37 // set symbol breakpoints
38 {SocketAction::SEND, "setSymbolicBreakpoints " "common_func"},
39 {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
40 {SocketAction::SEND, "setSymbolicBreakpoints " "for_loop"},
41 {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
42
43 // hit the common_func function
44 {SocketAction::SEND, "resume"},
45 {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
46 {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
47 {SocketAction::RECV, "Debugger.paused", ActionRule::CUSTOM_RULE,
48 [this](auto recv, auto, auto) -> bool { return RecvBreakInfo(recv, "common_func", 16); }},
49
50 // set symbol breakpoints
51 {SocketAction::SEND, "setSymbolicBreakpoints " "while_loop"},
52 {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
53
54 // hit the for_loop function
55 {SocketAction::SEND, "resume"},
56 {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
57 {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
58 {SocketAction::RECV, "Debugger.paused", ActionRule::CUSTOM_RULE,
59 [this](auto recv, auto, auto) -> bool { return RecvBreakInfo(recv, "for_loop", 26); }},
60
61 // set symbol breakpoints
62 {SocketAction::SEND, "setSymbolicBreakpoints " "while_loop"},
63 {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
64
65 // hit the while_loop function
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 RecvBreakInfo(recv, "while_loop", 34); }},
71
72 // set symbol breakpoints
73 {SocketAction::SEND, "setSymbolicBreakpoints " "loop_switch"},
74 {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
75
76 // hit the loop_switch function
77 {SocketAction::SEND, "resume"},
78 {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
79 {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
80 {SocketAction::RECV, "Debugger.paused", ActionRule::STRING_CONTAIN},
81
82 // set symbol breakpoints
83 {SocketAction::SEND, "setSymbolicBreakpoints " "factorial"},
84 {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
85
86 // firstly hit the factorial function
87 {SocketAction::SEND, "resume"},
88 {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
89 {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
90 {SocketAction::RECV, "Debugger.paused", ActionRule::CUSTOM_RULE,
91 [this](auto recv, auto, auto) -> bool { return RecvBreakInfo(recv, "factorial", 57); }},
92
93 // remove symbol breakpoints
94 {SocketAction::SEND, "removeSymbolicBreakpoints " "loop_switch"},
95 {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
96
97 // secondly hit the factorial function
98 {SocketAction::SEND, "resume"},
99 {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
100 {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
101 {SocketAction::RECV, "Debugger.paused", ActionRule::CUSTOM_RULE,
102 [this](auto recv, auto, auto) -> bool { return RecvBreakInfo(recv, "factorial", 57); }},
103
104 // remove symbol breakpoints
105 {SocketAction::SEND, "removeSymbolicBreakpoints " "factorial"},
106 {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
107
108 // reply success and run
109 {SocketAction::SEND, "success"},
110 {SocketAction::SEND, "resume"},
111 {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
112 {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
113 };
114 }
115
RecvBreakInfo(std::string recv,std::string funcName,int lineNumber)116 bool RecvBreakInfo(std::string recv, std::string funcName, int lineNumber)
117 {
118 std::unique_ptr<PtJson> json = PtJson::Parse(recv);
119 Result ret;
120 std::string method = "";
121 ret = json->GetString("method", &method);
122 if (ret != Result::SUCCESS || method != "Debugger.paused") {
123 return false;
124 }
125
126 std::unique_ptr<PtJson> params = nullptr;
127 ret = json->GetObject("params", ¶ms);
128 if (ret != Result::SUCCESS) {
129 return false;
130 }
131
132 std::unique_ptr<PtJson> callFrames = nullptr;
133 ret = params->GetArray("callFrames", &callFrames);
134 if (ret != Result::SUCCESS) {
135 return false;
136 }
137
138 std::string functionName = "";
139 ret = callFrames->Get(0)->GetString("functionName", &functionName);
140 if (ret != Result::SUCCESS || functionName != funcName) {
141 return false;
142 }
143
144 std::unique_ptr<PtJson> location = nullptr;
145 ret = callFrames->Get(0)->GetObject("location", &location);
146 if (ret != Result::SUCCESS) {
147 return false;
148 }
149
150 int lineNum = 0;
151 ret = location->GetInt("lineNumber", &lineNum);
152 if (ret != Result::SUCCESS || lineNum != lineNumber) {
153 return false;
154 }
155
156 DebuggerClient debuggerClient(0);
157 debuggerClient.PausedReply(std::move(json));
158 return true;
159 }
160
GetEntryPoint()161 std::pair<std::string, std::string> GetEntryPoint() override
162 {
163 return {pandaFile_, entryPoint_};
164 }
165 ~JsSymbolicBreakpointTest() = default;
166
167 private:
168 std::string pandaFile_ = DEBUGGER_ABC_DIR "common_func.abc";
169 std::string sourceFile_ = DEBUGGER_JS_DIR "common_func.js";
170 std::string entryPoint_ = "common_func";
171 };
172
GetJsSymbolicBreakpointTest()173 std::unique_ptr<TestActions> GetJsSymbolicBreakpointTest()
174 {
175 return std::make_unique<JsSymbolicBreakpointTest>();
176 }
177 } // namespace panda::ecmascript::tooling::test
178
179 #endif // ECMASCRIPT_TOOLING_TEST_TESTCASES_JS_SYMBOLICBREAKPOINT_LOOP_TEST_H