add module UT

Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/IAIHFD

Signed-off-by: zhangyouyou <zhangyouyou2@huawei.com>
This commit is contained in:
zhangyouyou 2024-08-09 09:23:01 +08:00
parent 1062c46eeb
commit 21adf38105
10 changed files with 142 additions and 100 deletions

View File

@ -867,7 +867,6 @@ ecma_source = [
"ecmascript/module/js_module_manager.cpp",
"ecmascript/module/js_dynamic_import.cpp",
"ecmascript/module/js_module_namespace.cpp",
"ecmascript/module/js_module_record.cpp",
"ecmascript/module/js_module_source_text.cpp",
"ecmascript/module/js_module_deregister.cpp",
"ecmascript/module/js_shared_module.cpp",

View File

@ -53,8 +53,6 @@ JSHandle<ModuleNamespace> ModuleNamespace::ModuleNamespaceCreate(JSThread *threa
}
// 2. Assert: module.[[Namespace]] is undefined.
JSHandle<ModuleRecord> moduleRecord = JSHandle<ModuleRecord>::Cast(module);
ASSERT(ModuleRecord::GetNamespace(moduleRecord.GetTaggedValue()).IsUndefined());
// 3. Assert: exports is a List of String values.
// 4. Let M be a newly created object.
// 5. Set M's essential internal methods to the definitions specified in 9.4.6.
@ -75,7 +73,9 @@ JSHandle<ModuleNamespace> ModuleNamespace::ModuleNamespaceCreate(JSThread *threa
JSObject::DefineOwnProperty(thread, mNpObj, toStringTag, des);
// 10. Set module.[[Namespace]] to M.
SetModuleDeregisterProcession(thread, mNp, ModuleDeregister::FreeModuleRecord);
ModuleRecord::SetNamespace(thread, moduleRecord.GetTaggedValue(), mNp.GetTaggedValue());
JSHandle<ModuleRecord> moduleRecord = JSHandle<ModuleRecord>::Cast(module);
SourceTextModule::Cast(moduleRecord.GetTaggedValue().GetTaggedObject())->SetNamespace(thread,
mNp.GetTaggedValue());
mNp->GetJSHClass()->SetExtensible(false);
return mNp;
}

View File

@ -1,59 +0,0 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/module/js_module_record.h"
#include "ecmascript/module/js_module_source_text.h"
#include "ecmascript/object_factory-inl.h"
namespace panda::ecmascript {
int32_t ModuleRecord::Instantiate(JSThread *thread, const JSHandle<JSTaggedValue> &module)
{
STACK_LIMIT_CHECK(thread, SourceTextModule::UNDEFINED_INDEX);
if (module->IsSourceTextModule()) {
return SourceTextModule::Instantiate(thread, module);
}
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
JSTaggedValue ModuleRecord::Evaluate(JSThread *thread, const JSHandle<JSTaggedValue> &module)
{
if (module->IsSourceTextModule()) {
JSHandle<SourceTextModule> moduleRecord = JSHandle<SourceTextModule>::Cast(module);
return SourceTextModule::Evaluate(thread, moduleRecord);
}
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
JSTaggedValue ModuleRecord::GetNamespace(JSTaggedValue module)
{
if (module.IsSourceTextModule()) {
return SourceTextModule::Cast(module.GetTaggedObject())->GetNamespace();
}
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
void ModuleRecord::SetNamespace(JSThread *thread, JSTaggedValue module, JSTaggedValue value)
{
if (module.IsSourceTextModule()) {
SourceTextModule::Cast(module.GetTaggedObject())->SetNamespace(thread, value);
} else {
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
} // namespace panda::ecmascript

View File

@ -23,14 +23,6 @@ namespace panda::ecmascript {
class ModuleRecord : public Record {
public:
CAST_CHECK(ModuleRecord, IsModuleRecord);
// 15.2.1.16.4 Instantiate()
static int Instantiate(JSThread *thread, const JSHandle<JSTaggedValue> &module);
// 15.2.1.16.5 Evaluate()
static JSTaggedValue Evaluate(JSThread *thread, const JSHandle<JSTaggedValue> &module);
static JSTaggedValue GetNamespace(JSTaggedValue module);
static void SetNamespace(JSThread *thread, JSTaggedValue module, JSTaggedValue value);
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_MODULE_JS_MODULE_RECORD_H

View File

@ -643,8 +643,9 @@ int SourceTextModule::InnerModuleInstantiation(JSThread *thread, const JSHandle<
{
// 1. If module is not a Source Text Module Record, then
if (!moduleRecord.GetTaggedValue().IsSourceTextModule()) {
STACK_LIMIT_CHECK(thread, SourceTextModule::UNDEFINED_INDEX);
SourceTextModule::Instantiate(thread, JSHandle<JSTaggedValue>::Cast(moduleRecord));
// a. Perform ? module.Instantiate().
ModuleRecord::Instantiate(thread, JSHandle<JSTaggedValue>::Cast(moduleRecord));
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
// b. Return index.
return index;
@ -1012,9 +1013,9 @@ int SourceTextModule::InnerModuleEvaluationUnsafe(JSThread *thread, const JSHand
{
STACK_LIMIT_CHECK(thread, index);
if (!moduleRecord.GetTaggedValue().IsSourceTextModule()) {
JSTaggedValue promise = ModuleRecord::Evaluate(thread, JSHandle<JSTaggedValue>::Cast(moduleRecord));
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
PromiseState state = JSPromise::Cast(promise.GetTaggedObject())->GetPromiseState();
JSTaggedValue promise = SourceTextModule::Evaluate(thread, JSHandle<SourceTextModule>::Cast(moduleRecord));
PromiseState state = JSPromise::Cast(moduleRecord.GetTaggedValue().GetTaggedObject())->GetPromiseState();
ASSERT(state != PromiseState::PENDING);
if (state == PromiseState::REJECTED) {
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
@ -1025,7 +1026,6 @@ int SourceTextModule::InnerModuleEvaluationUnsafe(JSThread *thread, const JSHand
}
return index;
}
JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
ModuleStatus status = module->GetStatus();
if (status == ModuleStatus::EVALUATING_ASYNC || status == ModuleStatus::EVALUATED) {

View File

@ -186,8 +186,6 @@ JSHandle<ModuleNamespace> JSSharedModule::SModuleNamespaceCreate(JSThread *threa
{
auto globalConst = thread->GlobalConstants();
// 2. Assert: module.[[Namespace]] is undefined.
JSHandle<ModuleRecord> moduleRecord = JSHandle<ModuleRecord>::Cast(module);
ASSERT(ModuleRecord::GetNamespace(moduleRecord.GetTaggedValue()).IsUndefined());
// 3. Assert: exports is a List of String values.
// 4. Let M be a newly created object.
// 5. Set M's essential internal methods to the definitions specified in 9.4.6.
@ -206,8 +204,10 @@ JSHandle<ModuleNamespace> JSSharedModule::SModuleNamespaceCreate(JSThread *threa
PropertyDescriptor des(thread, moduleString, false, false, false);
JSHandle<JSObject> mNpObj = JSHandle<JSObject>::Cast(mNp);
JSObject::DefineOwnProperty(thread, mNpObj, toStringTag, des);
JSHandle<ModuleRecord> moduleRecord = JSHandle<ModuleRecord>::Cast(module);
SourceTextModule::Cast(moduleRecord.GetTaggedValue().GetTaggedObject())->SetNamespace(thread,
mNp.GetTaggedValue());
// 10. Set module.[[Namespace]] to M.
ModuleRecord::SetNamespace(thread, moduleRecord.GetTaggedValue(), mNp.GetTaggedValue());
mNp->GetJSHClass()->SetExtensible(false);
return mNp;
}

View File

@ -46,6 +46,7 @@ public:
int32_t index);
void InsertParentModule(JSHandle<SourceTextModule> currentModule, JSHandle<SourceTextModule> requiredModule);
void InsertEntryPointModule(JSHandle<SourceTextModule> currentModule);
void PrintModuleLoadInfo();
private:
static constexpr const int MILLISECONDS_PER_SEC = 1000;
@ -62,13 +63,12 @@ private:
bool CreateResultFile(std::string &path) const; // first time
bool OpenResultFile(std::string &path) const;
ModuleLoadInfo *GetModuleLoadInfo(const CString &recordName);
void PrintModuleLoadInfo();
void PrintSummary() const;
void PrintUsedFileInfo() const;
void PrintUnusedFileInfo() const;
void ProcessModuleExecuteTime();
static std::string ToStringWithPrecision(const double num, const uint8_t n);
EcmaVM *vm_ {nullptr};
CUnorderedMap<CString, ModuleLoadInfo*> jsModuleLoadInfo_ {};
uint32_t totalFileNumber_ {0};

View File

@ -26,6 +26,7 @@
#include "ecmascript/module/js_module_manager.h"
#include "ecmascript/module/js_module_source_text.h"
#include "ecmascript/module/module_data_extractor.h"
#include "ecmascript/module/module_logger.h"
#include "ecmascript/module/module_path_helper.h"
#include "ecmascript/tests/test_helper.h"
#include "ecmascript/linked_hash_table.h"
@ -327,24 +328,6 @@ HWTEST_F_L0(EcmaModuleTest, PreventExtensions_IsExtensible)
EXPECT_TRUE(ModuleNamespace::PreventExtensions());
}
HWTEST_F_L0(EcmaModuleTest, Instantiate_Evaluate_GetNamespace_SetNamespace)
{
std::string baseFileName = MODULE_ABC_PATH "module_test_module_test_C.abc";
JSNApi::EnableUserUncaughtErrorHandler(instance);
bool result = JSNApi::Execute(instance, baseFileName, "module_test_module_test_C");
EXPECT_TRUE(result);
ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
JSHandle<SourceTextModule> module = moduleManager->HostGetImportedModule("module_test_module_test_C");
module->SetStatus(ModuleStatus::UNINSTANTIATED);
ModuleRecord::Instantiate(thread, JSHandle<JSTaggedValue>(module));
JSTaggedValue res = ModuleRecord::Evaluate(thread, JSHandle<JSTaggedValue>(module));
ModuleRecord::GetNamespace(module.GetTaggedValue());
ModuleRecord::SetNamespace(thread, module.GetTaggedValue(), JSTaggedValue::Undefined());
EXPECT_TRUE(res.IsJSPromise());
}
HWTEST_F_L0(EcmaModuleTest, ConcatFileNameWithMerge1)
{
CString baseFilename = "merge.abc";
@ -907,4 +890,122 @@ HWTEST_F_L0(EcmaModuleTest, NeedTranslateToNormalized)
res = ModulePathHelper::NeedTranslateToNormalized(requestName);
EXPECT_EQ(res, true);
}
} // namespace panda::test
HWTEST_F_L0(EcmaModuleTest, ModuleLogger) {
ObjectFactory *objectFactory = thread->GetEcmaVM()->GetFactory();
JSHandle<SourceTextModule> module1 = objectFactory->NewSourceTextModule();
CString baseFileName = "modules.abc";
module1->SetEcmaModuleFilenameString(baseFileName);
CString recordName1 = "a";
module1->SetEcmaModuleRecordNameString(recordName1);
JSHandle<SourceTextModule> module2 = objectFactory->NewSourceTextModule();
module2->SetEcmaModuleFilenameString(baseFileName);
CString recordName2 = "b";
module2->SetEcmaModuleRecordNameString(recordName2);
JSHandle<JSTaggedValue> moduleRequest = JSHandle<JSTaggedValue>::Cast(objectFactory->NewFromUtf8("c"));
JSHandle<JSTaggedValue> importName = JSHandle<JSTaggedValue>::Cast(objectFactory->NewFromUtf8("ccc"));
JSHandle<JSTaggedValue> localName = JSHandle<JSTaggedValue>::Cast(objectFactory->NewFromUtf8("ccc"));
JSHandle<ImportEntry> importEntry = objectFactory->NewImportEntry(moduleRequest, importName,
localName, SharedTypes::UNSENDABLE_MODULE);
SourceTextModule::AddImportEntry(thread, module2, importEntry, 0, 1);
JSHandle<SourceTextModule> module3 = objectFactory->NewSourceTextModule();
module2->SetEcmaModuleFilenameString(baseFileName);
CString recordName3 = "c";
module2->SetEcmaModuleRecordNameString(recordName3);
ModuleLogger *moduleLogger = new ModuleLogger(thread->GetEcmaVM());
moduleLogger->SetStartTime(recordName1);
moduleLogger->SetEndTime(recordName1);
moduleLogger->SetStartTime(recordName2);
moduleLogger->SetEndTime(recordName2);
moduleLogger->SetStartTime(recordName3);
moduleLogger->InsertEntryPointModule(module1);
moduleLogger->InsertParentModule(module1, module2);
moduleLogger->InsertModuleLoadInfo(module2, module3, -1);
moduleLogger->InsertModuleLoadInfo(module2, module3, 0);
moduleLogger->PrintModuleLoadInfo();
Local<JSValueRef> nativeFunc = SourceTextModule::GetRequireNativeModuleFunc(thread->GetEcmaVM(),
module3->GetTypes());
bool isFunc = nativeFunc->IsFunction(thread->GetEcmaVM());
EXPECT_EQ(isFunc, false);
}
HWTEST_F_L0(EcmaModuleTest, GetRequireNativeModuleFunc) {
ObjectFactory *objectFactory = thread->GetEcmaVM()->GetFactory();
JSHandle<SourceTextModule> module = objectFactory->NewSourceTextModule();
uint16_t registerNum = module->GetRegisterCounts();
module->SetStatus(ecmascript::ModuleStatus::INSTANTIATED);
module->SetRegisterCounts(registerNum);
Local<JSValueRef> nativeFunc = SourceTextModule::GetRequireNativeModuleFunc(thread->GetEcmaVM(),
module->GetTypes());
bool isFunc = nativeFunc->IsFunction(thread->GetEcmaVM());
EXPECT_EQ(isFunc, false);
}
/*
* Feature: Module
* Function: StoreModuleValue
* SubFunction: StoreModuleValue/GetModuleValue
* FunctionPoints: store a module export item in module
* CaseDescription: Simulated implementation of "export foo as bar", set foo as "hello world",
* use "import bar" in same js file
*/
HWTEST_F_L0(EcmaModuleTest, StoreModuleValue2)
{
ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory();
CString localName = "foo";
CString exportName = "bar";
CString value = "hello world";
CString value2 = "hello world1";
int32_t index = 1;
JSHandle<JSTaggedValue> localNameHandle = JSHandle<JSTaggedValue>::Cast(objFactory->NewFromUtf8(localName));
JSHandle<JSTaggedValue> exportNameHandle = JSHandle<JSTaggedValue>::Cast(objFactory->NewFromUtf8(exportName));
JSHandle<LocalExportEntry> localExportEntry =
objFactory->NewLocalExportEntry(exportNameHandle, localNameHandle, LocalExportEntry::LOCAL_DEFAULT_INDEX,
SharedTypes::UNSENDABLE_MODULE);
JSHandle<SourceTextModule> module = objFactory->NewSourceTextModule();
SourceTextModule::AddLocalExportEntry(thread, module, localExportEntry, 0, 1);
JSHandle<JSTaggedValue> storeKey = JSHandle<JSTaggedValue>::Cast(objFactory->NewFromUtf8(localName));
JSHandle<JSTaggedValue> valueHandle = JSHandle<JSTaggedValue>::Cast(objFactory->NewFromUtf8(value));
JSHandle<JSTaggedValue> valueHandle1 = JSHandle<JSTaggedValue>::Cast(objFactory->NewFromUtf8(value2));
module->StoreModuleValue(thread, storeKey, valueHandle);
module->StoreModuleValue(thread, index, valueHandle1);
JSHandle<JSTaggedValue> loadKey = JSHandle<JSTaggedValue>::Cast(objFactory->NewFromUtf8(localName));
JSTaggedValue loadValue = module->GetModuleValue(thread, loadKey.GetTaggedValue(), false);
JSTaggedValue loadValue1 = module->GetModuleValue(thread, index, false);
EXPECT_EQ(valueHandle.GetTaggedValue(), loadValue);
EXPECT_EQ(valueHandle1.GetTaggedValue(), loadValue1);
}
HWTEST_F_L0(EcmaModuleTest, MakeAppArgs1) {
std::vector<Local<JSValueRef>> arguments;
CString soPath = "@normalized:Y&&&libentry.so&";
CString moduleName = "entry";
CString requestName = "@normalized:";
arguments.emplace_back(StringRef::NewFromUtf8(thread->GetEcmaVM(), soPath.c_str()));
SourceTextModule::MakeAppArgs(thread->GetEcmaVM(), arguments, soPath, moduleName, requestName);
std::string res1 = arguments[0]->ToString(thread->GetEcmaVM())->ToString(thread->GetEcmaVM());
std::string res2 = arguments[1]->ToString(thread->GetEcmaVM())->ToString(thread->GetEcmaVM());
std::string res3 = arguments[2]->ToString(thread->GetEcmaVM())->ToString(thread->GetEcmaVM());
EXPECT_TRUE(res1 == "entry");
EXPECT_TRUE(res2 == "true");
EXPECT_TRUE(res3 == "/entry");
}
HWTEST_F_L0(EcmaModuleTest, MakeAppArgs2) {
std::vector<Local<JSValueRef>> arguments;
CString soPath = "@app:com.example.myapplication/entry";
CString moduleName = "entry";
CString requestName = "@app:";
arguments.emplace_back(StringRef::NewFromUtf8(thread->GetEcmaVM(), soPath.c_str()));
SourceTextModule::MakeAppArgs(thread->GetEcmaVM(), arguments, soPath, moduleName, requestName);
std::string res1 = arguments[0]->ToString(thread->GetEcmaVM())->ToString(thread->GetEcmaVM());
std::string res2 = arguments[1]->ToString(thread->GetEcmaVM())->ToString(thread->GetEcmaVM());
std::string res3 = arguments[2]->ToString(thread->GetEcmaVM())->ToString(thread->GetEcmaVM());
EXPECT_TRUE(res1 == "entry");
EXPECT_TRUE(res2 == "true");
EXPECT_TRUE(res3 == "@app:com.example.myapplication");
}
} // namespace panda::test

View File

@ -60,10 +60,17 @@ import('./1.json').then(m => {
print(m.default.name);
}).then().catch();
import('@native:system.app').then(m => {
print("native module");
}).then().catch();
import('@native:system.app').then(m => {
print("native module");
}).then().catch();
// Dynamic Loading Reload Test
import('./aaa.js').then(m => {
print("dynamic import aaa.js 1st time");
})
import('./aaa.js').then(m => {
print("dynamic import aaa.js 2nd time");
})
})

View File

@ -20,5 +20,7 @@ undefined
{}
TypeError
dynamicImport Json
native module
native module
dynamic import aaa.js 1st time
dynamic import aaa.js 2nd time