mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 09:31:22 -05:00
Add ESM support to libdeno
Introduces deno_execute_mod() for executing ES modules.
This commit is contained in:
parent
cbb18a596a
commit
bba0ed3185
6 changed files with 288 additions and 44 deletions
|
@ -80,7 +80,10 @@ deno::DenoIsolate* unwrap(Deno* d_) {
|
|||
deno_buf deno_get_snapshot(Deno* d_) {
|
||||
auto* d = unwrap(d_);
|
||||
CHECK_NE(d->snapshot_creator_, nullptr);
|
||||
CHECK(d->resolve_module_.IsEmpty());
|
||||
d->ClearModules();
|
||||
d->context_.Reset();
|
||||
|
||||
auto blob = d->snapshot_creator_->CreateBlob(
|
||||
v8::SnapshotCreator::FunctionCodeHandling::kClear);
|
||||
return {nullptr, 0, reinterpret_cast<uint8_t*>(const_cast<char*>(blob.data)),
|
||||
|
@ -123,6 +126,19 @@ int deno_execute(Deno* d_, void* user_data, const char* js_filename,
|
|||
return deno::Execute(context, js_filename, js_source) ? 1 : 0;
|
||||
}
|
||||
|
||||
int deno_execute_mod(Deno* d_, void* user_data, const char* js_filename,
|
||||
const char* js_source) {
|
||||
auto* d = unwrap(d_);
|
||||
deno::UserDataScope user_data_scope(d, user_data);
|
||||
auto* isolate = d->isolate_;
|
||||
v8::Locker locker(isolate);
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
auto context = d->context_.Get(d->isolate_);
|
||||
CHECK(!context.IsEmpty());
|
||||
return deno::ExecuteMod(context, js_filename, js_source) ? 1 : 0;
|
||||
}
|
||||
|
||||
int deno_respond(Deno* d_, void* user_data, int32_t req_id, deno_buf buf) {
|
||||
auto* d = unwrap(d_);
|
||||
if (d->current_args_ != nullptr) {
|
||||
|
@ -193,4 +209,9 @@ void deno_terminate_execution(Deno* d_) {
|
|||
deno::DenoIsolate* d = reinterpret_cast<deno::DenoIsolate*>(d_);
|
||||
d->isolate_->TerminateExecution();
|
||||
}
|
||||
|
||||
void deno_resolve_ok(Deno* d_, const char* filename, const char* source) {
|
||||
deno::DenoIsolate* d = reinterpret_cast<deno::DenoIsolate*>(d_);
|
||||
d->ResolveOk(filename, source);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -285,7 +285,7 @@ void Send(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||
DCHECK_EQ(d->isolate_, isolate);
|
||||
|
||||
v8::Locker locker(d->isolate_);
|
||||
v8::EscapableHandleScope handle_scope(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
CHECK_EQ(d->current_args_, nullptr); // libdeno.send re-entry forbidden.
|
||||
int32_t req_id = d->next_req_id_++;
|
||||
|
@ -343,19 +343,164 @@ void Shared(v8::Local<v8::Name> property,
|
|||
info.GetReturnValue().Set(ab);
|
||||
}
|
||||
|
||||
bool ExecuteV8StringSource(v8::Local<v8::Context> context,
|
||||
const char* js_filename,
|
||||
v8::Local<v8::String> source) {
|
||||
v8::ScriptOrigin ModuleOrigin(v8::Local<v8::Value> resource_name,
|
||||
v8::Isolate* isolate) {
|
||||
return v8::ScriptOrigin(resource_name, v8::Local<v8::Integer>(),
|
||||
v8::Local<v8::Integer>(), v8::Local<v8::Boolean>(),
|
||||
v8::Local<v8::Integer>(), v8::Local<v8::Value>(),
|
||||
v8::Local<v8::Boolean>(), v8::Local<v8::Boolean>(),
|
||||
v8::True(isolate));
|
||||
}
|
||||
|
||||
void DenoIsolate::ClearModules() {
|
||||
for (auto it = module_map_.begin(); it != module_map_.end(); it++) {
|
||||
it->second.Reset();
|
||||
}
|
||||
module_map_.clear();
|
||||
module_filename_map_.clear();
|
||||
}
|
||||
|
||||
void DenoIsolate::RegisterModule(const char* filename,
|
||||
v8::Local<v8::Module> module) {
|
||||
int id = module->GetIdentityHash();
|
||||
|
||||
// v8.h says that identity hash is not necessarily unique. It seems it's quite
|
||||
// unique enough for the purposes of O(1000) modules, so we use it as a
|
||||
// hashmap key here. The following check is to detect collisions.
|
||||
CHECK_EQ(0, module_filename_map_.count(id));
|
||||
|
||||
module_filename_map_[id] = filename;
|
||||
module_map_.emplace(std::piecewise_construct, std::make_tuple(filename),
|
||||
std::make_tuple(isolate_, module));
|
||||
}
|
||||
|
||||
v8::MaybeLocal<v8::Module> CompileModule(v8::Local<v8::Context> context,
|
||||
const char* js_filename,
|
||||
v8::Local<v8::String> source_text) {
|
||||
auto* isolate = context->GetIsolate();
|
||||
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
v8::EscapableHandleScope handle_scope(isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
|
||||
auto origin = ModuleOrigin(v8_str(js_filename, true), isolate);
|
||||
v8::ScriptCompiler::Source source(source_text, origin);
|
||||
|
||||
auto maybe_module = v8::ScriptCompiler::CompileModule(isolate, &source);
|
||||
|
||||
if (!maybe_module.IsEmpty()) {
|
||||
auto module = maybe_module.ToLocalChecked();
|
||||
CHECK_EQ(v8::Module::kUninstantiated, module->GetStatus());
|
||||
DenoIsolate* d = FromIsolate(isolate);
|
||||
d->RegisterModule(js_filename, module);
|
||||
}
|
||||
|
||||
return handle_scope.EscapeMaybe(maybe_module);
|
||||
}
|
||||
|
||||
v8::MaybeLocal<v8::Module> ResolveCallback(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::String> specifier,
|
||||
v8::Local<v8::Module> referrer) {
|
||||
auto* isolate = context->GetIsolate();
|
||||
DenoIsolate* d = FromIsolate(isolate);
|
||||
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
v8::EscapableHandleScope handle_scope(isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
|
||||
int ref_id = referrer->GetIdentityHash();
|
||||
std::string referrer_filename = d->module_filename_map_[ref_id];
|
||||
|
||||
v8::String::Utf8Value specifier_(isolate, specifier);
|
||||
const char* specifier_c = ToCString(specifier_);
|
||||
|
||||
CHECK_NE(d->resolve_cb_, nullptr);
|
||||
d->resolve_cb_(d->user_data_, specifier_c, referrer_filename.c_str());
|
||||
|
||||
if (d->resolve_module_.IsEmpty()) {
|
||||
// Resolution Error.
|
||||
isolate->ThrowException(v8_str("module resolution error"));
|
||||
return v8::MaybeLocal<v8::Module>();
|
||||
} else {
|
||||
auto module = d->resolve_module_.Get(isolate);
|
||||
d->resolve_module_.Reset();
|
||||
return handle_scope.Escape(module);
|
||||
}
|
||||
}
|
||||
|
||||
void DenoIsolate::ResolveOk(const char* filename, const char* source) {
|
||||
CHECK(resolve_module_.IsEmpty());
|
||||
auto count = module_map_.count(filename);
|
||||
if (count == 1) {
|
||||
auto module = module_map_[filename].Get(isolate_);
|
||||
resolve_module_.Reset(isolate_, module);
|
||||
} else {
|
||||
CHECK_EQ(count, 0);
|
||||
v8::HandleScope handle_scope(isolate_);
|
||||
auto context = context_.Get(isolate_);
|
||||
v8::TryCatch try_catch(isolate_);
|
||||
auto maybe_module = CompileModule(context, filename, v8_str(source));
|
||||
if (maybe_module.IsEmpty()) {
|
||||
DCHECK(try_catch.HasCaught());
|
||||
HandleException(context, try_catch.Exception());
|
||||
} else {
|
||||
auto module = maybe_module.ToLocalChecked();
|
||||
resolve_module_.Reset(isolate_, module);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ExecuteMod(v8::Local<v8::Context> context, const char* js_filename,
|
||||
const char* js_source) {
|
||||
auto* isolate = context->GetIsolate();
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
v8::Context::Scope context_scope(context);
|
||||
|
||||
auto source = v8_str(js_source, true);
|
||||
|
||||
v8::TryCatch try_catch(isolate);
|
||||
|
||||
auto maybe_module = CompileModule(context, js_filename, source);
|
||||
|
||||
if (maybe_module.IsEmpty()) {
|
||||
DCHECK(try_catch.HasCaught());
|
||||
HandleException(context, try_catch.Exception());
|
||||
return false;
|
||||
}
|
||||
DCHECK(!try_catch.HasCaught());
|
||||
|
||||
auto module = maybe_module.ToLocalChecked();
|
||||
auto maybe_ok = module->InstantiateModule(context, ResolveCallback);
|
||||
if (maybe_ok.IsNothing()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CHECK_EQ(v8::Module::kInstantiated, module->GetStatus());
|
||||
auto result = module->Evaluate(context);
|
||||
|
||||
if (result.IsEmpty()) {
|
||||
DCHECK(try_catch.HasCaught());
|
||||
CHECK_EQ(v8::Module::kErrored, module->GetStatus());
|
||||
HandleException(context, module->GetException());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Execute(v8::Local<v8::Context> context, const char* js_filename,
|
||||
const char* js_source) {
|
||||
auto* isolate = context->GetIsolate();
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
|
||||
auto source = v8_str(js_source, true);
|
||||
auto name = v8_str(js_filename, true);
|
||||
|
||||
v8::TryCatch try_catch(isolate);
|
||||
|
||||
v8::ScriptOrigin origin(name);
|
||||
|
||||
auto script = v8::Script::Compile(context, source, &origin);
|
||||
|
@ -377,15 +522,6 @@ bool ExecuteV8StringSource(v8::Local<v8::Context> context,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Execute(v8::Local<v8::Context> context, const char* js_filename,
|
||||
const char* js_source) {
|
||||
auto* isolate = context->GetIsolate();
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
auto source = v8_str(js_source, true);
|
||||
return ExecuteV8StringSource(context, js_filename, source);
|
||||
}
|
||||
|
||||
void InitializeContext(v8::Isolate* isolate, v8::Local<v8::Context> context) {
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
|
|
|
@ -25,15 +25,26 @@ typedef struct deno_s Deno;
|
|||
typedef void (*deno_recv_cb)(void* user_data, int32_t req_id,
|
||||
deno_buf control_buf, deno_buf data_buf);
|
||||
|
||||
// A callback to implement ES Module imports. User must call deno_resolve_ok()
|
||||
// at most once during deno_resolve_cb. If deno_resolve_ok() is not called, the
|
||||
// specifier is considered invalid and will issue an error in JS. The reason
|
||||
// deno_resolve_cb does not return deno_module is to avoid unnecessary heap
|
||||
// allocations.
|
||||
typedef void (*deno_resolve_cb)(void* user_data, const char* specifier,
|
||||
const char* referrer);
|
||||
|
||||
void deno_resolve_ok(Deno* d, const char* filename, const char* source);
|
||||
|
||||
void deno_init();
|
||||
const char* deno_v8_version();
|
||||
void deno_set_v8_flags(int* argc, char** argv);
|
||||
|
||||
typedef struct {
|
||||
int will_snapshot; // Default 0. If calling deno_get_snapshot 1.
|
||||
deno_buf load_snapshot; // Optionally: A deno_buf from deno_get_snapshot.
|
||||
deno_buf shared; // Shared buffer to be mapped to libdeno.shared
|
||||
deno_recv_cb recv_cb; // Maps to libdeno.send() calls.
|
||||
int will_snapshot; // Default 0. If calling deno_get_snapshot 1.
|
||||
deno_buf load_snapshot; // Optionally: A deno_buf from deno_get_snapshot.
|
||||
deno_buf shared; // Shared buffer to be mapped to libdeno.shared
|
||||
deno_recv_cb recv_cb; // Maps to libdeno.send() calls.
|
||||
deno_resolve_cb resolve_cb; // Each import calls this.
|
||||
} deno_config;
|
||||
|
||||
// Create a new deno isolate.
|
||||
|
@ -47,9 +58,10 @@ deno_buf deno_get_snapshot(Deno* d);
|
|||
|
||||
void deno_delete(Deno* d);
|
||||
|
||||
// Returns false on error.
|
||||
// Compile and execute a traditional JavaScript script that does not use
|
||||
// module import statements.
|
||||
// Return value: 0 = fail, 1 = success
|
||||
// Get error text with deno_last_exception().
|
||||
// 0 = fail, 1 = success
|
||||
//
|
||||
// TODO change return value to be const char*. On success the return
|
||||
// value is nullptr, on failure it is the JSON exception text that
|
||||
|
@ -59,6 +71,13 @@ void deno_delete(Deno* d);
|
|||
int deno_execute(Deno* d, void* user_data, const char* js_filename,
|
||||
const char* js_source);
|
||||
|
||||
// Compile and execute an ES module. Caller must have provided a deno_resolve_cb
|
||||
// when instantiating the Deno object.
|
||||
// Return value: 0 = fail, 1 = success
|
||||
// Get error text with deno_last_exception().
|
||||
int deno_execute_mod(Deno* d, void* user_data, const char* js_filename,
|
||||
const char* js_source);
|
||||
|
||||
// deno_respond sends up to one message back for every deno_recv_cb made.
|
||||
//
|
||||
// If this is called during deno_recv_cb, the issuing libdeno.send() in
|
||||
|
|
|
@ -20,6 +20,7 @@ class DenoIsolate {
|
|||
snapshot_creator_(nullptr),
|
||||
global_import_buf_ptr_(nullptr),
|
||||
recv_cb_(config.recv_cb),
|
||||
resolve_cb_(config.resolve_cb),
|
||||
next_req_id_(0),
|
||||
user_data_(nullptr) {
|
||||
array_buffer_allocator_ = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
|
||||
|
@ -40,6 +41,9 @@ class DenoIsolate {
|
|||
}
|
||||
|
||||
void AddIsolate(v8::Isolate* isolate);
|
||||
void RegisterModule(const char* filename, v8::Local<v8::Module> module);
|
||||
void ResolveOk(const char* filename, const char* source);
|
||||
void ClearModules();
|
||||
|
||||
v8::Isolate* isolate_;
|
||||
v8::ArrayBuffer::Allocator* array_buffer_allocator_;
|
||||
|
@ -48,9 +52,17 @@ class DenoIsolate {
|
|||
v8::SnapshotCreator* snapshot_creator_;
|
||||
void* global_import_buf_ptr_;
|
||||
deno_recv_cb recv_cb_;
|
||||
deno_resolve_cb resolve_cb_;
|
||||
int32_t next_req_id_;
|
||||
void* user_data_;
|
||||
|
||||
// identity hash -> filename
|
||||
std::map<int, std::string> module_filename_map_;
|
||||
// filename -> Module
|
||||
std::map<std::string, v8::Persistent<v8::Module>> module_map_;
|
||||
// Set by deno_resolve_ok
|
||||
v8::Persistent<v8::Module> resolve_module_;
|
||||
|
||||
v8::Persistent<v8::Context> context_;
|
||||
std::map<int32_t, v8::Persistent<v8::Value>> async_data_map_;
|
||||
std::map<int, v8::Persistent<v8::Value>> pending_promise_map_;
|
||||
|
@ -121,6 +133,8 @@ void DeleteDataRef(DenoIsolate* d, int32_t req_id);
|
|||
|
||||
bool Execute(v8::Local<v8::Context> context, const char* js_filename,
|
||||
const char* js_source);
|
||||
bool ExecuteMod(v8::Local<v8::Context> context, const char* js_filename,
|
||||
const char* js_source);
|
||||
|
||||
} // namespace deno
|
||||
|
||||
|
|
|
@ -3,24 +3,18 @@
|
|||
|
||||
TEST(LibDenoTest, InitializesCorrectly) {
|
||||
EXPECT_NE(snapshot.data_ptr, nullptr);
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr});
|
||||
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "1 + 2"));
|
||||
deno_delete(d);
|
||||
}
|
||||
|
||||
TEST(LibDenoTest, InitializesCorrectlyWithoutSnapshot) {
|
||||
Deno* d = deno_new(deno_config{0, empty, empty, nullptr});
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
|
||||
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "1 + 2"));
|
||||
deno_delete(d);
|
||||
}
|
||||
|
||||
TEST(LibDenoTest, Snapshotter) {
|
||||
Deno* d1 = deno_new(deno_config{1, empty, empty, nullptr});
|
||||
Deno* d1 = deno_new(deno_config{1, empty, empty, nullptr, nullptr});
|
||||
EXPECT_TRUE(deno_execute(d1, nullptr, "a.js", "a = 1 + 2"));
|
||||
deno_buf test_snapshot = deno_get_snapshot(d1);
|
||||
deno_delete(d1);
|
||||
|
||||
Deno* d2 = deno_new(deno_config{0, test_snapshot, empty, nullptr});
|
||||
Deno* d2 = deno_new(deno_config{0, test_snapshot, empty, nullptr, nullptr});
|
||||
EXPECT_TRUE(
|
||||
deno_execute(d2, nullptr, "b.js", "if (a != 3) throw Error('x');"));
|
||||
deno_delete(d2);
|
||||
|
@ -29,14 +23,14 @@ TEST(LibDenoTest, Snapshotter) {
|
|||
}
|
||||
|
||||
TEST(LibDenoTest, CanCallFunction) {
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr});
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
|
||||
EXPECT_TRUE(deno_execute(d, nullptr, "a.js",
|
||||
"if (CanCallFunction() != 'foo') throw Error();"));
|
||||
deno_delete(d);
|
||||
}
|
||||
|
||||
TEST(LibDenoTest, ErrorsCorrectly) {
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr});
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
|
||||
EXPECT_FALSE(deno_execute(d, nullptr, "a.js", "throw Error()"));
|
||||
deno_delete(d);
|
||||
}
|
||||
|
@ -81,7 +75,7 @@ TEST(LibDenoTest, RecvReturnEmpty) {
|
|||
EXPECT_EQ(buf.data_ptr[1], 'b');
|
||||
EXPECT_EQ(buf.data_ptr[2], 'c');
|
||||
};
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb});
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, nullptr});
|
||||
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "RecvReturnEmpty()"));
|
||||
EXPECT_EQ(count, 2);
|
||||
deno_delete(d);
|
||||
|
@ -99,14 +93,14 @@ TEST(LibDenoTest, RecvReturnBar) {
|
|||
EXPECT_EQ(buf.data_ptr[2], 'c');
|
||||
deno_respond(d, user_data, req_id, strbuf("bar"));
|
||||
};
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb});
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, nullptr});
|
||||
EXPECT_TRUE(deno_execute(d, d, "a.js", "RecvReturnBar()"));
|
||||
EXPECT_EQ(count, 1);
|
||||
deno_delete(d);
|
||||
}
|
||||
|
||||
TEST(LibDenoTest, DoubleRecvFails) {
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr});
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
|
||||
EXPECT_FALSE(deno_execute(d, nullptr, "a.js", "DoubleRecvFails()"));
|
||||
deno_delete(d);
|
||||
}
|
||||
|
@ -140,7 +134,7 @@ TEST(LibDenoTest, SendRecvSlice) {
|
|||
// Send back.
|
||||
deno_respond(d, user_data, req_id, buf2);
|
||||
};
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb});
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, nullptr});
|
||||
EXPECT_TRUE(deno_execute(d, d, "a.js", "SendRecvSlice()"));
|
||||
EXPECT_EQ(count, 5);
|
||||
deno_delete(d);
|
||||
|
@ -157,26 +151,26 @@ TEST(LibDenoTest, JSSendArrayBufferViewTypes) {
|
|||
EXPECT_EQ(buf.alloc_len, 4321u);
|
||||
EXPECT_EQ(buf.data_ptr[0], count);
|
||||
};
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb});
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, nullptr});
|
||||
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "JSSendArrayBufferViewTypes()"));
|
||||
EXPECT_EQ(count, 3);
|
||||
deno_delete(d);
|
||||
}
|
||||
|
||||
TEST(LibDenoTest, TypedArraySnapshots) {
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr});
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
|
||||
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "TypedArraySnapshots()"));
|
||||
deno_delete(d);
|
||||
}
|
||||
|
||||
TEST(LibDenoTest, SnapshotBug) {
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr});
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
|
||||
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "SnapshotBug()"));
|
||||
deno_delete(d);
|
||||
}
|
||||
|
||||
TEST(LibDenoTest, GlobalErrorHandling) {
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr});
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
|
||||
EXPECT_FALSE(deno_execute(d, nullptr, "a.js", "GlobalErrorHandling()"));
|
||||
// We only check that it starts with this string, so we don't have to check
|
||||
// the second frame, which contains line numbers in libdeno_test.js and may
|
||||
|
@ -204,7 +198,7 @@ TEST(LibDenoTest, DataBuf) {
|
|||
EXPECT_EQ(buf.data_ptr[0], 1);
|
||||
EXPECT_EQ(buf.data_ptr[1], 2);
|
||||
};
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb});
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, nullptr});
|
||||
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "DataBuf()"));
|
||||
EXPECT_EQ(count, 1);
|
||||
// data_buf was subsequently changed in JS, let's check that our copy reflects
|
||||
|
@ -217,7 +211,7 @@ TEST(LibDenoTest, DataBuf) {
|
|||
TEST(LibDenoTest, CheckPromiseErrors) {
|
||||
static int count = 0;
|
||||
auto recv_cb = [](auto _, int req_id, auto buf, auto data_buf) { count++; };
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb});
|
||||
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, nullptr});
|
||||
EXPECT_EQ(deno_last_exception(d), nullptr);
|
||||
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "CheckPromiseErrors()"));
|
||||
EXPECT_EQ(deno_last_exception(d), nullptr);
|
||||
|
@ -230,7 +224,7 @@ TEST(LibDenoTest, CheckPromiseErrors) {
|
|||
}
|
||||
|
||||
TEST(LibDenoTest, LastException) {
|
||||
Deno* d = deno_new(deno_config{0, empty, empty, nullptr});
|
||||
Deno* d = deno_new(deno_config{0, empty, empty, nullptr, nullptr});
|
||||
EXPECT_EQ(deno_last_exception(d), nullptr);
|
||||
EXPECT_FALSE(deno_execute(d, nullptr, "a.js", "\n\nthrow Error('boo');\n\n"));
|
||||
EXPECT_STREQ(deno_last_exception(d),
|
||||
|
@ -245,10 +239,70 @@ TEST(LibDenoTest, LastException) {
|
|||
TEST(LibDenoTest, Shared) {
|
||||
uint8_t s[] = {0, 1, 2};
|
||||
deno_buf shared = {nullptr, 0, s, 3};
|
||||
Deno* d = deno_new(deno_config{0, snapshot, shared, nullptr});
|
||||
Deno* d = deno_new(deno_config{0, snapshot, shared, nullptr, nullptr});
|
||||
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "Shared()"));
|
||||
EXPECT_EQ(s[0], 42);
|
||||
EXPECT_EQ(s[1], 43);
|
||||
EXPECT_EQ(s[2], 44);
|
||||
deno_delete(d);
|
||||
}
|
||||
|
||||
static const char* mod_a =
|
||||
"import { retb } from 'b.js'\n"
|
||||
"if (retb() != 'b') throw Error();";
|
||||
|
||||
static const char* mod_b = "export function retb() { return 'b' }";
|
||||
|
||||
TEST(LibDenoTest, ModuleResolution) {
|
||||
static int count = 0;
|
||||
auto resolve_cb = [](void* user_data, const char* specifier,
|
||||
const char* referrer) {
|
||||
EXPECT_STREQ(specifier, "b.js");
|
||||
EXPECT_STREQ(referrer, "a.js");
|
||||
count++;
|
||||
auto d = reinterpret_cast<Deno*>(user_data);
|
||||
deno_resolve_ok(d, "b.js", mod_b);
|
||||
};
|
||||
Deno* d = deno_new(deno_config{0, empty, empty, nullptr, resolve_cb});
|
||||
EXPECT_TRUE(deno_execute_mod(d, d, "a.js", mod_a));
|
||||
EXPECT_EQ(count, 1);
|
||||
deno_delete(d);
|
||||
}
|
||||
|
||||
TEST(LibDenoTest, ModuleResolutionFail) {
|
||||
static int count = 0;
|
||||
auto resolve_cb = [](void* user_data, const char* specifier,
|
||||
const char* referrer) {
|
||||
EXPECT_STREQ(specifier, "b.js");
|
||||
EXPECT_STREQ(referrer, "a.js");
|
||||
count++;
|
||||
// Do not call deno_resolve_ok();
|
||||
};
|
||||
Deno* d = deno_new(deno_config{0, empty, empty, nullptr, resolve_cb});
|
||||
EXPECT_FALSE(deno_execute_mod(d, d, "a.js", mod_a));
|
||||
EXPECT_EQ(count, 1);
|
||||
deno_delete(d);
|
||||
}
|
||||
|
||||
TEST(LibDenoTest, ModuleSnapshot) {
|
||||
Deno* d1 = deno_new(deno_config{1, empty, empty, nullptr, nullptr});
|
||||
EXPECT_TRUE(deno_execute_mod(d1, nullptr, "x.js",
|
||||
"const globalEval = eval\n"
|
||||
"const global = globalEval('this')\n"
|
||||
"global.a = 1 + 2"));
|
||||
deno_buf test_snapshot = deno_get_snapshot(d1);
|
||||
deno_delete(d1);
|
||||
|
||||
const char* y_src = "if (a != 3) throw Error('x');";
|
||||
|
||||
deno_config config{0, test_snapshot, empty, nullptr, nullptr};
|
||||
Deno* d2 = deno_new(config);
|
||||
EXPECT_TRUE(deno_execute(d2, nullptr, "y.js", y_src));
|
||||
deno_delete(d2);
|
||||
|
||||
Deno* d3 = deno_new(config);
|
||||
EXPECT_TRUE(deno_execute_mod(d3, nullptr, "y.js", y_src));
|
||||
deno_delete(d3);
|
||||
|
||||
delete[] test_snapshot.data_ptr;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ int main(int argc, char** argv) {
|
|||
CHECK(deno::ReadFileToString(js_fn, &js_source));
|
||||
|
||||
deno_init();
|
||||
deno_config config = {1, deno::empty_buf, deno::empty_buf, nullptr};
|
||||
deno_config config = {1, deno::empty_buf, deno::empty_buf, nullptr, nullptr};
|
||||
Deno* d = deno_new(config);
|
||||
|
||||
int r = deno_execute(d, nullptr, js_fn, js_source.c_str());
|
||||
|
|
Loading…
Add table
Reference in a new issue