Files
ark_js_runtime/ecmascript/tests/ecma_module_test.cpp
T
lifansheng e25d85cd16 modify ecmaModule to support CjsModule
Signed-off-by: lifansheng <lifansheng1@huawei.com>
Change-Id: I45e23bfa131ff9eb044d9b0c1f7908f7763bebb7
2022-06-08 17:27:48 +08:00

283 lines
13 KiB
C++

/*
* 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/global_env.h"
#include "ecmascript/jspandafile/module_data_extractor.h"
#include "ecmascript/module/js_module_manager.h"
#include "ecmascript/module/js_module_source_text.h"
#include "ecmascript/tests/test_helper.h"
#include "ecmascript/linked_hash_table.h"
using namespace panda::ecmascript;
namespace panda::test {
class EcmaModuleTest : public testing::Test {
public:
static void SetUpTestCase()
{
GTEST_LOG_(INFO) << "SetUpTestCase";
}
static void TearDownTestCase()
{
GTEST_LOG_(INFO) << "TearDownCase";
}
void SetUp() override
{
TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
}
void TearDown() override
{
TestHelper::DestroyEcmaVMWithScope(instance, scope);
}
EcmaVM *instance {nullptr};
ecmascript::EcmaHandleScope *scope {nullptr};
JSThread *thread {nullptr};
};
/*
* Feature: Module
* Function: AddImportEntry
* SubFunction: AddImportEntry
* FunctionPoints: Add import entry
* CaseDescription: Add two import item and check module import entries size
*/
HWTEST_F_L0(EcmaModuleTest, AddImportEntry)
{
ObjectFactory *objectFactory = thread->GetEcmaVM()->GetFactory();
JSHandle<SourceTextModule> module = objectFactory->NewSourceTextModule();
JSHandle<ImportEntry> importEntry1 = objectFactory->NewImportEntry();
SourceTextModule::AddImportEntry(thread, module, importEntry1);
JSHandle<ImportEntry> importEntry2 = objectFactory->NewImportEntry();
SourceTextModule::AddImportEntry(thread, module, importEntry2);
JSHandle<TaggedArray> importEntries(thread, module->GetImportEntries());
EXPECT_TRUE(importEntries->GetLength() == 2U);
}
/*
* Feature: Module
* Function: AddLocalExportEntry
* SubFunction: AddLocalExportEntry
* FunctionPoints: Add local export entry
* CaseDescription: Add two local export item and check module local export entries size
*/
HWTEST_F_L0(EcmaModuleTest, AddLocalExportEntry)
{
ObjectFactory *objectFactory = thread->GetEcmaVM()->GetFactory();
JSHandle<SourceTextModule> module = objectFactory->NewSourceTextModule();
JSHandle<ExportEntry> exportEntry1 = objectFactory->NewExportEntry();
SourceTextModule::AddLocalExportEntry(thread, module, exportEntry1);
JSHandle<ExportEntry> exportEntry2 = objectFactory->NewExportEntry();
SourceTextModule::AddLocalExportEntry(thread, module, exportEntry2);
JSHandle<TaggedArray> localExportEntries(thread, module->GetLocalExportEntries());
EXPECT_TRUE(localExportEntries->GetLength() == 2U);
}
/*
* Feature: Module
* Function: AddIndirectExportEntry
* SubFunction: AddIndirectExportEntry
* FunctionPoints: Add indirect export entry
* CaseDescription: Add two indirect export item and check module indirect export entries size
*/
HWTEST_F_L0(EcmaModuleTest, AddIndirectExportEntry)
{
ObjectFactory *objectFactory = thread->GetEcmaVM()->GetFactory();
JSHandle<SourceTextModule> module = objectFactory->NewSourceTextModule();
JSHandle<ExportEntry> exportEntry1 = objectFactory->NewExportEntry();
SourceTextModule::AddIndirectExportEntry(thread, module, exportEntry1);
JSHandle<ExportEntry> exportEntry2 = objectFactory->NewExportEntry();
SourceTextModule::AddIndirectExportEntry(thread, module, exportEntry2);
JSHandle<TaggedArray> indirectExportEntries(thread, module->GetIndirectExportEntries());
EXPECT_TRUE(indirectExportEntries->GetLength() == 2U);
}
/*
* Feature: Module
* Function: StarExportEntries
* SubFunction: StarExportEntries
* FunctionPoints: Add start export entry
* CaseDescription: Add two start export item and check module start export entries size
*/
HWTEST_F_L0(EcmaModuleTest, AddStarExportEntry)
{
ObjectFactory *objectFactory = thread->GetEcmaVM()->GetFactory();
JSHandle<SourceTextModule> module = objectFactory->NewSourceTextModule();
JSHandle<ExportEntry> exportEntry1 = objectFactory->NewExportEntry();
SourceTextModule::AddStarExportEntry(thread, module, exportEntry1);
JSHandle<ExportEntry> exportEntry2 = objectFactory->NewExportEntry();
SourceTextModule::AddStarExportEntry(thread, module, exportEntry2);
JSHandle<TaggedArray> startExportEntries(thread, module->GetStarExportEntries());
EXPECT_TRUE(startExportEntries->GetLength() == 2U);
}
/*
* 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, StoreModuleValue)
{
ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory();
CString localName = "foo";
CString exportName = "bar";
CString value = "hello world";
JSHandle<JSTaggedValue> localNameHandle = JSHandle<JSTaggedValue>::Cast(objFactory->NewFromUtf8(localName));
JSHandle<JSTaggedValue> exportNameHandle = JSHandle<JSTaggedValue>::Cast(objFactory->NewFromUtf8(exportName));
JSHandle<JSTaggedValue> defaultValue = thread->GlobalConstants()->GetHandledUndefined();
JSHandle<ExportEntry> exportEntry =
objFactory->NewExportEntry(exportNameHandle, defaultValue, defaultValue, localNameHandle);
JSHandle<SourceTextModule> module = objFactory->NewSourceTextModule();
SourceTextModule::AddLocalExportEntry(thread, module, exportEntry);
JSHandle<JSTaggedValue> storeKey = JSHandle<JSTaggedValue>::Cast(objFactory->NewFromUtf8(localName));
JSHandle<JSTaggedValue> valueHandle = JSHandle<JSTaggedValue>::Cast(objFactory->NewFromUtf8(value));
module->StoreModuleValue(thread, storeKey, valueHandle);
JSHandle<JSTaggedValue> loadKey = JSHandle<JSTaggedValue>::Cast(objFactory->NewFromUtf8(exportName));
JSTaggedValue loadValue = module->GetModuleValue(thread, loadKey.GetTaggedValue(), false);
EXPECT_EQ(valueHandle.GetTaggedValue(), loadValue);
}
/*
* Feature: Module
* Function: GetModuleValue
* SubFunction: StoreModuleValue/GetModuleValue
* FunctionPoints: load module value from module
* CaseDescription: Simulated implementation of "export default let foo = 'hello world'",
* use "import C from 'xxx' to get default value"
*/
HWTEST_F_L0(EcmaModuleTest, GetModuleValue)
{
ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> defaultValue = thread->GlobalConstants()->GetHandledUndefined();
// export entry
CString exportLocalName = "*default*";
CString exportName = "default";
CString exportValue = "hello world";
JSHandle<JSTaggedValue> exportLocalNameHandle =
JSHandle<JSTaggedValue>::Cast(objFactory->NewFromUtf8(exportLocalName));
JSHandle<JSTaggedValue> exportNameHandle =
JSHandle<JSTaggedValue>::Cast(objFactory->NewFromUtf8(exportName));
JSHandle<ExportEntry> exportEntry =
objFactory->NewExportEntry(exportNameHandle, defaultValue, defaultValue, exportLocalNameHandle);
JSHandle<SourceTextModule> moduleExport = objFactory->NewSourceTextModule();
SourceTextModule::AddLocalExportEntry(thread, moduleExport, exportEntry);
// store module value
JSHandle<JSTaggedValue> exportValueHandle = JSHandle<JSTaggedValue>::Cast(objFactory->NewFromUtf8(exportValue));
moduleExport->StoreModuleValue(thread, exportLocalNameHandle, exportValueHandle);
JSTaggedValue importDefaultValue =
moduleExport->GetModuleValue(thread, exportLocalNameHandle.GetTaggedValue(), false);
EXPECT_EQ(exportValueHandle.GetTaggedValue(), importDefaultValue);
}
/*
* Feature: Module
* Function: EcmaModule use CjsModule
* SubFunction:
* FunctionPoints: EcmaModule use CjsModule
* CaseDescription: Simulated implementation of "module.export.obj = 'hello world cjs'","import {a as b} from "test.js,
* import cjs from "cjs"", print(cjs)", while exectue the ldModuleVar byteCode to load cjs var;
* use ParseCjsModule function to generate Cjsmodule which type is MODULETYPES::CJSMODULE
*/
HWTEST_F_L0(EcmaModuleTest, ParseCjsModule)
{
ObjectFactory* factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> defaultValue = thread->GlobalConstants()->GetHandledUndefined();
// fileName
CString ecmaFileName = "currentModule.js";
CString cjsFileName = "cjs.js";
CString requesFileName = "test.js";
// current module
JSHandle<SourceTextModule> EcmaModule = factory->NewSourceTextModule();
JSHandle<EcmaString> ecmaModuleFilename = factory->NewFromUtf8(ecmaFileName);
JSHandle<JSTaggedValue> importName1 = JSHandle<JSTaggedValue>(factory->NewFromUtf8("a"));
JSHandle<JSTaggedValue> localName1 = JSHandle<JSTaggedValue>(factory->NewFromUtf8("b"));
JSHandle<JSTaggedValue> moduleRequest1 = JSHandle<JSTaggedValue>(factory->NewFromUtf8(requesFileName));
JSHandle<ImportEntry> importEntry1 = factory->NewImportEntry(moduleRequest1, importName1, localName1);
JSHandle<JSTaggedValue> importName2 = JSHandle<JSTaggedValue>(factory->NewFromUtf8("default"));
JSHandle<JSTaggedValue> localName2 = JSHandle<JSTaggedValue>(factory->NewFromUtf8("cjs"));
JSHandle<JSTaggedValue> moduleRequest2 = JSHandle<JSTaggedValue>(factory->NewFromUtf8(cjsFileName));
JSHandle<ImportEntry> importEntry2 = factory->NewImportEntry(moduleRequest2, importName2, localName2);
JSHandle<TaggedArray> requestModuleArray = factory->NewTaggedArray(2);
requestModuleArray->Set(thread, 0, moduleRequest1);
requestModuleArray->Set(thread, 1, moduleRequest2);
SourceTextModule::AddImportEntry(thread, EcmaModule, importEntry1);
SourceTextModule::AddImportEntry(thread, EcmaModule, importEntry2);
EcmaModule->SetRequestedModules(thread, requestModuleArray);
EcmaModule->SetEcmaModuleFilename(thread, ecmaModuleFilename);
EcmaModule->SetStatus(ModuleStatus::UNINSTANTIATED);
EcmaModule->SetTypes(ModuleTypes::ECMAMODULE);
// export module
JSHandle<SourceTextModule> exportModule = factory->NewSourceTextModule();
JSHandle<JSTaggedValue> exportModuleValue =JSHandle<JSTaggedValue>::Cast(exportModule);
JSHandle<EcmaString> exportModuleFilename = factory->NewFromUtf8(requesFileName);
JSHandle<JSTaggedValue> exportName = JSHandle<JSTaggedValue>(factory->NewFromUtf8("a"));
JSHandle<JSTaggedValue> localName3 = JSHandle<JSTaggedValue>(factory->NewFromUtf8("a"));
JSHandle<ExportEntry> exportEntry = factory->NewExportEntry(exportName, defaultValue, defaultValue, localName3);
JSHandle<TaggedArray> requestModuleArray1 = factory->NewTaggedArray(0);
SourceTextModule::AddLocalExportEntry(thread, exportModule, exportEntry);
exportModule->SetRequestedModules(thread, requestModuleArray1);
exportModule->SetEcmaModuleFilename(thread, exportModuleFilename);
exportModule->SetStatus(ModuleStatus::UNINSTANTIATED);
exportModule->SetTypes(ModuleTypes::ECMAMODULE);
// cjs module
JSHandle<JSTaggedValue> cjsModule = ModuleDataExtractor::ParseCjsModule(thread, cjsFileName);
const CString requesFile = "test.abc";
const CString cjsFile = "cjs.abc";
thread->GetEcmaVM()->GetModuleManager()->AddResolveImportedModule(requesFile, exportModuleValue);
thread->GetEcmaVM()->GetModuleManager()->AddResolveImportedModule(cjsFile, cjsModule);
SourceTextModule::Instantiate(thread, EcmaModule);
JSTaggedValue moduleEnvironment = EcmaModule->GetEnvironment();
JSTaggedValue resolvedBinding1 =
LinkedHashMap::Cast(moduleEnvironment.GetTaggedObject())->Get(localName1.GetTaggedValue());
JSTaggedValue resolvedBinding2 =
LinkedHashMap::Cast(moduleEnvironment.GetTaggedObject())->Get(localName2.GetTaggedValue());
ResolvedBinding *binding1 = ResolvedBinding::Cast(resolvedBinding1.GetTaggedObject());
ResolvedBinding *binding2 = ResolvedBinding::Cast(resolvedBinding2.GetTaggedObject());
JSTaggedValue resolvedModule2 = binding2->GetModule();
JSTaggedValue resolvedModule1 = binding1->GetModule();
SourceTextModule *module1 = SourceTextModule::Cast(resolvedModule1.GetHeapObject());
SourceTextModule *module2 = SourceTextModule::Cast(resolvedModule2.GetHeapObject());
CString bindingName1 = ConvertToString(binding1->GetBindingName());
CString bindingName2 = ConvertToString(binding2->GetBindingName());
EXPECT_EQ(module1->GetTypes(), ModuleTypes::ECMAMODULE);
EXPECT_EQ(module2->GetTypes(), ModuleTypes::CJSMODULE);
EXPECT_EQ(bindingName1, "a");
EXPECT_EQ(bindingName2, "default");
}
} // namespace panda::test