v8/test/cctest/test-modules.cc
adamk cf127e8144 [modules] Expand API to allow linking and use it in d8
This patch gives the ability for the embedder to ask for the
module requests of a module, and to pass a ResolveCallback
into Module::Instantiate().

In d8, I've implemented a simple module_map that's used
along with this API to allow loading, compiling, instantiating,
and evaluating a whole tree of modules.

No path resolution is yet implemented, meaning that all
import paths are relative to whatever directory d8 runs
in. And no imports are linked to the exports of the
requested module.

BUG=v8:1569

Review-Url: https://codereview.chromium.org/2351113004
Cr-Commit-Position: refs/heads/master@{#39569}
2016-09-20 23:39:41 +00:00

92 lines
3.1 KiB
C++

// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/flags.h"
#include "test/cctest/cctest.h"
using v8::Context;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::MaybeLocal;
using v8::Module;
using v8::ScriptCompiler;
using v8::ScriptOrigin;
using v8::String;
using v8::Value;
static MaybeLocal<Module> AlwaysEmptyResolveCallback(Local<Context> context,
Local<String> specifier,
Local<Module> referrer,
Local<Value> data) {
return MaybeLocal<Module>();
}
static int g_count = 0;
static MaybeLocal<Module> FailOnSecondCallResolveCallback(
Local<Context> context, Local<String> specifier, Local<Module> referrer,
Local<Value> data) {
if (g_count++ > 0) return MaybeLocal<Module>();
Local<String> source_text = v8_str("");
ScriptOrigin origin(v8_str("module.js"));
ScriptCompiler::Source source(source_text, origin);
return ScriptCompiler::CompileModule(CcTest::isolate(), &source)
.ToLocalChecked();
}
TEST(ModuleInstantiationFailures) {
Isolate* isolate = CcTest::isolate();
HandleScope scope(isolate);
LocalContext env;
Local<String> source_text = v8_str(
"import './foo.js';"
"export {} from './bar.js';");
ScriptOrigin origin(v8_str("file.js"));
ScriptCompiler::Source source(source_text, origin);
Local<Module> module =
ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
CHECK_EQ(2, module->GetModuleRequestsLength());
CHECK(v8_str("./foo.js")->StrictEquals(module->GetModuleRequest(0)));
CHECK(v8_str("./bar.js")->StrictEquals(module->GetModuleRequest(1)));
// Instantiation should fail.
CHECK(!module->Instantiate(env.local(), AlwaysEmptyResolveCallback));
// Start over again...
module = ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
// Instantiation should fail if a sub-module fails to resolve.
g_count = 0;
CHECK(!module->Instantiate(env.local(), FailOnSecondCallResolveCallback));
}
static MaybeLocal<Module> CompileSpecifierAsModuleResolveCallback(
Local<Context> context, Local<String> specifier, Local<Module> referrer,
Local<Value> data) {
ScriptOrigin origin(v8_str("module.js"));
ScriptCompiler::Source source(specifier, origin);
return ScriptCompiler::CompileModule(CcTest::isolate(), &source)
.ToLocalChecked();
}
TEST(ModuleEvaluation) {
Isolate* isolate = CcTest::isolate();
HandleScope scope(isolate);
LocalContext env;
Local<String> source_text = v8_str(
"import 'Object.expando = 5';"
"import 'Object.expando *= 2';");
ScriptOrigin origin(v8_str("file.js"));
ScriptCompiler::Source source(source_text, origin);
Local<Module> module =
ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
CHECK(module->Instantiate(env.local(),
CompileSpecifierAsModuleResolveCallback));
CHECK(!module->Evaluate(env.local()).IsEmpty());
ExpectInt32("Object.expando", 10);
}