• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/object_repository.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 "runtime_options.h"
25 #include "tooling/debugger.h"
26 
27 #include "types/numeric_id.h"
28 
29 #include "common.h"
30 #include "json_object_matcher.h"
31 
32 // NOLINTBEGIN
33 
34 namespace ark::tooling::inspector::test {
35 
36 static constexpr const char *g_source = R"(
37     .record Test {}
38 
39     .function i32 Test.foo() {
40         ldai 111
41         return
42     }
43 )";
44 
45 class ObjectRepositoryTest : public testing::Test {
46 protected:
SetUpTestSuite()47     static void SetUpTestSuite()
48     {
49         RuntimeOptions options;
50         options.SetShouldInitializeIntrinsics(false);
51         options.SetShouldLoadBootPandaFiles(false);
52         Runtime::Create(options);
53         thread_ = ark::MTManagedThread::GetCurrent();
54         thread_->ManagedCodeBegin();
55 
56         pandasm::Parser p;
57 
58         auto res = p.Parse(g_source, "source.pa");
59         ASSERT_TRUE(res.HasValue());
60         auto pf = pandasm::AsmEmitter::Emit(res.Value());
61         ASSERT(pf);
62         ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
63         classLinker->AddPandaFile(std::move(pf));
64 
65         PandaString descriptor;
66         auto *ext = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
67         Class *klass = ext->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("Test"), &descriptor));
68         ASSERT_NE(klass, nullptr);
69 
70         auto methods = klass->GetMethods();
71         ASSERT_EQ(methods.size(), 1);
72 
73         clsObject = klass->GetManagedObject();
74         methodFoo = &methods[0];
75     }
76 
TearDownTestSuite()77     static void TearDownTestSuite()
78     {
79         thread_->ManagedCodeEnd();
80         Runtime::Destroy();
81     }
82 
83     static constexpr uint16_t U16_VALUE = 43602;
84     static constexpr int32_t I32_VALUE = -2345678;
85     static constexpr int64_t I64_VALUE = 200000000000002;
86     static constexpr double F64_VALUE = 6.547;
87 
88     static ark::MTManagedThread *thread_;
89     static Method *methodFoo;
90     static ObjectHeader *clsObject;
91 };
92 
93 ark::MTManagedThread *ObjectRepositoryTest::thread_ = nullptr;
94 Method *ObjectRepositoryTest::methodFoo = nullptr;
95 ObjectHeader *ObjectRepositoryTest::clsObject = nullptr;
96 
97 template <typename ValueT, typename V>
GetPrimitiveProperties(const char * type,V value,const char * valueName="value")98 static auto GetPrimitiveProperties(const char *type, V value, const char *valueName = "value")
99 {
100     return JsonProperties(JsonProperty<JsonObject::StringT> {"type", type}, JsonProperty<ValueT> {valueName, value});
101 }
102 
103 template <typename NameT, typename DescT>
GetObjectProperties(NameT className,DescT description,const char * objectId)104 static auto GetObjectProperties(NameT className, DescT description, const char *objectId)
105 {
106     return JsonProperties(JsonProperty<JsonObject::StringT> {"type", "object"},
107                           JsonProperty<JsonObject::StringT> {"className", className},
108                           JsonProperty<JsonObject::StringT> {"description", description},
109                           JsonProperty<JsonObject::StringT> {"objectId", objectId});
110 }
111 
112 template <typename NameT, typename V>
GetFrameObjectProperties(NameT name,V valueProperties)113 static auto GetFrameObjectProperties(NameT name, V valueProperties)
114 {
115     return JsonProperties(JsonProperty<JsonObject::StringT> {"name", name},
116                           JsonProperty<JsonObject::JsonObjPointer> {"value", valueProperties},
117                           JsonProperty<JsonObject::BoolT> {"writable", testing::_},
118                           JsonProperty<JsonObject::BoolT> {"configurable", testing::_},
119                           JsonProperty<JsonObject::BoolT> {"enumerable", testing::_});
120 }
121 
TEST_F(ObjectRepositoryTest,S)122 TEST_F(ObjectRepositoryTest, S)
123 {
124     ObjectRepository obj;
125 
126     auto clsObj = obj.CreateObject(TypedValue::Reference(clsObject));
127     ASSERT_EQ(clsObj.GetObjectId(), RemoteObjectId(1));
128     ASSERT_THAT(ToJson(clsObj), GetObjectProperties(testing::_, testing::_, "1"));
129 
130     auto nullObj = obj.CreateObject(TypedValue::Reference(nullptr));
131     ASSERT_THAT(ToJson(nullObj), JsonProperties(JsonProperty<JsonObject::StringT> {"type", "object"},
132                                                 JsonProperty<JsonObject::StringT> {"subtype", "null"},
133                                                 JsonProperty<JsonObject::JsonObjPointer> {"value", testing::IsNull()}));
134 
135     auto invObj = obj.CreateObject(TypedValue::Invalid());
136     ASSERT_THAT(ToJson(invObj), JsonProperties(JsonProperty<JsonObject::StringT> {"type", "undefined"}));
137 
138     auto boolObj = obj.CreateObject(TypedValue::U1(true));
139     ASSERT_THAT(ToJson(boolObj), GetPrimitiveProperties<JsonObject::BoolT>("boolean", true));
140 
141     auto numObj = obj.CreateObject(TypedValue::U16(U16_VALUE));
142     ASSERT_THAT(ToJson(numObj), GetPrimitiveProperties<JsonObject::NumT>("number", U16_VALUE));
143 
144     auto negObj = obj.CreateObject(TypedValue::I32(I32_VALUE));
145     ASSERT_THAT(ToJson(negObj), GetPrimitiveProperties<JsonObject::NumT>("number", I32_VALUE));
146 
147     auto hugeObj = obj.CreateObject(TypedValue::I64(I64_VALUE));
148     ASSERT_THAT(ToJson(hugeObj),
149                 GetPrimitiveProperties<JsonObject::StringT>("bigint", "200000000000002", "unserializableValue"));
150 
151     auto doubObj = obj.CreateObject(TypedValue::F64(F64_VALUE));
152     ASSERT_THAT(ToJson(doubObj), GetPrimitiveProperties<JsonObject::NumT>("number", testing::DoubleEq(F64_VALUE)));
153 
154     auto globObj1 = obj.CreateGlobalObject();
155     ASSERT_THAT(ToJson(globObj1), GetObjectProperties("[Global]", "Global object", "0"));
156 
157     auto globObj2 = obj.CreateGlobalObject();
158     ASSERT_THAT(ToJson(globObj2), GetObjectProperties("[Global]", "Global object", "0"));
159 
160     PtDebugFrame frame(methodFoo, nullptr);
161     std::map<std::string, TypedValue> locals;
162     locals.emplace("a", TypedValue::U16(56U));
163     locals.emplace("ref", TypedValue::Reference(clsObject));
164     // "this" parameter for static languages. Note that ArkTS uses "=t" instead of "this".
165     locals.emplace("this", TypedValue::Reference(clsObject));
166 
167     std::optional<RemoteObject> objThis;
168     auto frameObj = obj.CreateFrameObject(frame, locals, objThis);
169     ASSERT_EQ(frameObj.GetObjectId().value(), RemoteObjectId(2UL));
170 
171     auto properties = obj.GetProperties(frameObj.GetObjectId().value(), false);
172     ASSERT_EQ(properties.size(), 2UL);
173     ASSERT_EQ(properties[0].GetName(), "a");
174 
175     ASSERT_THAT(ToJson(frameObj), GetObjectProperties("", "Frame #0", "2"));
176 
177     ASSERT_THAT(
178         ToJson(properties[0]),
179         GetFrameObjectProperties("a", testing::Pointee(GetPrimitiveProperties<JsonObject::NumT>("number", 56U))));
180 
181     ASSERT_THAT(ToJson(properties[1]),
182                 GetFrameObjectProperties("ref", testing::Pointee(GetObjectProperties(testing::_, testing::_, "1"))));
183 
184     // Call to "CreateFrameObject" must find and fill "this" parameter.
185     ASSERT_TRUE(objThis.has_value());
186     auto idThis = objThis->GetObjectId();
187     ASSERT_TRUE(idThis.has_value());
188     ASSERT_EQ(idThis.value(), 1U);
189 }
190 
TEST_F(ObjectRepositoryTest,TestFrameObjectNoThis)191 TEST_F(ObjectRepositoryTest, TestFrameObjectNoThis)
192 {
193     ObjectRepository obj;
194 
195     PtDebugFrame frame(methodFoo, nullptr);
196     std::map<std::string, TypedValue> locals;
197     locals.emplace("a", TypedValue::U16(56U));
198     locals.emplace("ref", TypedValue::Reference(clsObject));
199 
200     std::optional<RemoteObject> objThis;
201     auto frameObj = obj.CreateFrameObject(frame, locals, objThis);
202     ASSERT_EQ(frameObj.GetObjectId().value(), RemoteObjectId(2UL));
203 
204     auto properties = obj.GetProperties(frameObj.GetObjectId().value(), true);
205     ASSERT_EQ(properties.size(), 2UL);
206 
207     // No "this" parameter was provided.
208     ASSERT_FALSE(objThis.has_value());
209 }
210 }  // namespace ark::tooling::inspector::test
211 
212 // NOLINTEND
213