1 /**
2 * Copyright (c) 2023-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 #include "inspector_server.h"
17
18 #include "gmock/gmock.h"
19 #include "gtest/gtest.h"
20
21 #include "assembly-emitter.h"
22 #include "assembly-parser.h"
23 #include "runtime.h"
24 #include "types/location.h"
25 #include "utils/json_builder.h"
26
27 #include "connection/server.h"
28
29 #include "common.h"
30 #include "json_object_matcher.h"
31
32 // NOLINTBEGIN
33
34 using namespace std::placeholders;
35
36 namespace ark::tooling::inspector::test {
37
38 class TestServer : public Server {
39 public:
OnValidate(std::function<void ()> && handler)40 void OnValidate([[maybe_unused]] std::function<void()> &&handler) override {};
OnOpen(std::function<void ()> && handler)41 void OnOpen([[maybe_unused]] std::function<void()> &&handler) override {};
OnFail(std::function<void ()> && handler)42 void OnFail([[maybe_unused]] std::function<void()> &&handler) override {};
43
Call(const std::string & session,const char * method_call,std::function<void (JsonObjectBuilder &)> && parameters)44 void Call(const std::string &session, const char *method_call,
45 std::function<void(JsonObjectBuilder &)> &¶meters) override
46 {
47 std::string tmp(method_call);
48 CallMock(session, tmp, std::move(parameters));
49 }
50
OnCall(const char * method_call,Handler && handler)51 void OnCall(const char *method_call, Handler &&handler) override
52 {
53 std::string tmp(method_call);
54 OnCallMock(tmp, std::move(handler));
55 }
56
57 MOCK_METHOD(void, CallMock,
58 (const std::string &session, const std::string &method_call,
59 std::function<void(JsonObjectBuilder &)> &¶meters));
60
61 MOCK_METHOD(void, OnCallMock, (const std::string &method_call, Handler &&handler));
62
RunOne()63 bool RunOne() override
64 {
65 return true;
66 };
67 };
68
69 static PtThread g_mthread = PtThread(PtThread::NONE);
70 static const std::string g_sessionId;
71 static const std::string g_sourceFile = "source";
72 static bool g_handlerCalled = false;
73
74 class ServerTest : public testing::Test {
75 public:
SetUp()76 void SetUp() override
77 {
78 RuntimeOptions options;
79 options.SetShouldInitializeIntrinsics(false);
80 options.SetShouldLoadBootPandaFiles(false);
81 Runtime::Create(options);
82 g_mthread = PtThread(ManagedThread::GetCurrent());
83 g_handlerCalled = false;
84 }
TearDown()85 void TearDown() override
86 {
87 Runtime::Destroy();
88 }
89 TestServer server;
90 InspectorServer inspectorServer {server};
91 };
92
TEST_F(ServerTest,CallDebuggerResumed)93 TEST_F(ServerTest, CallDebuggerResumed)
94 {
95 inspectorServer.CallTargetAttachedToTarget(g_mthread);
96 EXPECT_CALL(server, CallMock(g_sessionId, "Debugger.resumed", testing::_)).Times(1);
97
98 inspectorServer.CallDebuggerResumed(g_mthread);
99 }
100
TEST_F(ServerTest,CallDebuggerScriptParsed)101 TEST_F(ServerTest, CallDebuggerScriptParsed)
102 {
103 inspectorServer.CallTargetAttachedToTarget(g_mthread);
104
105 size_t scriptId = 4;
106 EXPECT_CALL(server, CallMock(g_sessionId, "Debugger.scriptParsed", testing::_))
107 .WillOnce([&](testing::Unused, testing::Unused, auto s) {
108 ASSERT_THAT(ToObject(std::move(s)),
109 JsonProperties(JsonProperty<JsonObject::NumT> {"executionContextId", 0},
110 JsonProperty<JsonObject::StringT> {"scriptId", std::to_string(scriptId)},
111 JsonProperty<JsonObject::NumT> {"startLine", 0},
112 JsonProperty<JsonObject::NumT> {"startColumn", 0},
113 JsonProperty<JsonObject::NumT> {"endLine", std::numeric_limits<int>::max()},
114 JsonProperty<JsonObject::NumT> {"endColumn", std::numeric_limits<int>::max()},
115 JsonProperty<JsonObject::StringT> {"hash", ""},
116 JsonProperty<JsonObject::StringT> {"url", g_sourceFile.c_str()}));
117 });
118 inspectorServer.CallDebuggerScriptParsed(ScriptId(scriptId), g_sourceFile);
119 }
120
121 using ResultHolder = std::optional<JsonObject>;
122
GetResult(Expected<std::unique_ptr<JsonSerializable>,JRPCError> && returned,ResultHolder & result)123 static void GetResult(Expected<std::unique_ptr<JsonSerializable>, JRPCError> &&returned, ResultHolder &result)
124 {
125 ASSERT_TRUE(returned.HasValue());
126 if (returned.Value() != nullptr) {
127 JsonObjectBuilder builder;
128 returned.Value()->Serialize(builder);
129 result.emplace(std::move(builder).Build());
130 } else {
131 result.emplace("{}");
132 }
133 }
134
TEST_F(ServerTest,DebuggerEnable)135 TEST_F(ServerTest, DebuggerEnable)
136 {
137 TestServer server1;
138 EXPECT_CALL(server1, OnCallMock("Debugger.enable", testing::_)).WillOnce([&](testing::Unused, auto handler) {
139 JsonObject empty;
140 auto res = handler(g_sessionId, empty);
141 ResultHolder result;
142 GetResult(std::move(res), result);
143 std::vector<testing::Matcher<JsonObject::JsonObjPointer>> protocols;
144 ASSERT_THAT(*result,
145 JsonProperties(JsonProperty<JsonObject::NumT> {"debuggerId", 0},
146 JsonProperty<JsonObject::ArrayT> {"protocols", JsonElementsAreArray(protocols)}));
147 });
148 InspectorServer inspector_server1(server1);
149 inspector_server1.OnCallDebuggerEnable([] {});
150 }
151
__anon9a312da50402(auto unused, auto handler) 152 static auto g_simpleHandler = []([[maybe_unused]] auto unused, auto handler) {
153 JsonObject empty;
154 auto res = handler(g_sessionId, empty);
155 ResultHolder result;
156 GetResult(std::move(res), result);
157 ASSERT_THAT(*result, JsonProperties());
158 ASSERT_TRUE(g_handlerCalled);
159 };
160
TEST_F(ServerTest,OnCallDebuggerPause)161 TEST_F(ServerTest, OnCallDebuggerPause)
162 {
163 inspectorServer.CallTargetAttachedToTarget(g_mthread);
164
165 EXPECT_CALL(server, OnCallMock("Debugger.pause", testing::_)).WillOnce(g_simpleHandler);
166 inspectorServer.OnCallDebuggerPause([](PtThread thread) {
167 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
168 g_handlerCalled = true;
169 });
170 }
171
TEST_F(ServerTest,OnCallDebuggerRemoveBreakpoint)172 TEST_F(ServerTest, OnCallDebuggerRemoveBreakpoint)
173 {
174 size_t break_id = 14;
175
176 inspectorServer.CallTargetAttachedToTarget(g_mthread);
177
178 EXPECT_CALL(server, OnCallMock("Debugger.removeBreakpoint", testing::_))
179 .WillOnce([&](testing::Unused, auto handler) {
180 JsonObject empty;
181 auto res = handler(g_sessionId, empty);
182 ASSERT_FALSE(res.HasValue());
183 ASSERT_FALSE(g_handlerCalled);
184 });
185
186 auto breaks = [break_id](PtThread thread, BreakpointId bid) {
187 ASSERT_EQ(bid, BreakpointId(break_id));
188 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
189 g_handlerCalled = true;
190 };
191 inspectorServer.OnCallDebuggerRemoveBreakpoint(std::move(breaks));
192
193 EXPECT_CALL(server, OnCallMock("Debugger.removeBreakpoint", testing::_))
194 .WillOnce([&](testing::Unused, auto handler) {
195 JsonObjectBuilder params;
196 params.AddProperty("breakpointId", std::to_string(break_id));
197 auto res = handler(g_sessionId, JsonObject(std::move(params).Build()));
198 ResultHolder result;
199 GetResult(std::move(res), result);
200 ASSERT_THAT(*result, JsonProperties());
201 ASSERT_TRUE(g_handlerCalled);
202 });
203
204 inspectorServer.OnCallDebuggerRemoveBreakpoint(std::move(breaks));
205 }
206
TEST_F(ServerTest,OnCallDebuggerRestartFrame)207 TEST_F(ServerTest, OnCallDebuggerRestartFrame)
208 {
209 size_t fid = 5;
210
211 inspectorServer.CallTargetAttachedToTarget(g_mthread);
212
213 EXPECT_CALL(server, OnCallMock("Debugger.restartFrame", testing::_)).WillOnce([&](testing::Unused, auto handler) {
214 std::vector<testing::Matcher<JsonObject::JsonObjPointer>> callFrames;
215 JsonObjectBuilder params;
216 auto res = handler(g_sessionId, JsonObject(std::move(params).Build()));
217 ASSERT_FALSE(res.HasValue());
218 ASSERT_FALSE(g_handlerCalled);
219 });
220
221 inspectorServer.OnCallDebuggerRestartFrame([&](auto, auto) { g_handlerCalled = true; });
222
223 EXPECT_CALL(server, OnCallMock("Debugger.restartFrame", testing::_)).WillOnce([&](testing::Unused, auto handler) {
224 std::vector<testing::Matcher<JsonObject::JsonObjPointer>> callFrames;
225 JsonObjectBuilder params;
226 params.AddProperty("callFrameId", std::to_string(fid));
227 auto res = handler(g_sessionId, JsonObject(std::move(params).Build()));
228 ResultHolder result;
229 GetResult(std::move(res), result);
230 ASSERT_THAT(*result,
231 JsonProperties(JsonProperty<JsonObject::ArrayT> {"callFrames", JsonElementsAreArray(callFrames)}));
232 ASSERT_TRUE(g_handlerCalled);
233 });
234
235 inspectorServer.OnCallDebuggerRestartFrame([&](PtThread thread, FrameId id) {
236 ASSERT_EQ(id, FrameId(fid));
237 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
238 g_handlerCalled = true;
239 });
240 }
241
TEST_F(ServerTest,OnCallDebuggerResume)242 TEST_F(ServerTest, OnCallDebuggerResume)
243 {
244 inspectorServer.CallTargetAttachedToTarget(g_mthread);
245
246 EXPECT_CALL(server, OnCallMock("Debugger.resume", testing::_)).WillOnce(g_simpleHandler);
247 inspectorServer.OnCallDebuggerResume([](PtThread thread) {
248 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
249 g_handlerCalled = true;
250 });
251 }
252
CreatePossibleBreakpointsRequest(ScriptId startScriptId,size_t start,ScriptId endScriptId,size_t end,bool restrictToFunction)253 static JsonObject CreatePossibleBreakpointsRequest(ScriptId startScriptId, size_t start, ScriptId endScriptId,
254 size_t end, bool restrictToFunction)
255 {
256 JsonObjectBuilder params;
257 params.AddProperty("start", Location(startScriptId, start));
258 params.AddProperty("end", Location(endScriptId, end));
259 params.AddProperty("restrictToFunction", restrictToFunction);
260 return JsonObject(std::move(params).Build());
261 }
262
263 static auto g_getPossibleBreakpointsHandler = [](ScriptId scriptId, size_t start, size_t end, bool restrictToFunction,
__anon9a312da50e02(ScriptId scriptId, size_t start, size_t end, bool restrictToFunction, testing::Unused, auto handler) 264 testing::Unused, auto handler) {
265 auto res =
266 handler(g_sessionId, CreatePossibleBreakpointsRequest(scriptId, start, scriptId, end, restrictToFunction));
267 ResultHolder result;
268 GetResult(std::move(res), result);
269 std::vector<testing::Matcher<JsonObject::JsonObjPointer>> locations;
270 for (auto i = start; i < end; i++) {
271 locations.push_back(
272 testing::Pointee(JsonProperties(JsonProperty<JsonObject::StringT> {"scriptId", std::to_string(scriptId)},
273 JsonProperty<JsonObject::NumT> {"lineNumber", i})));
274 }
275 ASSERT_THAT(*result,
276 JsonProperties(JsonProperty<JsonObject::ArrayT> {"locations", JsonElementsAreArray(locations)}));
277 };
278
DefaultFrameEnumerator(const InspectorServer::FrameInfoHandler & handler)279 static void DefaultFrameEnumerator(const InspectorServer::FrameInfoHandler &handler)
280 {
281 std::optional<RemoteObject> objThis;
282 auto scope_chain = std::vector {Scope(Scope::Type::LOCAL, RemoteObject::Number(72))};
283 handler(FrameId(0), std::to_string(0), g_sourceFile, 0, scope_chain, objThis);
284 }
285
TEST_F(ServerTest,OnCallDebuggerGetPossibleBreakpoints)286 TEST_F(ServerTest, OnCallDebuggerGetPossibleBreakpoints)
287 {
288 auto scriptId = 0;
289 size_t start = 5;
290 size_t end = 5;
291
292 inspectorServer.CallTargetAttachedToTarget(g_mthread);
293 inspectorServer.CallDebuggerPaused(g_mthread, {}, {}, PauseReason::OTHER, DefaultFrameEnumerator);
294
295 EXPECT_CALL(server, OnCallMock("Debugger.getPossibleBreakpoints", testing::_))
296 .WillOnce(std::bind(g_getPossibleBreakpointsHandler, scriptId, start, end, // NOLINT(modernize-avoid-bind)
297 true, _1, _2));
298 auto getLinesTrue = [](std::string_view source, size_t startLine, size_t endLine, bool restrictToFunction) {
299 std::set<size_t> result;
300 if ((source == g_sourceFile) && restrictToFunction) {
301 for (auto i = startLine; i < endLine; i++) {
302 result.insert(i);
303 }
304 }
305 return result;
306 };
307 inspectorServer.OnCallDebuggerGetPossibleBreakpoints(getLinesTrue);
308
309 EXPECT_CALL(server, OnCallMock("Debugger.getPossibleBreakpoints", testing::_))
310 .WillOnce(std::bind(g_getPossibleBreakpointsHandler, scriptId, start, end, // NOLINT(modernize-avoid-bind)
311 false, _1, _2));
312 auto getLinesFalse = [](std::string_view source, size_t startLine, size_t endLine, bool restrictToFunction) {
313 std::set<size_t> result;
314 if ((source == g_sourceFile) && !restrictToFunction) {
315 for (auto i = startLine; i < endLine; i++) {
316 result.insert(i);
317 }
318 }
319 return result;
320 };
321 inspectorServer.OnCallDebuggerGetPossibleBreakpoints(getLinesFalse);
322
323 EXPECT_CALL(server, OnCallMock("Debugger.getPossibleBreakpoints", testing::_))
324 .WillOnce([&](testing::Unused, auto handler) {
325 auto res =
326 handler(g_sessionId, CreatePossibleBreakpointsRequest(scriptId, start, scriptId + 1, end, false));
327 ASSERT_FALSE(res.HasValue());
328 });
329 inspectorServer.OnCallDebuggerGetPossibleBreakpoints(getLinesFalse);
330 }
331
TEST_F(ServerTest,OnCallDebuggerGetScriptSource)332 TEST_F(ServerTest, OnCallDebuggerGetScriptSource)
333 {
334 auto scriptId = 0;
335
336 EXPECT_CALL(server, CallMock(g_sessionId, "Debugger.paused", testing::_))
337 .WillOnce([&](testing::Unused, testing::Unused, auto s) { ToObject(std::move(s)); });
338
339 inspectorServer.CallTargetAttachedToTarget(g_mthread);
340 inspectorServer.CallDebuggerPaused(g_mthread, {}, {}, PauseReason::OTHER, DefaultFrameEnumerator);
341
342 EXPECT_CALL(server, OnCallMock("Debugger.getScriptSource", testing::_))
343 .WillOnce([&](testing::Unused, auto handler) {
344 JsonObjectBuilder params;
345 params.AddProperty("scriptId", std::to_string(scriptId));
346 auto res = handler(g_sessionId, JsonObject(std::move(params).Build()));
347 ResultHolder result;
348 GetResult(std::move(res), result);
349 ASSERT_THAT(*result, JsonProperties(JsonProperty<JsonObject::StringT> {"scriptSource", g_sourceFile}));
350 });
351 inspectorServer.OnCallDebuggerGetScriptSource([](auto source) {
352 std::string s(source);
353 return s;
354 });
355
356 EXPECT_CALL(server, OnCallMock("Debugger.getScriptSource", testing::_))
357 .WillOnce([&](testing::Unused, auto handler) {
358 JsonObject empty;
359 auto res = handler(g_sessionId, empty);
360 ASSERT_FALSE(res.HasValue());
361 });
362 inspectorServer.OnCallDebuggerGetScriptSource([](auto) { return "a"; });
363 }
364
TEST_F(ServerTest,OnCallDebuggerStepOut)365 TEST_F(ServerTest, OnCallDebuggerStepOut)
366 {
367 inspectorServer.CallTargetAttachedToTarget(g_mthread);
368
369 EXPECT_CALL(server, OnCallMock("Debugger.stepOut", testing::_)).WillOnce(g_simpleHandler);
370
371 inspectorServer.OnCallDebuggerStepOut([](PtThread thread) {
372 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
373 g_handlerCalled = true;
374 });
375 }
376
TEST_F(ServerTest,OnCallDebuggerStepInto)377 TEST_F(ServerTest, OnCallDebuggerStepInto)
378 {
379 inspectorServer.CallTargetAttachedToTarget(g_mthread);
380
381 EXPECT_CALL(server, OnCallMock("Debugger.stepInto", testing::_)).WillOnce(g_simpleHandler);
382
383 inspectorServer.OnCallDebuggerStepInto([](PtThread thread) {
384 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
385 g_handlerCalled = true;
386 });
387 }
388
TEST_F(ServerTest,OnCallDebuggerStepOver)389 TEST_F(ServerTest, OnCallDebuggerStepOver)
390 {
391 inspectorServer.CallTargetAttachedToTarget(g_mthread);
392
393 EXPECT_CALL(server, OnCallMock("Debugger.stepOver", testing::_)).WillOnce(g_simpleHandler);
394
395 inspectorServer.OnCallDebuggerStepOver([](PtThread thread) {
396 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
397 g_handlerCalled = true;
398 });
399 }
400
handlerForSetBreak(PtThread thread,const std::function<bool (std::string_view)> & comp,size_t line,std::set<std::string_view> & sources,const std::string * condition)401 std::optional<BreakpointId> handlerForSetBreak([[maybe_unused]] PtThread thread,
402 [[maybe_unused]] const std::function<bool(std::string_view)> &comp,
403 size_t line, [[maybe_unused]] std::set<std::string_view> &sources,
404 [[maybe_unused]] const std::string *condition)
405 {
406 sources.insert("source");
407 return BreakpointId(line);
408 }
409
handlerForSetBreakEmpty(PtThread thread,const std::function<bool (std::string_view)> & comp,size_t line,std::set<std::string_view> & sources,const std::string * condition)410 std::optional<BreakpointId> handlerForSetBreakEmpty([[maybe_unused]] PtThread thread,
411 [[maybe_unused]] const std::function<bool(std::string_view)> &comp,
412 [[maybe_unused]] size_t line,
413 [[maybe_unused]] std::set<std::string_view> &sources,
414 [[maybe_unused]] const std::string *condition)
415 {
416 sources.insert("source");
417 return {};
418 }
419
TEST_F(ServerTest,OnCallDebuggerSetBreakpoint)420 TEST_F(ServerTest, OnCallDebuggerSetBreakpoint)
421 {
422 auto scriptId = 0;
423 size_t start = 5;
424
425 inspectorServer.CallTargetAttachedToTarget(g_mthread);
426 inspectorServer.CallDebuggerPaused(g_mthread, {}, {}, PauseReason::OTHER, DefaultFrameEnumerator);
427
428 EXPECT_CALL(server, OnCallMock("Debugger.setBreakpoint", testing::_)).WillOnce([&](testing::Unused, auto handler) {
429 JsonObjectBuilder params;
430 params.AddProperty("location", Location(scriptId, start));
431 auto res = handler(g_sessionId, JsonObject(std::move(params).Build()));
432 ResultHolder result;
433 GetResult(std::move(res), result);
434 ASSERT_THAT(*result,
435 JsonProperties(JsonProperty<JsonObject::StringT> {"breakpointId", std::to_string(start)},
436 JsonProperty<JsonObject::JsonObjPointer> {
437 "actualLocation",
438 testing::Pointee(JsonProperties(
439 JsonProperty<JsonObject::StringT> {"scriptId", std::to_string(scriptId)},
440 JsonProperty<JsonObject::NumT> {"lineNumber", start - 1}))}));
441 });
442
443 inspectorServer.OnCallDebuggerSetBreakpoint(handlerForSetBreak);
444
445 EXPECT_CALL(server, OnCallMock("Debugger.setBreakpoint", testing::_)).WillOnce([&](testing::Unused, auto handler) {
446 JsonObject empty;
447 auto res = handler(g_sessionId, empty);
448 ASSERT_FALSE(res.HasValue());
449 });
450
451 inspectorServer.OnCallDebuggerSetBreakpoint(handlerForSetBreak);
452
453 EXPECT_CALL(server, OnCallMock("Debugger.setBreakpoint", testing::_)).WillOnce([&](testing::Unused, auto handler) {
454 JsonObjectBuilder params;
455 params.AddProperty("location", Location(scriptId, start));
456 auto res = handler(g_sessionId, JsonObject(std::move(params).Build()));
457 ASSERT_FALSE(res.HasValue());
458 });
459
460 inspectorServer.OnCallDebuggerSetBreakpoint(handlerForSetBreakEmpty);
461 }
462
TEST_F(ServerTest,OnCallDebuggerSetBreakpointByUrl)463 TEST_F(ServerTest, OnCallDebuggerSetBreakpointByUrl)
464 {
465 auto scriptId = 0;
466 size_t start = 5;
467
468 inspectorServer.CallTargetAttachedToTarget(g_mthread);
469
470 EXPECT_CALL(server, OnCallMock("Debugger.setBreakpointByUrl", testing::_))
471 .WillOnce([&](testing::Unused, auto handler) {
472 JsonObjectBuilder params;
473 params.AddProperty("lineNumber", start);
474 auto res = handler(g_sessionId, JsonObject(std::move(params).Build()));
475 ASSERT_FALSE(res.HasValue());
476 });
477
478 inspectorServer.OnCallDebuggerSetBreakpointByUrl(handlerForSetBreak);
479
480 EXPECT_CALL(server, OnCallMock("Debugger.setBreakpointByUrl", testing::_))
481 .WillOnce([&](testing::Unused, auto handler) {
482 JsonObjectBuilder params;
483 params.AddProperty("lineNumber", start);
484 params.AddProperty("url", "file://source");
485 auto res = handler(g_sessionId, JsonObject(std::move(params).Build()));
486 ResultHolder result;
487 GetResult(std::move(res), result);
488
489 std::vector<testing::Matcher<JsonObject::JsonObjPointer>> locations;
490 locations.push_back(testing::Pointee(
491 JsonProperties(JsonProperty<JsonObject::StringT> {"scriptId", std::to_string(scriptId)},
492 JsonProperty<JsonObject::NumT> {"lineNumber", start})));
493 auto expected =
494 JsonProperties(JsonProperty<JsonObject::StringT> {"breakpointId", std::to_string(start + 1)},
495 JsonProperty<JsonObject::ArrayT> {"locations", JsonElementsAreArray(locations)});
496
497 ASSERT_THAT(*result, expected);
498 });
499
500 inspectorServer.OnCallDebuggerSetBreakpointByUrl(handlerForSetBreak);
501 }
502
TEST_F(ServerTest,OnCallDebuggerSetBreakpointsActive)503 TEST_F(ServerTest, OnCallDebuggerSetBreakpointsActive)
504 {
505 inspectorServer.CallTargetAttachedToTarget(g_mthread);
506
507 EXPECT_CALL(server, OnCallMock("Debugger.setBreakpointsActive", testing::_))
508 .WillOnce([&](testing::Unused, auto handler) {
509 JsonObject empty;
510 auto res = handler(g_sessionId, empty);
511 ASSERT_FALSE(res.HasValue());
512 ASSERT_FALSE(g_handlerCalled);
513 });
514
515 inspectorServer.OnCallDebuggerSetBreakpointsActive([](auto thread, auto value) {
516 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
517 ASSERT_FALSE(value);
518 g_handlerCalled = true;
519 });
520
521 EXPECT_CALL(server, OnCallMock("Debugger.setBreakpointsActive", testing::_))
522 .WillOnce([&](testing::Unused, auto handler) {
523 JsonObjectBuilder params;
524 params.AddProperty("active", true);
525 auto res = handler(g_sessionId, JsonObject(std::move(params).Build()));
526 ResultHolder result;
527 GetResult(std::move(res), result);
528 ASSERT_THAT(*result, JsonProperties());
529 ASSERT_TRUE(g_handlerCalled);
530 g_handlerCalled = false;
531 });
532
533 inspectorServer.OnCallDebuggerSetBreakpointsActive([](auto thread, auto value) {
534 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
535 ASSERT_TRUE(value);
536 g_handlerCalled = true;
537 });
538
539 EXPECT_CALL(server, OnCallMock("Debugger.setBreakpointsActive", testing::_))
540 .WillOnce([&](testing::Unused, auto handler) {
541 JsonObjectBuilder params;
542 params.AddProperty("active", false);
543 auto res = handler(g_sessionId, JsonObject(std::move(params).Build()));
544 ResultHolder result;
545 GetResult(std::move(res), result);
546 ASSERT_THAT(*result, JsonProperties());
547 ASSERT_TRUE(g_handlerCalled);
548 });
549
550 inspectorServer.OnCallDebuggerSetBreakpointsActive([](auto thread, auto value) {
551 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
552 ASSERT_FALSE(value);
553 g_handlerCalled = true;
554 });
555 }
556
TEST_F(ServerTest,OnCallDebuggerSetPauseOnExceptions)557 TEST_F(ServerTest, OnCallDebuggerSetPauseOnExceptions)
558 {
559 inspectorServer.CallTargetAttachedToTarget(g_mthread);
560
561 EXPECT_CALL(server, OnCallMock("Debugger.setPauseOnExceptions", testing::_))
562 .WillOnce([&](testing::Unused, auto handler) {
563 JsonObjectBuilder params;
564 params.AddProperty("state", "none");
565 auto res = handler(g_sessionId, JsonObject(std::move(params).Build()));
566 ResultHolder result;
567 GetResult(std::move(res), result);
568 ASSERT_THAT(*result, JsonProperties());
569 ASSERT_TRUE(g_handlerCalled);
570 });
571
572 inspectorServer.OnCallDebuggerSetPauseOnExceptions([](PtThread thread, PauseOnExceptionsState state) {
573 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
574 ASSERT_EQ(PauseOnExceptionsState::NONE, state);
575 g_handlerCalled = true;
576 });
577 }
578
TEST_F(ServerTest,OnCallDebuggerDisable)579 TEST_F(ServerTest, OnCallDebuggerDisable)
580 {
581 inspectorServer.CallTargetAttachedToTarget(g_mthread);
582
583 EXPECT_CALL(server, OnCallMock("Debugger.disable", testing::_)).WillOnce(g_simpleHandler);
584
585 inspectorServer.OnCallDebuggerDisable([](PtThread thread) {
586 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
587 g_handlerCalled = true;
588 });
589 }
590
TEST_F(ServerTest,OnCallDebuggerClientDisconnect)591 TEST_F(ServerTest, OnCallDebuggerClientDisconnect)
592 {
593 inspectorServer.CallTargetAttachedToTarget(g_mthread);
594
595 EXPECT_CALL(server, OnCallMock("Debugger.clientDisconnect", testing::_)).WillOnce(g_simpleHandler);
596
597 inspectorServer.OnCallDebuggerClientDisconnect([](PtThread thread) {
598 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
599 g_handlerCalled = true;
600 });
601 }
602
TEST_F(ServerTest,OnCallDebuggerSetAsyncCallStackDepth)603 TEST_F(ServerTest, OnCallDebuggerSetAsyncCallStackDepth)
604 {
605 inspectorServer.CallTargetAttachedToTarget(g_mthread);
606
607 EXPECT_CALL(server, OnCallMock("Debugger.setAsyncCallStackDepth", testing::_)).WillOnce(g_simpleHandler);
608
609 inspectorServer.OnCallDebuggerSetAsyncCallStackDepth([](PtThread thread) {
610 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
611 g_handlerCalled = true;
612 });
613 }
614
TEST_F(ServerTest,OnCallDebuggerSetBlackboxPatterns)615 TEST_F(ServerTest, OnCallDebuggerSetBlackboxPatterns)
616 {
617 inspectorServer.CallTargetAttachedToTarget(g_mthread);
618
619 EXPECT_CALL(server, OnCallMock("Debugger.setBlackboxPatterns", testing::_)).WillOnce(g_simpleHandler);
620
621 inspectorServer.OnCallDebuggerSetBlackboxPatterns([](PtThread thread) {
622 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
623 g_handlerCalled = true;
624 });
625 }
626
TEST_F(ServerTest,OnCallDebuggerSmartStepInto)627 TEST_F(ServerTest, OnCallDebuggerSmartStepInto)
628 {
629 inspectorServer.CallTargetAttachedToTarget(g_mthread);
630
631 EXPECT_CALL(server, OnCallMock("Debugger.smartStepInto", testing::_)).WillOnce(g_simpleHandler);
632
633 inspectorServer.OnCallDebuggerSmartStepInto([](PtThread thread) {
634 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
635 g_handlerCalled = true;
636 });
637 }
638
TEST_F(ServerTest,OnCallDebuggerDropFrame)639 TEST_F(ServerTest, OnCallDebuggerDropFrame)
640 {
641 inspectorServer.CallTargetAttachedToTarget(g_mthread);
642
643 EXPECT_CALL(server, OnCallMock("Debugger.dropFrame", testing::_)).WillOnce(g_simpleHandler);
644
645 inspectorServer.OnCallDebuggerDropFrame([](PtThread thread) {
646 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
647 g_handlerCalled = true;
648 });
649 }
650
TEST_F(ServerTest,OnCallDebuggerSetNativeRange)651 TEST_F(ServerTest, OnCallDebuggerSetNativeRange)
652 {
653 inspectorServer.CallTargetAttachedToTarget(g_mthread);
654
655 EXPECT_CALL(server, OnCallMock("Debugger.setNativeRange", testing::_)).WillOnce(g_simpleHandler);
656
657 inspectorServer.OnCallDebuggerSetNativeRange([](PtThread thread) {
658 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
659 g_handlerCalled = true;
660 });
661 }
662
TEST_F(ServerTest,OnCallDebuggerReplyNativeCalling)663 TEST_F(ServerTest, OnCallDebuggerReplyNativeCalling)
664 {
665 inspectorServer.CallTargetAttachedToTarget(g_mthread);
666
667 EXPECT_CALL(server, OnCallMock("Debugger.replyNativeCalling", testing::_)).WillOnce(g_simpleHandler);
668
669 inspectorServer.OnCallDebuggerReplyNativeCalling([](PtThread thread) {
670 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
671 g_handlerCalled = true;
672 });
673 }
674
TEST_F(ServerTest,OnCallDebuggerContinueToLocation)675 TEST_F(ServerTest, OnCallDebuggerContinueToLocation)
676 {
677 auto scriptId = 0;
678 size_t start = 5;
679
680 inspectorServer.CallTargetAttachedToTarget(g_mthread);
681
682 EXPECT_CALL(server, OnCallMock("Debugger.continueToLocation", testing::_))
683 .WillOnce([&](testing::Unused, auto handler) {
684 JsonObjectBuilder params;
685 params.AddProperty("location", Location(scriptId, start));
686 handler(g_sessionId, JsonObject(std::move(params).Build()));
687 });
688
689 inspectorServer.OnCallDebuggerContinueToLocation([](PtThread thread, std::string_view, size_t) {
690 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
691 g_handlerCalled = true;
692 });
693 }
694
TEST_F(ServerTest,OnCallDebuggerSetSkipAllPauses)695 TEST_F(ServerTest, OnCallDebuggerSetSkipAllPauses)
696 {
697 inspectorServer.CallTargetAttachedToTarget(g_mthread);
698
699 EXPECT_CALL(server, OnCallMock("Debugger.setSkipAllPauses", testing::_))
700 .WillOnce([&](testing::Unused, auto handler) {
701 JsonObjectBuilder params;
702 params.AddProperty("skip", true);
703 handler(g_sessionId, JsonObject(std::move(params).Build()));
704 });
705
706 inspectorServer.OnCallDebuggerSetSkipAllPauses([](PtThread thread, bool) {
707 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
708 g_handlerCalled = true;
709 });
710 }
711
handlerForEvaluateFailed(PtThread thread,const std::string & bytecodeBase64,size_t frameNumber)712 Expected<EvaluationResult, std::string> handlerForEvaluateFailed([[maybe_unused]] PtThread thread,
713 [[maybe_unused]] const std::string &bytecodeBase64,
714 [[maybe_unused]] size_t frameNumber)
715 {
716 return Unexpected(std::string("evaluate failed"));
717 }
718
handlerForEvaluate(PtThread thread,const std::string & bytecodeBase64,size_t frameNumber)719 Expected<EvaluationResult, std::string> handlerForEvaluate([[maybe_unused]] PtThread thread,
720 [[maybe_unused]] const std::string &bytecodeBase64,
721 [[maybe_unused]] size_t frameNumber)
722 {
723 return Unexpected(std::string("evaluation failed"));
724 }
725
TEST_F(ServerTest,OnCallDebuggerEvaluateOnCallFrame)726 TEST_F(ServerTest, OnCallDebuggerEvaluateOnCallFrame)
727 {
728 inspectorServer.CallTargetAttachedToTarget(g_mthread);
729
730 EXPECT_CALL(server, OnCallMock("Debugger.evaluateOnCallFrame", testing::_))
731 .WillOnce([&](testing::Unused, auto handler) {
732 JsonObjectBuilder params;
733 params.AddProperty("callFrameId", -1);
734 params.AddProperty("expression", "any expression");
735
736 auto res = handler(g_sessionId, JsonObject(std::move(params).Build()));
737 ASSERT_FALSE(res.HasValue());
738 });
739
740 inspectorServer.OnCallDebuggerEvaluateOnCallFrame(handlerForEvaluateFailed);
741 }
742
TEST_F(ServerTest,OnCallDebuggerCallFunctionOn)743 TEST_F(ServerTest, OnCallDebuggerCallFunctionOn)
744 {
745 inspectorServer.CallTargetAttachedToTarget(g_mthread);
746
747 EXPECT_CALL(server, OnCallMock("Debugger.callFunctionOn", testing::_)).WillOnce([&](testing::Unused, auto handler) {
748 JsonObjectBuilder params;
749 params.AddProperty("callFrameId", -1);
750 params.AddProperty("functionDeclaration", "any functionDeclaration");
751
752 auto res = handler(g_sessionId, JsonObject(std::move(params).Build()));
753 ASSERT_FALSE(res.HasValue());
754 });
755
756 inspectorServer.OnCallDebuggerCallFunctionOn(handlerForEvaluateFailed);
757 }
758
TEST_F(ServerTest,OnCallDebuggerGetPossibleAndSetBreakpointByUrl)759 TEST_F(ServerTest, OnCallDebuggerGetPossibleAndSetBreakpointByUrl)
760 {
761 auto scriptId = 0;
762 size_t start1 = 5;
763 size_t start2 = 6;
764
765 inspectorServer.CallTargetAttachedToTarget(g_mthread);
766
767 EXPECT_CALL(server, OnCallMock("Debugger.getPossibleAndSetBreakpointByUrl", testing::_))
768 .WillOnce([&](testing::Unused, auto handler) {
769 class RequestLocation : public JsonSerializable {
770 public:
771 explicit RequestLocation(std::string url, size_t lineNumber) : url_(url), lineNumber_(lineNumber) {}
772
773 void Serialize(JsonObjectBuilder &builder) const override
774 {
775 builder.AddProperty("url", url_);
776 builder.AddProperty("lineNumber", lineNumber_);
777 }
778
779 private:
780 std::string url_;
781 size_t lineNumber_;
782 };
783 std::vector<RequestLocation> requestLocations = {RequestLocation("file://source", start1),
784 RequestLocation("file://source", start2)};
785 JsonObjectBuilder builder;
786 builder.AddProperty("locations", [&](JsonArrayBuilder &locations) {
787 for (const auto &loc : requestLocations) {
788 locations.Add(loc);
789 }
790 });
791
792 auto res = handler(g_sessionId, JsonObject(std::move(builder).Build()));
793 ResultHolder result;
794 GetResult(std::move(res), result);
795
796 std::vector<testing::Matcher<JsonObject::JsonObjPointer>> locations;
797 locations.push_back(testing::Pointee(JsonProperties(JsonProperty<JsonObject::NumT> {"scriptId", scriptId},
798 JsonProperty<JsonObject::NumT> {"lineNumber", start1},
799 JsonProperty<JsonObject::NumT> {"columnNumber", 0},
800 JsonProperty<JsonObject::StringT> {"id", "6"})));
801 locations.push_back(testing::Pointee(JsonProperties(JsonProperty<JsonObject::NumT> {"scriptId", scriptId},
802 JsonProperty<JsonObject::NumT> {"lineNumber", start2},
803 JsonProperty<JsonObject::NumT> {"columnNumber", 0},
804 JsonProperty<JsonObject::StringT> {"id", "7"})));
805 auto expected =
806 JsonProperties(JsonProperty<JsonObject::ArrayT> {"locations", JsonElementsAreArray(locations)});
807
808 ASSERT_THAT(*result, expected);
809 });
810
811 inspectorServer.OnCallDebuggerGetPossibleAndSetBreakpointByUrl(handlerForSetBreak);
812 }
813
TEST_F(ServerTest,OnCallRuntimeEnable)814 TEST_F(ServerTest, OnCallRuntimeEnable)
815 {
816 inspectorServer.CallTargetAttachedToTarget(g_mthread);
817
818 EXPECT_CALL(server, OnCallMock("Runtime.enable", testing::_)).WillOnce([&](testing::Unused, auto handler) {
819 JsonObject empty;
820 auto res = handler(g_sessionId, empty);
821 ResultHolder result;
822 GetResult(std::move(res), result);
823 ASSERT_THAT(*result, JsonProperties());
824 ASSERT_TRUE(g_handlerCalled);
825 });
826 inspectorServer.OnCallRuntimeEnable([](PtThread thread) {
827 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
828 g_handlerCalled = true;
829 });
830 }
831
TEST_F(ServerTest,OnCallRuntimeGetProperties)832 TEST_F(ServerTest, OnCallRuntimeGetProperties)
833 {
834 auto object_id = 6;
835 auto preview = true;
836
837 inspectorServer.CallTargetAttachedToTarget(g_mthread);
838
839 EXPECT_CALL(server, OnCallMock("Runtime.getProperties", testing::_)).WillOnce([&](testing::Unused, auto handler) {
840 JsonObjectBuilder params;
841 params.AddProperty("objectId", std::to_string(object_id));
842 params.AddProperty("generatePreview", preview);
843 auto res = handler(g_sessionId, JsonObject(std::move(params).Build()));
844 ResultHolder result;
845 GetResult(std::move(res), result);
846
847 std::vector<testing::Matcher<JsonObject::JsonObjPointer>> expected;
848 expected.push_back(testing::Pointee(JsonProperties(
849 JsonProperty<JsonObject::StringT> {"name", "object"},
850 JsonProperty<JsonObject::JsonObjPointer> {
851 "value", testing::Pointee(JsonProperties(JsonProperty<JsonObject::NumT> {"value", object_id},
852 JsonProperty<JsonObject::StringT> {"type", "number"}))},
853 JsonProperty<JsonObject::BoolT> {"writable", testing::_},
854 JsonProperty<JsonObject::BoolT> {"configurable", testing::_},
855 JsonProperty<JsonObject::BoolT> {"enumerable", testing::_})));
856 expected.push_back(testing::Pointee(JsonProperties(
857 JsonProperty<JsonObject::StringT> {"name", "preview"},
858 JsonProperty<JsonObject::JsonObjPointer> {
859 "value", testing::Pointee(JsonProperties(JsonProperty<JsonObject::BoolT> {"value", preview},
860 JsonProperty<JsonObject::StringT> {"type", "boolean"}))},
861 JsonProperty<JsonObject::BoolT> {"writable", testing::_},
862 JsonProperty<JsonObject::BoolT> {"configurable", testing::_},
863 JsonProperty<JsonObject::BoolT> {"enumerable", testing::_})));
864 expected.push_back(testing::Pointee(JsonProperties(
865 JsonProperty<JsonObject::StringT> {"name", "threadId"},
866 JsonProperty<JsonObject::JsonObjPointer> {
867 "value", testing::Pointee(JsonProperties(JsonProperty<JsonObject::NumT> {"value", g_mthread.GetId()},
868 JsonProperty<JsonObject::StringT> {"type", "number"}))},
869 JsonProperty<JsonObject::BoolT> {"writable", testing::_},
870 JsonProperty<JsonObject::BoolT> {"configurable", testing::_},
871 JsonProperty<JsonObject::BoolT> {"enumerable", testing::_})));
872
873 ASSERT_THAT(*result,
874 JsonProperties(JsonProperty<JsonObject::ArrayT> {"result", JsonElementsAreArray(expected)}));
875 });
876
877 auto getProperties = [](PtThread thread, RemoteObjectId id, bool need_preview) {
878 std::vector<PropertyDescriptor> res;
879 res.push_back(PropertyDescriptor("object", RemoteObject::Number(id)));
880 res.push_back(PropertyDescriptor("preview", RemoteObject::Boolean(need_preview)));
881 res.push_back(PropertyDescriptor("threadId", RemoteObject::Number(thread.GetId())));
882 return res;
883 };
884
885 inspectorServer.OnCallRuntimeGetProperties(getProperties);
886 }
887
TEST_F(ServerTest,OnCallRuntimeRunIfWaitingForDebugger)888 TEST_F(ServerTest, OnCallRuntimeRunIfWaitingForDebugger)
889 {
890 inspectorServer.CallTargetAttachedToTarget(g_mthread);
891
892 EXPECT_CALL(server, OnCallMock("Runtime.runIfWaitingForDebugger", testing::_))
893 .WillOnce([&](testing::Unused, auto handler) {
894 JsonObject empty;
895 auto res = handler(g_sessionId, empty);
896 ResultHolder result;
897 GetResult(std::move(res), result);
898 ASSERT_THAT(*result, JsonProperties());
899 ASSERT_TRUE(g_handlerCalled);
900 });
901
902 inspectorServer.OnCallRuntimeRunIfWaitingForDebugger([](PtThread thread) {
903 ASSERT_EQ(thread.GetId(), g_mthread.GetId());
904 g_handlerCalled = true;
905 });
906 }
907
908 } // namespace ark::tooling::inspector::test
909
910 // NOLINTEND
911