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_DROP_FRAME_TEST_H
17 #define ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_DROP_FRAME_TEST_H
18
19 #include "test/utils/test_util.h"
20
21 namespace panda::ecmascript::tooling::test {
22 class JsDropFrameTest : public TestEvents {
23 public:
JsDropFrameTest()24 JsDropFrameTest()
25 {
26 channel_ = new JsDropFrameTestChannel();
27
28 breakpoint = [this](const JSPtLocation &location) {
29 ASSERT_TRUE(location.GetMethodId().IsValid());
30 ++breakpointCounter_;
31 debugger_->NotifyPaused(location, PauseReason::INSTRUMENTATION);
32 static_cast<JsDropFrameTestChannel *>(channel_)->IncreaseCheckVariableCounter();
33 DropFrameIfChecked();
34 TestUtil::SuspendUntilContinue(DebugEvent::BREAKPOINT, location);
35 return true;
36 };
37
38 singleStep = [this](const JSPtLocation &location) {
39 if (debugger_->NotifySingleStep(location)) {
40 debugger_->NotifyPaused({}, PauseReason::INSTRUMENTATION);
41 static_cast<JsDropFrameTestChannel *>(channel_)->IncreaseCheckVariableCounter();
42 TestUtil::SuspendUntilContinue(DebugEvent::CHECK_COMPLETE);
43 DropFrameIfChecked();
44 TestUtil::SuspendUntilContinue(DebugEvent::DROPFRAME);
45 return true;
46 }
47 return false;
48 };
49
50 loadModule = [this](std::string_view moduleName) {
51 static_cast<JsDropFrameTestChannel *>(channel_)->Initial(vm_, runtime_);
52 runtime_->Enable();
53 size_t breakpoint[POINTER_SIZE][LINE_COLUMN] =
54 {{26, 0}, {42, 0}, {57, 0}, {69, 0}, {87, 0}, {100, 0}, {117, 0}}; // 0-based
55 SetJSPtLocation(breakpoint[0], POINTER_SIZE, pointerLocations_);
56 InitBreakpointOpQueue();
57 TestUtil::SuspendUntilContinue(DebugEvent::LOAD_MODULE);
58 ASSERT_EQ(moduleName, pandaFile_);
59 ASSERT_TRUE(debugger_->NotifyScriptParsed(0, pandaFile_));
60 auto condFuncRef = FunctionRef::Undefined(vm_);
61 for (auto &iter : pointerLocations_) {
62 auto ret = debugInterface_->SetBreakpoint(iter, condFuncRef);
63 ASSERT_TRUE(ret);
64 }
65 return true;
66 };
67
68 scenario = [this]() {
69 TestUtil::WaitForLoadModule();
70 TestUtil::Continue();
71 for (size_t index = 0; index < POINTER_SIZE; index++) {
72 for (size_t hitCount = 0; hitCount < breakpointHitTimes[index]; hitCount++) {
73 TestUtil::WaitForBreakpoint(pointerLocations_.at(index));
74 TestUtil::Continue();
75 while (dropFrameChecked_) {
76 dropFrameChecked_ = false;
77 TestUtil::WaitForCheckComplete();
78 TestUtil::Continue();
79 TestUtil::WaitForDropframe();
80 dropframeCounter_++;
81 TestUtil::Continue();
82 }
83 }
84 auto ret = debugInterface_->RemoveBreakpoint(pointerLocations_.at(index));
85 ASSERT_TRUE(ret);
86 }
87 ASSERT_EXITED();
88 return true;
89 };
90
91 vmDeath = [this]() {
92 ASSERT_EQ(breakpointCounter_, 29U); // a total of 29 times hitting breakpoints
93 ASSERT_EQ(dropframeCounter_, 23U); // a total of 23 times dropping frames
94 return true;
95 };
96 }
97
GetEntryPoint()98 std::pair<std::string, std::string> GetEntryPoint() override
99 {
100 return {pandaFile_, entryPoint_};
101 }
~JsDropFrameTest()102 ~JsDropFrameTest()
103 {
104 delete channel_;
105 channel_ = nullptr;
106 }
107
108 private:
109 class JsDropFrameTestChannel : public TestChannel {
110 public:
111 JsDropFrameTestChannel() = default;
112 ~JsDropFrameTestChannel() = default;
Initial(const EcmaVM * vm,RuntimeImpl * runtime)113 void Initial(const EcmaVM *vm, RuntimeImpl *runtime)
114 {
115 vm_ = vm;
116 runtime_ = runtime;
117 }
118
SendNotification(const PtBaseEvents & events)119 void SendNotification(const PtBaseEvents &events) override
120 {
121 const static std::vector<std::function<bool(const PtBaseEvents &events)>> eventList = {
122 [](const PtBaseEvents &events) -> bool {
123 std::string sourceFile = DEBUGGER_JS_DIR "dropframe.js";
124 auto parsed = static_cast<const ScriptParsed *>(&events);
125 ASSERT_EQ(parsed->GetName(), "Debugger.scriptParsed");
126 ASSERT_EQ(parsed->GetUrl(), sourceFile);
127 return true;
128 },
129 [this](const PtBaseEvents &events) -> bool {
130 std::cout << checkVariableCounter_ << std::endl;
131 auto paused = static_cast<const Paused *>(&events);
132 ASSERT_EQ(paused->GetName(), "Debugger.paused");
133 auto allFrames = paused->GetCallFrames();
134 std::map<std::string, std::string> truthVariableMap = variableMap_.at(checkVariableCounter_);
135 for (size_t index = 0; index < allFrames->size(); index++) {
136 auto frame = paused->GetCallFrames()->at(index).get();
137 auto scopes = frame->GetScopeChain();
138 for (uint32_t i = 0; i < scopes->size(); i++) {
139 auto scope = scopes->at(i).get();
140 if (scope->GetType() != Scope::Type::Local()) {
141 continue;
142 }
143 auto localId = scope->GetObject()->GetObjectId();
144 GetPropertiesParams params;
145 params.SetObjectId(localId).SetOwnProperties(true);
146 std::vector<std::unique_ptr<PropertyDescriptor>> outPropertyDesc;
147 runtime_->GetProperties(params, &outPropertyDesc, {}, {}, {});
148 for (const auto &property : outPropertyDesc) {
149 std::cout << "=====================================" << std::endl;
150 std::string name = property->GetName();
151 std::cout << name << std::endl;
152 if (truthVariableMap.count(name)) {
153 auto value = property->GetValue();
154 if (value->HasValue()) {
155 std::string valueStr = value->GetValue()->ToString(vm_)->ToString();
156 std::cout << valueStr << std::endl;
157 ASSERT_EQ(valueStr, truthVariableMap[name]);
158 }
159 }
160 }
161 }
162 }
163 return true;
164 }
165 };
166
167 ASSERT_TRUE(eventList[index_](events));
168 index_ |= 1;
169 }
170
IncreaseCheckVariableCounter()171 void IncreaseCheckVariableCounter()
172 {
173 checkVariableCounter_++;
174 }
175
176 private:
177 NO_COPY_SEMANTIC(JsDropFrameTestChannel);
178 NO_MOVE_SEMANTIC(JsDropFrameTestChannel);
179
180 const std::vector<std::map<std::string, std::string>> variableMap_ = {
181 { { "a", "2" }, { "b", "3" }, { "c", "4" }, {"d", "2"} },
182 { { "a", "2" }, { "b", "3" }, { "c", "3" }, {"d", "1"} },
183 { { "a", "2" }, { "b", "2" }, { "c", "3" }, {"d", "0"} },
184 { { "a", "1" }, { "b", "2" }, { "c", "3" } },
185 { { "a", "2" }, { "b", "3" }, { "c", "4" }, {"d", "2"} },
186 { { "a", "4" }, { "b", "5" }, { "c", "6" }, {"d", "2"} },
187 { { "a", "6" }, { "b", "4" }, { "c", "5" }, {"d", "2"} },
188 { { "a", "6" }, { "b", "4" }, { "c", "5" }, {"d", "1"} },
189 { { "a", "2" }, { "b", "3" }, { "c", "4" } },
190 { { "a", "4" }, { "b", "5" }, { "c", "6" }, {"d", "2"} },
191 { { "a", "8" }, { "b", "13" }, { "c", "78" }, {"d", "1"} },
192 { { "a", "4" }, { "b", "5" }, { "c", "6" }, {"d", "1"} },
193 { { "a", "8" }, { "b", "13" }, { "c", "78" }, {"d", "1"} },
194 { { "a", "16" }, { "b", "29" }, { "c", "2262" }, {"d", "182"} },
195 { { "a", "8" }, { "b", "13" }, { "c", "78" }, {"d", "182"} },
196 { { "a", "4" }, { "b", "5" }, { "c", "6" } },
197 { { "a", "8" }, { "b", "13" }, { "c", "78" }, {"d", "1"} },
198 { { "a", "32" }, { "b", "61" }, { "c", "4214" }, {"d", "1"} },
199 { { "a", "16" }, { "b", "29" }, { "c", "2262" }, {"d", "1"} },
200 { { "a", "32" }, { "b", "61" }, { "c", "4214" }, {"d", "1"} },
201 { { "a", "64" }, { "b", "125" }, { "c", "12214" }, {"d", "29"} },
202 { { "a", "128" }, { "b", "253" }, { "c", "44598" }, {"d", "1769"} },
203 { { "a", "256" }, { "b", "509" }, { "c", "174902" }, {"d", "221125"} },
204 { { "a", "128" }, { "b", "253" }, { "c", "44598" }, {"d", "221125"} },
205 { { "a", "16" }, { "b", "29" }, { "c", "2262" } },
206 { { "a", "32" }, { "b", "61" }, { "c", "4214" }, {"d", "1"} },
207 { { "a", "256" }, { "b", "1277" }, { "c", "176435" } },
208 { { "a", "256" }, { "b", "509" }, { "c", "174902" } },
209 { { "a", "256" }, { "b", "509" }, { "c", "174902" } },
210 { { "a", "256" }, { "b", "1277" }, { "c", "176435" } },
211 { { "a", "256" }, { "b", "2301" }, { "c", "178992" } },
212 { { "a", "512" }, { "b", "3837" }, { "c", "183341" } },
213 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" } },
214 { { "a", "512" }, { "b", "3837" }, { "c", "183341" } },
215 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" } },
216 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" }, {"s", "2"} },
217 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" }, {"s", "2"} },
218 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" } },
219 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" } },
220 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" } },
221 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" }, {"s", "2"} },
222 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" }, {"s", "3"} },
223 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" } },
224 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" }, {"s", "3"} },
225 { { "a", "10" }, { "b", "7933" }, { "c", "192298" }, {"x", "7"} },
226 { { "a", "9" }, { "b", "7933" }, { "c", "192298" }, {"x", "7"} },
227 { { "a", "8" }, { "b", "7933" }, { "c", "192298" }, {"x", "7"} },
228 { { "a", "10" }, { "b", "7933" }, { "c", "192298" }, {"x", "7"} },
229 { { "a", "11" }, { "b", "7933" }, { "c", "192298" }, {"x", "7"} },
230 { { "a", "12" }, { "b", "7933" }, { "c", "192298" }, {"x", "7"} },
231 { { "a", "7" }, { "b", "7933" }, { "c", "192298" }, {"x", "7"} },
232 { { "a", "10" }, { "b", "7933" }, { "c", "192298" }, {"x", "7"} }
233 };
234
235 int32_t index_ {0};
236 const EcmaVM *vm_ {nullptr};
237 RuntimeImpl *runtime_ {nullptr};
238 size_t checkVariableCounter_ {0};
239 };
240
241 enum breakpointOpType {
242 RESUME = 1,
243 DROPLASTFRAME = 2
244 };
245
246 static constexpr size_t LINE_COLUMN = 2;
247 static constexpr size_t POINTER_SIZE = 7;
248
249 std::string pandaFile_ = DEBUGGER_ABC_DIR "dropframe.abc";
250 std::string sourceFile_ = DEBUGGER_JS_DIR "dropframe.js";
251 std::string entryPoint_ = "_GLOBAL::func_main_0";
252 size_t breakpointCounter_ = 0;
253 size_t dropframeCounter_ = 0;
254 bool dropFrameChecked_ = false;
255 std::vector<JSPtLocation> pointerLocations_;
256 size_t breakpointHitTimes[POINTER_SIZE] = {2, 2, 4, 6, 6, 4, 5};
257 std::queue<std::pair<uint8_t, uint8_t>> breakpointOp;
258
InitBreakpointOpQueue()259 void InitBreakpointOpQueue()
260 {
261 breakpointOp.push({1, breakpointOpType::DROPLASTFRAME});
262 breakpointOp.push({1, breakpointOpType::DROPLASTFRAME});
263 breakpointOp.push({1, breakpointOpType::DROPLASTFRAME});
264 breakpointOp.push({3, breakpointOpType::DROPLASTFRAME});
265 breakpointOp.push({3, breakpointOpType::DROPLASTFRAME});
266 breakpointOp.push({3, breakpointOpType::DROPLASTFRAME});
267 breakpointOp.push({5, breakpointOpType::DROPLASTFRAME});
268 breakpointOp.push({7, breakpointOpType::DROPLASTFRAME});
269 breakpointOp.push({7, breakpointOpType::DROPLASTFRAME});
270 breakpointOp.push({9, breakpointOpType::DROPLASTFRAME});
271 breakpointOp.push({13, breakpointOpType::DROPLASTFRAME});
272 breakpointOp.push({13, breakpointOpType::DROPLASTFRAME});
273 breakpointOp.push({15, breakpointOpType::DROPLASTFRAME});
274 breakpointOp.push({15, breakpointOpType::DROPLASTFRAME});
275 breakpointOp.push({19, breakpointOpType::DROPLASTFRAME});
276 breakpointOp.push({21, breakpointOpType::DROPLASTFRAME});
277 breakpointOp.push({21, breakpointOpType::DROPLASTFRAME});
278 breakpointOp.push({21, breakpointOpType::DROPLASTFRAME});
279 breakpointOp.push({21, breakpointOpType::DROPLASTFRAME});
280 breakpointOp.push({23, breakpointOpType::DROPLASTFRAME});
281 breakpointOp.push({25, breakpointOpType::DROPLASTFRAME});
282 breakpointOp.push({25, breakpointOpType::DROPLASTFRAME});
283 breakpointOp.push({28, breakpointOpType::DROPLASTFRAME});
284 }
285
DropFrameIfChecked()286 void DropFrameIfChecked()
287 {
288 while (!dropFrameChecked_ && !breakpointOp.empty() && breakpointOp.front().first == breakpointCounter_) {
289 if (breakpointOp.front().second == breakpointOpType::DROPLASTFRAME) {
290 PtJson paramsJson;
291 paramsJson.Add("droppedDepth", 1U);
292 std::unique_ptr<DropFrameParams> params = DropFrameParams::Create(paramsJson);
293 debugger_->DropFrame(*params);
294 dropFrameChecked_ = true;
295 }
296 breakpointOp.pop();
297 }
298 }
299
SetJSPtLocation(size_t * arr,size_t number,std::vector<JSPtLocation> & locations)300 void SetJSPtLocation(size_t *arr, size_t number, std::vector<JSPtLocation> &locations)
301 {
302 for (size_t i = 0; i < number; i++) {
303 JSPtLocation location = TestUtil::GetLocation(sourceFile_.c_str(), arr[i * LINE_COLUMN],
304 arr[i * LINE_COLUMN + 1], pandaFile_.c_str());
305 locations.push_back(location);
306 }
307 };
308 };
309
GetJsDropFrameTest()310 std::unique_ptr<TestEvents> GetJsDropFrameTest()
311 {
312 return std::make_unique<JsDropFrameTest>();
313 }
314 } // namespace panda::ecmascript::tooling::test
315
316 #endif // ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_DROP_FRAME_TEST_H
317