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 "debugger/thread_state.h"
17
18 #include "gtest/gtest.h"
19
20 #include "evaluation/evaluation_engine.h"
21 #include "file.h"
22 #include "object_header.h"
23 #include "runtime_options.h"
24 #include "runtime.h"
25 #include "typed_value.h"
26
27 // NOLINTBEGIN
28
29 namespace ark::tooling::inspector::test {
30 class MockEvaluationEngine final : public EvaluationEngine {
31 public:
EvaluateExpression(uint32_t frameNumber,const ExpressionWrapper & bytecode,Method ** method)32 Expected<std::pair<TypedValue, ObjectHeader *>, Error> EvaluateExpression(
33 [[maybe_unused]] uint32_t frameNumber, [[maybe_unused]] const ExpressionWrapper &bytecode,
34 [[maybe_unused]] Method **method) override
35 {
36 return std::make_pair<TypedValue, ObjectHeader *>(TypedValue::Invalid(), nullptr);
37 }
38 };
39
40 class ThreadStateTest : public testing::Test {
SetUp()41 void SetUp()
42 {
43 state = std::make_unique<ThreadState>(mockEvaluationEngine_, bpStorage_);
44 }
45
46 protected:
47 MockEvaluationEngine mockEvaluationEngine_;
48 BreakpointStorage bpStorage_;
49 std::unique_ptr<ThreadState> state;
50 PtLocation fake = PtLocation("", {}, 0);
51 PtLocation location0 = PtLocation("test.abc", panda_file::File::EntityId(1), 0);
52 PtLocation location1 = PtLocation("test.abc", panda_file::File::EntityId(1), 1);
53 PtLocation location2 = PtLocation("test.abc", panda_file::File::EntityId(1), 2);
54 PtLocation location3 = PtLocation("test.abc", panda_file::File::EntityId(1), 3);
55 const char *source = "/test.ets";
56 };
57
TEST_F(ThreadStateTest,BreakOnStart)58 TEST_F(ThreadStateTest, BreakOnStart)
59 {
60 ASSERT_FALSE(state->IsPaused());
61 state->OnSingleStep(fake, source);
62 ASSERT_FALSE(state->IsPaused());
63
64 state->BreakOnStart();
65 state->OnSingleStep(fake, source);
66 ASSERT_TRUE(state->IsPaused());
67 }
68
TEST_F(ThreadStateTest,PauseAndContinue)69 TEST_F(ThreadStateTest, PauseAndContinue)
70 {
71 state->Pause();
72 state->OnSingleStep(fake, source);
73 ASSERT_TRUE(state->IsPaused());
74 state->Continue();
75 state->OnSingleStep(fake, source);
76 ASSERT_FALSE(state->IsPaused());
77
78 state->Pause();
79 ASSERT_FALSE(state->IsPaused());
80 state->Continue();
81 state->OnSingleStep(fake, source);
82 ASSERT_FALSE(state->IsPaused());
83 }
84
TEST_F(ThreadStateTest,StepInto)85 TEST_F(ThreadStateTest, StepInto)
86 {
87 state->Pause();
88 state->OnSingleStep(fake, source);
89
90 std::unordered_set<PtLocation, HashLocation> locs;
91 locs.insert(location1);
92 locs.insert(location2);
93
94 ASSERT_TRUE(state->IsPaused());
95 state->StepInto(locs);
96 state->OnSingleStep(location2, source);
97 ASSERT_FALSE(state->IsPaused());
98 state->OnSingleStep(location3, source);
99 ASSERT_TRUE(state->IsPaused());
100 }
101
TEST_F(ThreadStateTest,ContinueTo)102 TEST_F(ThreadStateTest, ContinueTo)
103 {
104 state->Pause();
105 state->OnSingleStep(fake, source);
106
107 std::unordered_set<PtLocation, HashLocation> locs;
108 locs.insert(location1);
109 locs.insert(location2);
110
111 ASSERT_TRUE(state->IsPaused());
112 state->ContinueTo(locs);
113 state->OnSingleStep(location0, source);
114 ASSERT_FALSE(state->IsPaused());
115 state->OnSingleStep(location1, source);
116 ASSERT_TRUE(state->IsPaused());
117 }
118
TEST_F(ThreadStateTest,StepOut)119 TEST_F(ThreadStateTest, StepOut)
120 {
121 state->Pause();
122 state->OnSingleStep(fake, source);
123
124 ASSERT_TRUE(state->IsPaused());
125 state->StepOut();
126 state->OnSingleStep(location0, source);
127 ASSERT_FALSE(state->IsPaused());
128 state->OnSingleStep(location1, source);
129 ASSERT_FALSE(state->IsPaused());
130 state->OnSingleStep(location2, source);
131 ASSERT_FALSE(state->IsPaused());
132 state->OnFramePop();
133 state->OnSingleStep(fake, source);
134 ASSERT_TRUE(state->IsPaused());
135 }
136
TEST_F(ThreadStateTest,StepOver)137 TEST_F(ThreadStateTest, StepOver)
138 {
139 state->Pause();
140 state->OnSingleStep(fake, source);
141
142 std::unordered_set<PtLocation, HashLocation> locs;
143 locs.insert(location1);
144 locs.insert(location2);
145
146 ASSERT_TRUE(state->IsPaused());
147 state->StepOver(locs);
148 state->OnSingleStep(location1, source);
149 ASSERT_FALSE(state->IsPaused());
150 state->OnMethodEntry();
151 state->OnSingleStep(fake, source);
152 ASSERT_FALSE(state->IsPaused());
153 state->OnFramePop();
154 state->OnSingleStep(location2, source);
155 ASSERT_FALSE(state->IsPaused());
156 state->OnFramePop();
157 state->OnSingleStep(fake, source);
158 ASSERT_TRUE(state->IsPaused());
159 }
160
TEST_F(ThreadStateTest,OnException)161 TEST_F(ThreadStateTest, OnException)
162 {
163 ASSERT_FALSE(state->IsPaused());
164
165 state->SetPauseOnExceptions(PauseOnExceptionsState::NONE);
166 state->OnException(false);
167 ASSERT_FALSE(state->IsPaused());
168 state->OnException(true);
169 ASSERT_FALSE(state->IsPaused());
170
171 state->SetPauseOnExceptions(PauseOnExceptionsState::CAUGHT);
172 state->OnException(true);
173 ASSERT_FALSE(state->IsPaused());
174 state->OnException(false);
175 ASSERT_TRUE(state->IsPaused());
176 state->Continue();
177 ASSERT_FALSE(state->IsPaused());
178
179 state->SetPauseOnExceptions(PauseOnExceptionsState::UNCAUGHT);
180 state->OnException(false);
181 ASSERT_FALSE(state->IsPaused());
182 state->OnException(true);
183 ASSERT_TRUE(state->IsPaused());
184 state->Continue();
185 ASSERT_FALSE(state->IsPaused());
186
187 state->SetPauseOnExceptions(PauseOnExceptionsState::ALL);
188 state->OnException(false);
189 ASSERT_TRUE(state->IsPaused());
190 state->Continue();
191 ASSERT_FALSE(state->IsPaused());
192 state->OnException(true);
193 ASSERT_TRUE(state->IsPaused());
194 }
195
196 } // namespace ark::tooling::inspector::test
197
198 // NOLINTEND
199