1 /*
2 * Copyright (c) 2022 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 <thread>
17
18 #include "ecmascript/ecma_vm.h"
19 #include "ecmascript/jspandafile/js_pandafile_manager.h"
20 #include "ecmascript/ts_types/tests/ts_type_test_helper.h"
21 #include "ecmascript/ts_types/ts_type_parser.h"
22
23 namespace panda::test {
24 using namespace panda::ecmascript;
25 using namespace panda::panda_file;
26 using namespace panda::pandasm;
27 using LiteralValueType = std::variant<uint8_t, uint32_t, std::string>;
28
29 static constexpr uint16_t FIRST_USER_DEFINE_MODULE_ID = TSModuleTable::DEFAULT_NUMBER_OF_TABLES;
30 static constexpr uint16_t FIRST_USER_DEFINE_LOCAL_ID = 1;
31
32 class TSTypeParserTest : public testing::Test {
33 public:
SetUpTestCase()34 static void SetUpTestCase()
35 {
36 GTEST_LOG_(INFO) << "SetUpTestCase";
37 }
38
TearDownTestCase()39 static void TearDownTestCase()
40 {
41 GTEST_LOG_(INFO) << "TearDownCase";
42 }
43
SetUp()44 void SetUp() override
45 {
46 TestHelper::CreateEcmaVMWithScope(ecmaVm, thread, scope);
47 }
48
TearDown()49 void TearDown() override
50 {
51 TestHelper::DestroyEcmaVMWithScope(ecmaVm, scope);
52 }
53
54 EcmaVM *ecmaVm {nullptr};
55 EcmaHandleScope *scope {nullptr};
56 JSThread *thread {nullptr};
57 };
58
HWTEST_F_L0(TSTypeParserTest,TestPrimetiveType)59 HWTEST_F_L0(TSTypeParserTest, TestPrimetiveType)
60 {
61 auto tsManager = ecmaVm->GetTSManager();
62 tsManager->Initialize();
63 TSTypeParser tsTypeParser(tsManager);
64 JSPandaFile *jsPandaFile = nullptr;
65 const CString recordName("");
66 uint32_t primetiveTypeId = 0U;
67 GlobalTSTypeRef resultGT = tsTypeParser.CreateGT(jsPandaFile, recordName, primetiveTypeId);
68 EXPECT_EQ(resultGT, GlobalTSTypeRef(TSModuleTable::PRIMITIVE_TABLE_ID, primetiveTypeId));
69 }
70
HWTEST_F_L0(TSTypeParserTest,TestBuiltinType)71 HWTEST_F_L0(TSTypeParserTest, TestBuiltinType)
72 {
73 auto tsManager = ecmaVm->GetTSManager();
74 tsManager->Initialize();
75 TSTypeParser tsTypeParser(tsManager);
76 JSPandaFile *jsPandaFile = nullptr;
77 const CString recordName("");
78 uint32_t builtinTypeId = 50U;
79 GlobalTSTypeRef builtinGT = tsTypeParser.CreateGT(jsPandaFile, recordName, builtinTypeId);
80 EXPECT_EQ(builtinGT, GlobalTSTypeRef(TSModuleTable::BUILTINS_TABLE_ID, builtinTypeId));
81 }
82
HWTEST_F_L0(TSTypeParserTest,TestTSClassType)83 HWTEST_F_L0(TSTypeParserTest, TestTSClassType)
84 {
85 const char *source = R"(
86 .language ECMAScript
87 .record test {}
88 .function void foo() {}
89 )";
90 pandasm::Parser parser;
91 auto res = parser.Parse(source);
92 EXPECT_EQ(parser.ShowError().err, Error::ErrorType::ERR_NONE);
93 auto &program = res.Value();
94
95 const std::string classId("test_1");
96 const std::string valueStr("value");
97 std::vector<panda_file::LiteralTag> classTags { panda_file::LiteralTag::INTEGER,
98 panda_file::LiteralTag::INTEGER,
99 panda_file::LiteralTag::BUILTINTYPEINDEX,
100 panda_file::LiteralTag::INTEGER,
101 panda_file::LiteralTag::INTEGER,
102 panda_file::LiteralTag::INTEGER,
103 panda_file::LiteralTag::INTEGER,
104 panda_file::LiteralTag::STRING,
105 panda_file::LiteralTag::BUILTINTYPEINDEX,
106 panda_file::LiteralTag::INTEGER,
107 panda_file::LiteralTag::INTEGER,
108 panda_file::LiteralTag::INTEGER };
109 std::vector<LiteralValueType> classValues { static_cast<uint32_t>(1),
110 static_cast<uint32_t>(0),
111 static_cast<uint8_t>(0),
112 static_cast<uint32_t>(0),
113 static_cast<uint32_t>(0),
114 static_cast<uint32_t>(0),
115 static_cast<uint32_t>(1),
116 valueStr,
117 static_cast<uint8_t>(1),
118 static_cast<uint32_t>(0),
119 static_cast<uint32_t>(0),
120 static_cast<uint32_t>(0) };
121 TSTypeTestHelper::AddLiteral(program, classId, classTags, classValues);
122
123 const std::string abcFileName("TSClassTypeTest.abc");
124 TSTypeTestHelper::AddTypeSummary(program, { classId });
125 TSTypeTestHelper::AddCommonJsField(program);
126 std::map<std::string, size_t> *statp = nullptr;
127 pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps {};
128 pandasm::AsmEmitter::PandaFileToPandaAsmMaps *mapsp = &maps;
129 EXPECT_TRUE(pandasm::AsmEmitter::Emit(abcFileName, program, statp, mapsp, false));
130 std::unique_ptr<const panda_file::File> pfPtr = panda_file::File::Open(abcFileName);
131 EXPECT_NE(pfPtr.get(), nullptr);
132
133 Span<const uint32_t> literalArrays = pfPtr.get()->GetLiteralArrays();
134 EXPECT_TRUE(literalArrays.size() >= 2);
135 // typeIds in order from largest to smallest and the last one is typeSummary literal
136 uint32_t testTypeIndex = literalArrays.size() - 2;
137 uint32_t testTypeOffset = literalArrays[testTypeIndex];
138
139 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
140 const CString fileName(abcFileName.c_str());
141 const JSPandaFile *jsPandaFile = pfManager->NewJSPandaFile(pfPtr.release(), fileName);
142 EXPECT_NE(jsPandaFile, nullptr);
143
144 auto tsManager = ecmaVm->GetTSManager();
145 tsManager->Initialize();
146 TSTypeParser tsTypeParser(tsManager);
147 const CString recordName("test");
148 GlobalTSTypeRef resultGT = tsTypeParser.CreateGT(jsPandaFile, recordName, testTypeOffset);
149 EXPECT_EQ(resultGT, GlobalTSTypeRef(FIRST_USER_DEFINE_MODULE_ID, FIRST_USER_DEFINE_LOCAL_ID));
150 EXPECT_TRUE(tsManager->IsClassTypeKind(resultGT));
151 JSHandle<JSTaggedValue> type = tsManager->GetTSType(resultGT);
152 EXPECT_TRUE(type->IsTSClassType());
153
154 JSHandle<TSClassType> classType(type);
155 EXPECT_EQ(resultGT, classType->GetGT());
156 auto factory = ecmaVm->GetFactory();
157 JSHandle<EcmaString> propertyName = factory->NewFromStdString(valueStr);
158 GlobalTSTypeRef propGT = TSClassType::GetPropTypeGT(thread, classType, propertyName);
159 EXPECT_EQ(propGT,
160 GlobalTSTypeRef(TSModuleTable::PRIMITIVE_TABLE_ID, static_cast<uint16_t>(TSPrimitiveType::NUMBER)));
161 }
162
HWTEST_F_L0(TSTypeParserTest,TestTSFunctionType)163 HWTEST_F_L0(TSTypeParserTest, TestTSFunctionType)
164 {
165 const char *source = R"(
166 .language ECMAScript
167 .record test {}
168 .function void foo() {}
169 )";
170 pandasm::Parser parser;
171 auto res = parser.Parse(source);
172 EXPECT_EQ(parser.ShowError().err, Error::ErrorType::ERR_NONE);
173 auto &program = res.Value();
174
175 const std::string functionId("test_1");
176 const std::string functionName("foo");
177 const uint32_t numOfParas = 2;
178 std::vector<panda_file::LiteralTag> functionTags { panda_file::LiteralTag::INTEGER,
179 panda_file::LiteralTag::INTEGER,
180 panda_file::LiteralTag::STRING,
181 panda_file::LiteralTag::INTEGER,
182 panda_file::LiteralTag::INTEGER,
183 panda_file::LiteralTag::BUILTINTYPEINDEX,
184 panda_file::LiteralTag::BUILTINTYPEINDEX,
185 panda_file::LiteralTag::BUILTINTYPEINDEX };
186 std::vector<LiteralValueType> functionValues { static_cast<uint32_t>(3),
187 static_cast<uint32_t>(0),
188 functionName,
189 static_cast<uint32_t>(0),
190 numOfParas,
191 static_cast<uint8_t>(1),
192 static_cast<uint8_t>(4),
193 static_cast<uint8_t>(2) };
194 TSTypeTestHelper::AddLiteral(program, functionId, functionTags, functionValues);
195
196 const std::string abcFileName("TSFunctionTypeTest.abc");
197 TSTypeTestHelper::AddTypeSummary(program, { functionId });
198 TSTypeTestHelper::AddCommonJsField(program);
199 std::map<std::string, size_t> *statp = nullptr;
200 pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps {};
201 pandasm::AsmEmitter::PandaFileToPandaAsmMaps *mapsp = &maps;
202 EXPECT_TRUE(pandasm::AsmEmitter::Emit(abcFileName, program, statp, mapsp, false));
203 std::unique_ptr<const panda_file::File> pfPtr = panda_file::File::Open(abcFileName);
204 EXPECT_NE(pfPtr.get(), nullptr);
205
206 Span<const uint32_t> literalArrays = pfPtr.get()->GetLiteralArrays();
207 EXPECT_TRUE(literalArrays.size() >= 2);
208 // typeIds in order from largest to smallest and the last one is typeSummary literal
209 uint32_t testTypeIndex = literalArrays.size() - 2;
210 uint32_t testTypeOffset = literalArrays[testTypeIndex];
211
212 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
213 const CString fileName(abcFileName.c_str());
214 const JSPandaFile *jsPandaFile = pfManager->NewJSPandaFile(pfPtr.release(), fileName);
215 EXPECT_NE(jsPandaFile, nullptr);
216
217 auto tsManager = ecmaVm->GetTSManager();
218 tsManager->Initialize();
219 TSTypeParser tsTypeParser(tsManager);
220 const CString recordName("test");
221 GlobalTSTypeRef resultGT = tsTypeParser.CreateGT(jsPandaFile, recordName, testTypeOffset);
222 EXPECT_EQ(resultGT, GlobalTSTypeRef(FIRST_USER_DEFINE_MODULE_ID, FIRST_USER_DEFINE_LOCAL_ID));
223 EXPECT_TRUE(tsManager->IsFunctionTypeKind(resultGT));
224 JSHandle<JSTaggedValue> type = tsManager->GetTSType(resultGT);
225 EXPECT_TRUE(type->IsTSFunctionType());
226
227 JSHandle<TSFunctionType> functionType(type);
228 EXPECT_EQ(resultGT, functionType->GetGT());
229 EXPECT_EQ(functionType->GetLength(), numOfParas);
230 EXPECT_EQ(functionType->GetParameterTypeGT(0),
231 GlobalTSTypeRef(TSModuleTable::PRIMITIVE_TABLE_ID, static_cast<uint16_t>(TSPrimitiveType::NUMBER)));
232 EXPECT_EQ(functionType->GetParameterTypeGT(1),
233 GlobalTSTypeRef(TSModuleTable::PRIMITIVE_TABLE_ID, static_cast<uint16_t>(TSPrimitiveType::STRING)));
234 EXPECT_EQ(functionType->GetReturnGT(),
235 GlobalTSTypeRef(TSModuleTable::PRIMITIVE_TABLE_ID, static_cast<uint16_t>(TSPrimitiveType::BOOLEAN)));
236 }
237
HWTEST_F_L0(TSTypeParserTest,TestTSUnionType)238 HWTEST_F_L0(TSTypeParserTest, TestTSUnionType)
239 {
240 const char *source = R"(
241 .language ECMAScript
242 .record test {}
243 .function void foo() {}
244 )";
245 pandasm::Parser parser;
246 auto res = parser.Parse(source);
247 EXPECT_EQ(parser.ShowError().err, Error::ErrorType::ERR_NONE);
248 auto &program = res.Value();
249
250 const std::string unionId("test_1");
251 const uint32_t numOfTypes = 2;
252 std::vector<panda_file::LiteralTag> unionTags { panda_file::LiteralTag::INTEGER,
253 panda_file::LiteralTag::INTEGER,
254 panda_file::LiteralTag::BUILTINTYPEINDEX,
255 panda_file::LiteralTag::BUILTINTYPEINDEX };
256 std::vector<LiteralValueType> unionValues { static_cast<uint32_t>(4),
257 numOfTypes,
258 static_cast<uint8_t>(1),
259 static_cast<uint8_t>(4) };
260 TSTypeTestHelper::AddLiteral(program, unionId, unionTags, unionValues);
261
262 const std::string abcFileName("TSUnionTypeTest.abc");
263 TSTypeTestHelper::AddTypeSummary(program, { unionId });
264 TSTypeTestHelper::AddCommonJsField(program);
265 std::map<std::string, size_t> *statp = nullptr;
266 pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps {};
267 pandasm::AsmEmitter::PandaFileToPandaAsmMaps *mapsp = &maps;
268 EXPECT_TRUE(pandasm::AsmEmitter::Emit(abcFileName, program, statp, mapsp, false));
269 std::unique_ptr<const panda_file::File> pfPtr = panda_file::File::Open(abcFileName);
270 EXPECT_NE(pfPtr.get(), nullptr);
271
272 Span<const uint32_t> literalArrays = pfPtr.get()->GetLiteralArrays();
273 EXPECT_TRUE(literalArrays.size() >= 2);
274 // typeIds in order from largest to smallest and the last one is typeSummary literal
275 uint32_t testTypeIndex = literalArrays.size() - 2;
276 uint32_t testTypeOffset = literalArrays[testTypeIndex];
277
278 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
279 const CString fileName(abcFileName.c_str());
280 const JSPandaFile *jsPandaFile = pfManager->NewJSPandaFile(pfPtr.release(), fileName);
281 EXPECT_NE(jsPandaFile, nullptr);
282
283 auto tsManager = ecmaVm->GetTSManager();
284 tsManager->Initialize();
285 TSTypeParser tsTypeParser(tsManager);
286 const CString recordName("test");
287 GlobalTSTypeRef resultGT = tsTypeParser.CreateGT(jsPandaFile, recordName, testTypeOffset);
288 EXPECT_EQ(resultGT, GlobalTSTypeRef(FIRST_USER_DEFINE_MODULE_ID, FIRST_USER_DEFINE_LOCAL_ID));
289 EXPECT_TRUE(tsManager->IsUnionTypeKind(resultGT));
290 JSHandle<JSTaggedValue> type = tsManager->GetTSType(resultGT);
291 EXPECT_TRUE(type->IsTSUnionType());
292
293 JSHandle<TSUnionType> unionType(type);
294 EXPECT_EQ(resultGT, unionType->GetGT());
295 EXPECT_EQ(tsManager->GetUnionTypeLength(resultGT), numOfTypes);
296 EXPECT_EQ(tsManager->GetUnionTypeByIndex(resultGT, 0),
297 GlobalTSTypeRef(TSModuleTable::PRIMITIVE_TABLE_ID, static_cast<uint16_t>(TSPrimitiveType::NUMBER)));
298 EXPECT_EQ(tsManager->GetUnionTypeByIndex(resultGT, 1),
299 GlobalTSTypeRef(TSModuleTable::PRIMITIVE_TABLE_ID, static_cast<uint16_t>(TSPrimitiveType::STRING)));
300 }
301
HWTEST_F_L0(TSTypeParserTest,TestTSArrayType)302 HWTEST_F_L0(TSTypeParserTest, TestTSArrayType)
303 {
304 const char *source = R"(
305 .language ECMAScript
306 .record test {}
307 .function void foo() {}
308 )";
309 pandasm::Parser parser;
310 auto res = parser.Parse(source);
311 EXPECT_EQ(parser.ShowError().err, Error::ErrorType::ERR_NONE);
312 auto &program = res.Value();
313
314 const std::string arrayId("test_1");
315 std::vector<panda_file::LiteralTag> arrayTags { panda_file::LiteralTag::INTEGER,
316 panda_file::LiteralTag::BUILTINTYPEINDEX };
317 std::vector<LiteralValueType> arrayValues { static_cast<uint32_t>(5),
318 static_cast<uint8_t>(1) };
319 TSTypeTestHelper::AddLiteral(program, arrayId, arrayTags, arrayValues);
320
321 const std::string abcFileName("TSArrayTypeTest.abc");
322 TSTypeTestHelper::AddTypeSummary(program, { arrayId });
323 TSTypeTestHelper::AddCommonJsField(program);
324 std::map<std::string, size_t> *statp = nullptr;
325 pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps {};
326 pandasm::AsmEmitter::PandaFileToPandaAsmMaps *mapsp = &maps;
327 EXPECT_TRUE(pandasm::AsmEmitter::Emit(abcFileName, program, statp, mapsp, false));
328 std::unique_ptr<const panda_file::File> pfPtr = panda_file::File::Open(abcFileName);
329 EXPECT_NE(pfPtr.get(), nullptr);
330
331 Span<const uint32_t> literalArrays = pfPtr.get()->GetLiteralArrays();
332 EXPECT_TRUE(literalArrays.size() >= 2);
333 // typeIds in order from largest to smallest and the last one is typeSummary literal
334 uint32_t testTypeIndex = literalArrays.size() - 2;
335 uint32_t testTypeOffset = literalArrays[testTypeIndex];
336
337 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
338 const CString fileName(abcFileName.c_str());
339 const JSPandaFile *jsPandaFile = pfManager->NewJSPandaFile(pfPtr.release(), fileName);
340 EXPECT_NE(jsPandaFile, nullptr);
341
342 auto tsManager = ecmaVm->GetTSManager();
343 tsManager->Initialize();
344 TSTypeParser tsTypeParser(tsManager);
345 const CString recordName("test");
346 GlobalTSTypeRef resultGT = tsTypeParser.CreateGT(jsPandaFile, recordName, testTypeOffset);
347 EXPECT_EQ(resultGT, GlobalTSTypeRef(FIRST_USER_DEFINE_MODULE_ID, FIRST_USER_DEFINE_LOCAL_ID));
348 EXPECT_TRUE(tsManager->IsArrayTypeKind(resultGT));
349 JSHandle<JSTaggedValue> type = tsManager->GetTSType(resultGT);
350 EXPECT_TRUE(type->IsTSArrayType());
351
352 JSHandle<TSArrayType> arrayType(type);
353 EXPECT_EQ(resultGT, arrayType->GetGT());
354 EXPECT_EQ(arrayType->GetElementGT(),
355 GlobalTSTypeRef(TSModuleTable::PRIMITIVE_TABLE_ID, static_cast<uint16_t>(TSPrimitiveType::NUMBER)));
356 }
357
HWTEST_F_L0(TSTypeParserTest,TestTSObjectType)358 HWTEST_F_L0(TSTypeParserTest, TestTSObjectType)
359 {
360 const char *source = R"(
361 .language ECMAScript
362 .record test {}
363 .function void foo() {}
364 )";
365 pandasm::Parser parser;
366 auto res = parser.Parse(source);
367 EXPECT_EQ(parser.ShowError().err, Error::ErrorType::ERR_NONE);
368 auto &program = res.Value();
369
370 const std::string objectId("test_1");
371 const std::string ageStr("age");
372 const std::string funStr("fun");
373 std::vector<panda_file::LiteralTag> objectTags { panda_file::LiteralTag::INTEGER,
374 panda_file::LiteralTag::INTEGER,
375 panda_file::LiteralTag::STRING,
376 panda_file::LiteralTag::BUILTINTYPEINDEX,
377 panda_file::LiteralTag::STRING,
378 panda_file::LiteralTag::BUILTINTYPEINDEX };
379 std::vector<LiteralValueType> objectValues { static_cast<uint32_t>(6),
380 static_cast<uint32_t>(2),
381 ageStr,
382 static_cast<uint8_t>(1),
383 funStr,
384 static_cast<uint8_t>(1) };
385 TSTypeTestHelper::AddLiteral(program, objectId, objectTags, objectValues);
386
387 const std::string abcFileName("TSObjectTypeTest.abc");
388 TSTypeTestHelper::AddTypeSummary(program, { objectId });
389 TSTypeTestHelper::AddCommonJsField(program);
390 std::map<std::string, size_t> *statp = nullptr;
391 pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps {};
392 pandasm::AsmEmitter::PandaFileToPandaAsmMaps *mapsp = &maps;
393 EXPECT_TRUE(pandasm::AsmEmitter::Emit(abcFileName, program, statp, mapsp, false));
394 std::unique_ptr<const panda_file::File> pfPtr = panda_file::File::Open(abcFileName);
395 EXPECT_NE(pfPtr.get(), nullptr);
396
397 Span<const uint32_t> literalArrays = pfPtr.get()->GetLiteralArrays();
398 EXPECT_TRUE(literalArrays.size() >= 2);
399 // typeIds in order from largest to smallest and the last one is typeSummary literal
400 uint32_t testTypeIndex = literalArrays.size() - 2;
401 uint32_t testTypeOffset = literalArrays[testTypeIndex];
402
403 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
404 const CString fileName(abcFileName.c_str());
405 const JSPandaFile *jsPandaFile = pfManager->NewJSPandaFile(pfPtr.release(), fileName);
406 EXPECT_NE(jsPandaFile, nullptr);
407
408 auto tsManager = ecmaVm->GetTSManager();
409 tsManager->Initialize();
410 TSTypeParser tsTypeParser(tsManager);
411 const CString recordName("test");
412 GlobalTSTypeRef resultGT = tsTypeParser.CreateGT(jsPandaFile, recordName, testTypeOffset);
413 EXPECT_EQ(resultGT, GlobalTSTypeRef(FIRST_USER_DEFINE_MODULE_ID, FIRST_USER_DEFINE_LOCAL_ID));
414 EXPECT_TRUE(tsManager->IsObjectTypeKind(resultGT));
415 JSHandle<JSTaggedValue> type = tsManager->GetTSType(resultGT);
416 EXPECT_TRUE(type->IsTSObjectType());
417
418 JSHandle<TSObjectType> objectType(type);
419 EXPECT_EQ(resultGT, objectType->GetGT());
420 auto factory = ecmaVm->GetFactory();
421 JSHandle<EcmaString> propName = factory->NewFromStdString(ageStr);
422 GlobalTSTypeRef propGT = TSObjectType::GetPropTypeGT(objectType, propName);
423 EXPECT_EQ(propGT,
424 GlobalTSTypeRef(TSModuleTable::PRIMITIVE_TABLE_ID, static_cast<uint16_t>(TSPrimitiveType::NUMBER)));
425 }
426 } // namespace panda::test
427