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