• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 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 <gtest/gtest.h>
17 
18 #include "types/ets_object.h"
19 
20 #include "ets_vm.h"
21 #include "ets_coroutine.h"
22 #include "ets_class_linker_extension.h"
23 #include "assembly-emitter.h"
24 #include "assembly-parser.h"
25 
26 // NOLINTBEGIN(readability-magic-numbers)
27 
28 namespace ark::ets::test {
29 
30 class EtsObjectTest : public testing::Test {
31 public:
EtsObjectTest()32     EtsObjectTest()
33     {
34         options_.SetShouldLoadBootPandaFiles(true);
35         options_.SetShouldInitializeIntrinsics(false);
36         options_.SetCompilerEnableJit(false);
37         options_.SetGcType("epsilon");
38         options_.SetLoadRuntimes({"ets"});
39 
40         auto stdlib = std::getenv("PANDA_STD_LIB");
41         if (stdlib == nullptr) {
42             std::cerr << "PANDA_STD_LIB env variable should be set and point to mock_stdlib.abc" << std::endl;
43             std::abort();
44         }
45         options_.SetBootPandaFiles({stdlib});
46 
47         Runtime::Create(options_);
48 
49         SetClassesPandasmSources();
50     }
51 
~EtsObjectTest()52     ~EtsObjectTest() override
53     {
54         Runtime::Destroy();
55     }
56 
57     NO_COPY_SEMANTIC(EtsObjectTest);
58     NO_MOVE_SEMANTIC(EtsObjectTest);
59 
SetUp()60     void SetUp() override
61     {
62         coroutine_ = EtsCoroutine::GetCurrent();
63         coroutine_->ManagedCodeBegin();
64     }
65 
TearDown()66     void TearDown() override
67     {
68         coroutine_->ManagedCodeEnd();
69     }
70 
71     void SetClassesPandasmSources();
72     EtsClass *GetTestClass(std::string className);
73 
74 private:
75     RuntimeOptions options_;
76     EtsCoroutine *coroutine_ = nullptr;
77     std::unordered_map<std::string, const char *> sources_;
78 
79 protected:
GetSources()80     const std::unordered_map<std::string, const char *> &GetSources()
81     {
82         return sources_;
83     }
84 };
85 
SetClassesPandasmSources()86 void EtsObjectTest::SetClassesPandasmSources()
87 {
88     const char *source = R"(
89         .language eTS
90         .record Rectangle {
91             i32 Width
92             f32 Height
93             i64 Color <static>
94         }
95     )";
96     sources_["Rectangle"] = source;
97 
98     source = R"(
99         .language eTS
100         .record Triangle {
101             i32 firSide
102             i32 secSide
103             i32 thirdSide
104             i64 Color <static>
105         }
106     )";
107     sources_["Triangle"] = source;
108 
109     source = R"(
110         .language eTS
111         .record Foo {
112             i32 member
113         }
114         .record Bar {
115             Foo foo1
116             Foo foo2
117         }
118     )";
119     sources_["Foo"] = source;
120     sources_["Bar"] = source;
121 }
122 
GetTestClass(std::string className)123 EtsClass *EtsObjectTest::GetTestClass(std::string className)
124 {
125     std::unordered_map<std::string, const char *> sources = GetSources();
126     pandasm::Parser p;
127 
128     auto res = p.Parse(sources[className]);
129     auto pf = pandasm::AsmEmitter::Emit(res.Value());
130 
131     auto classLinker = Runtime::GetCurrent()->GetClassLinker();
132     classLinker->AddPandaFile(std::move(pf));
133 
134     className.insert(0, 1, 'L');
135     className.push_back(';');
136 
137     EtsClass *klass = coroutine_->GetPandaVM()->GetClassLinker()->GetClass(className.c_str());
138     ASSERT(klass);
139     return klass;
140 }
141 
TEST_F(EtsObjectTest,GetClass)142 TEST_F(EtsObjectTest, GetClass)
143 {
144     EtsClass *klass = nullptr;
145     EtsObject *obj = nullptr;
146 
147     for (const auto &it : GetSources()) {
148         klass = GetTestClass(it.first);
149         obj = EtsObject::Create(klass);
150         ASSERT_EQ(klass, obj->GetClass());
151     }
152 }
153 
TEST_F(EtsObjectTest,SetClass)154 TEST_F(EtsObjectTest, SetClass)
155 {
156     EtsClass *klass1 = GetTestClass("Rectangle");
157     EtsClass *klass2 = GetTestClass("Triangle");
158     EtsObject *obj = EtsObject::Create(klass1);
159     ASSERT_EQ(obj->GetClass(), klass1);
160     obj->SetClass(klass2);
161     ASSERT_EQ(obj->GetClass(), klass2);
162 }
163 
TEST_F(EtsObjectTest,IsInstanceOf)164 TEST_F(EtsObjectTest, IsInstanceOf)
165 {
166     EtsClass *klass1 = GetTestClass("Rectangle");
167     EtsClass *klass2 = GetTestClass("Triangle");
168     EtsObject *obj1 = EtsObject::Create(klass1);
169     EtsObject *obj2 = EtsObject::Create(klass2);
170 
171     ASSERT_TRUE(obj1->IsInstanceOf(klass1));
172     ASSERT_TRUE(obj2->IsInstanceOf(klass2));
173     ASSERT_FALSE(obj1->IsInstanceOf(klass2));
174     ASSERT_FALSE(obj2->IsInstanceOf(klass1));
175 }
176 
TEST_F(EtsObjectTest,GetAndSetFieldObject)177 TEST_F(EtsObjectTest, GetAndSetFieldObject)
178 {
179     EtsClass *barKlass = GetTestClass("Bar");
180     EtsClass *fooKlass = GetTestClass("Foo");
181 
182     EtsObject *barObj = EtsObject::Create(barKlass);
183     EtsObject *fooObj1 = EtsObject::Create(fooKlass);
184     EtsObject *fooObj2 = EtsObject::Create(fooKlass);
185 
186     EtsField *foo1Field = barKlass->GetFieldIDByName("foo1");
187     EtsField *foo2Field = barKlass->GetFieldIDByName("foo2");
188 
189     barObj->SetFieldObject(foo1Field, fooObj1);
190     barObj->SetFieldObject(foo2Field, fooObj2);
191     ASSERT_EQ(barObj->GetFieldObject(foo1Field), fooObj1);
192     ASSERT_EQ(barObj->GetFieldObject(foo2Field), fooObj2);
193 
194     EtsObject *res = barObj->GetAndSetFieldObject(foo2Field->GetOffset(), fooObj1, std::memory_order_relaxed);
195     ASSERT_EQ(res, fooObj2);                                // returned pointer was in foo2_field
196     ASSERT_EQ(barObj->GetFieldObject(foo2Field), fooObj1);  // now in foo2_field is pointer to Foo_obj1
197 
198     res = barObj->GetAndSetFieldObject(foo1Field->GetOffset(), fooObj2, std::memory_order_relaxed);
199     ASSERT_EQ(res, fooObj1);
200     ASSERT_EQ(barObj->GetFieldObject(foo1Field), fooObj2);
201 }
202 
TEST_F(EtsObjectTest,SetAndGetFieldObject)203 TEST_F(EtsObjectTest, SetAndGetFieldObject)
204 {
205     EtsClass *barKlass = GetTestClass("Bar");
206     EtsClass *fooKlass = GetTestClass("Foo");
207 
208     EtsObject *barObj = EtsObject::Create(barKlass);
209     EtsObject *fooObj1 = EtsObject::Create(fooKlass);
210     EtsObject *fooObj2 = EtsObject::Create(fooKlass);
211 
212     EtsField *foo1Field = barKlass->GetFieldIDByName("foo1");
213     EtsField *foo2Field = barKlass->GetFieldIDByName("foo2");
214 
215     barObj->SetFieldObject(foo1Field, fooObj1);
216     barObj->SetFieldObject(foo2Field, fooObj2);
217     ASSERT_EQ(barObj->GetFieldObject(foo1Field), fooObj1);
218     ASSERT_EQ(barObj->GetFieldObject(foo2Field), fooObj2);
219 
220     barObj->SetFieldObject(foo1Field, fooObj2);
221     ASSERT_EQ(barObj->GetFieldObject(foo1Field), fooObj2);
222     barObj->SetFieldObject(foo2Field, fooObj1);
223     ASSERT_EQ(barObj->GetFieldObject(foo2Field), fooObj1);
224 }
225 
TEST_F(EtsObjectTest,SetAndGetFieldPrimitive)226 TEST_F(EtsObjectTest, SetAndGetFieldPrimitive)
227 {
228     EtsClass *klass = GetTestClass("Rectangle");
229     EtsObject *obj = EtsObject::Create(klass);
230     EtsField *field = klass->GetFieldIDByName("Width");
231     int32_t testNmb1 = 77;
232     obj->SetFieldPrimitive<int32_t>(field, testNmb1);
233     ASSERT_EQ(obj->GetFieldPrimitive<int32_t>(field), testNmb1);
234 
235     field = klass->GetFieldIDByName("Height");
236     float testNmb2 = 111.11;
237     obj->SetFieldPrimitive<float>(field, testNmb2);
238     ASSERT_EQ(obj->GetFieldPrimitive<float>(field), testNmb2);
239 }
240 
TEST_F(EtsObjectTest,CompareAndSetFieldPrimitive)241 TEST_F(EtsObjectTest, CompareAndSetFieldPrimitive)
242 {
243     EtsClass *klass = GetTestClass("Rectangle");
244     EtsObject *obj = EtsObject::Create(klass);
245     EtsField *field = klass->GetFieldIDByName("Width");
246     int32_t firNmb = 134;
247     int32_t secNmb = 12;
248     obj->SetFieldPrimitive(field, firNmb);
249     obj->CompareAndSetFieldPrimitive(field->GetOffset(), firNmb, secNmb, std::memory_order_relaxed, true);
250     ASSERT_EQ(obj->GetFieldPrimitive<int32_t>(field), secNmb);
251 }
252 
TEST_F(EtsObjectTest,CompareAndSetFieldObject)253 TEST_F(EtsObjectTest, CompareAndSetFieldObject)
254 {
255     EtsClass *barKlass = GetTestClass("Bar");
256     EtsClass *fooKlass = GetTestClass("Foo");
257 
258     EtsObject *barObj = EtsObject::Create(barKlass);
259     EtsObject *fooObj1 = EtsObject::Create(fooKlass);
260     EtsObject *fooObj2 = EtsObject::Create(fooKlass);
261 
262     EtsField *foo1Field = barKlass->GetFieldIDByName("foo1");
263     EtsField *foo2Field = barKlass->GetFieldIDByName("foo2");
264 
265     barObj->SetFieldObject(foo1Field, fooObj1);
266     barObj->SetFieldObject(foo2Field, fooObj2);
267     ASSERT_EQ(barObj->GetFieldObject(foo1Field), fooObj1);
268     ASSERT_EQ(barObj->GetFieldObject(foo2Field), fooObj2);
269 
270     ASSERT_TRUE(
271         barObj->CompareAndSetFieldObject(foo1Field->GetOffset(), fooObj1, fooObj2, std::memory_order_relaxed, false));
272     ASSERT_EQ(barObj->GetFieldObject(foo1Field), fooObj2);
273 
274     ASSERT_TRUE(
275         barObj->CompareAndSetFieldObject(foo2Field->GetOffset(), fooObj2, fooObj1, std::memory_order_relaxed, false));
276     ASSERT_EQ(barObj->GetFieldObject(foo2Field), fooObj1);
277 }
278 
279 }  // namespace ark::ets::test
280 
281 // NOLINTEND(readability-magic-numbers)
282