1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/memory/scoped_ptr.h"
6 #include "extensions/renderer/module_system.h"
7 #include "extensions/renderer/module_system_test.h"
8 #include "gin/modules/module_registry.h"
10 namespace extensions
{
12 class CounterNatives
: public ObjectBackedNativeHandler
{
14 explicit CounterNatives(ScriptContext
* context
)
15 : ObjectBackedNativeHandler(context
), counter_(0) {
17 base::Bind(&CounterNatives::Get
, base::Unretained(this)));
20 base::Bind(&CounterNatives::Increment
, base::Unretained(this)));
23 void Get(const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
24 args
.GetReturnValue().Set(static_cast<int32_t>(counter_
));
27 void Increment(const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
35 class TestExceptionHandler
: public ModuleSystem::ExceptionHandler
{
37 TestExceptionHandler() : handled_exception_(false) {}
39 void HandleUncaughtException(const v8::TryCatch
& try_catch
) override
{
40 handled_exception_
= true;
43 bool handled_exception() const { return handled_exception_
; }
46 bool handled_exception_
;
49 TEST_F(ModuleSystemTest
, TestExceptionHandling
) {
50 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
51 env()->module_system());
52 TestExceptionHandler
* handler
= new TestExceptionHandler
;
53 scoped_ptr
<ModuleSystem::ExceptionHandler
> scoped_handler(handler
);
54 ASSERT_FALSE(handler
->handled_exception());
55 env()->module_system()->SetExceptionHandlerForTest(scoped_handler
.Pass());
57 env()->RegisterModule("test", "throw 'hi';");
58 env()->module_system()->Require("test");
59 ASSERT_TRUE(handler
->handled_exception());
61 ExpectNoAssertionsMade();
64 TEST_F(ModuleSystemTest
, TestRequire
) {
65 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
66 env()->module_system());
67 env()->RegisterModule("add",
68 "exports.Add = function(x, y) { return x + y; };");
69 env()->RegisterModule("test",
70 "var Add = require('add').Add;"
71 "requireNative('assert').AssertTrue(Add(3, 5) == 8);");
72 env()->module_system()->Require("test");
75 TEST_F(ModuleSystemTest
, TestNestedRequire
) {
76 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
77 env()->module_system());
78 env()->RegisterModule("add",
79 "exports.Add = function(x, y) { return x + y; };");
80 env()->RegisterModule("double",
81 "var Add = require('add').Add;"
82 "exports.Double = function(x) { return Add(x, x); };");
83 env()->RegisterModule("test",
84 "var Double = require('double').Double;"
85 "requireNative('assert').AssertTrue(Double(3) == 6);");
86 env()->module_system()->Require("test");
89 TEST_F(ModuleSystemTest
, TestModuleInsulation
) {
90 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
91 env()->module_system());
92 env()->RegisterModule("x",
94 "exports.X = function() { return x; };");
95 env()->RegisterModule("y",
98 "exports.Y = function() { return x; };");
99 env()->RegisterModule("test",
100 "var Y = require('y').Y;"
101 "var X = require('x').X;"
102 "var assert = requireNative('assert');"
103 "assert.AssertTrue(!this.hasOwnProperty('x'));"
104 "assert.AssertTrue(Y() == 15);"
105 "assert.AssertTrue(X() == 10);");
106 env()->module_system()->Require("test");
109 TEST_F(ModuleSystemTest
, TestNativesAreDisabledOutsideANativesEnabledScope
) {
110 env()->RegisterModule("test",
113 " assert = requireNative('assert');"
115 " var caught = true;"
118 " assert.AssertTrue(true);"
120 env()->module_system()->Require("test");
121 ExpectNoAssertionsMade();
124 TEST_F(ModuleSystemTest
, TestNativesAreEnabledWithinANativesEnabledScope
) {
125 env()->RegisterModule("test",
126 "var assert = requireNative('assert');"
127 "assert.AssertTrue(true);");
130 ModuleSystem::NativesEnabledScope
natives_enabled(env()->module_system());
132 ModuleSystem::NativesEnabledScope
natives_enabled_inner(
133 env()->module_system());
135 env()->module_system()->Require("test");
139 TEST_F(ModuleSystemTest
, TestLazyField
) {
140 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
141 env()->module_system());
142 env()->RegisterModule("lazy", "exports.x = 5;");
144 v8::Handle
<v8::Object
> object
= env()->CreateGlobal("object");
146 env()->module_system()->SetLazyField(object
, "blah", "lazy", "x");
148 env()->RegisterModule("test",
149 "var assert = requireNative('assert');"
150 "assert.AssertTrue(object.blah == 5);");
151 env()->module_system()->Require("test");
154 TEST_F(ModuleSystemTest
, TestLazyFieldYieldingObject
) {
155 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
156 env()->module_system());
157 env()->RegisterModule(
160 "object.__defineGetter__('z', function() { return 1; });"
162 "object.y = function() { return 10; };"
163 "exports.object = object;");
165 v8::Handle
<v8::Object
> object
= env()->CreateGlobal("object");
167 env()->module_system()->SetLazyField(object
, "thing", "lazy", "object");
169 env()->RegisterModule("test",
170 "var assert = requireNative('assert');"
171 "assert.AssertTrue(object.thing.x == 5);"
172 "assert.AssertTrue(object.thing.y() == 10);"
173 "assert.AssertTrue(object.thing.z == 1);");
174 env()->module_system()->Require("test");
177 TEST_F(ModuleSystemTest
, TestLazyFieldIsOnlyEvaledOnce
) {
178 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
179 env()->module_system());
180 env()->module_system()->RegisterNativeHandler(
182 scoped_ptr
<NativeHandler
>(new CounterNatives(env()->context())));
183 env()->RegisterModule("lazy",
184 "requireNative('counter').Increment();"
187 v8::Handle
<v8::Object
> object
= env()->CreateGlobal("object");
189 env()->module_system()->SetLazyField(object
, "x", "lazy", "x");
191 env()->RegisterModule("test",
192 "var assert = requireNative('assert');"
193 "var counter = requireNative('counter');"
194 "assert.AssertTrue(counter.Get() == 0);"
196 "assert.AssertTrue(counter.Get() == 1);"
198 "assert.AssertTrue(counter.Get() == 1);");
199 env()->module_system()->Require("test");
202 TEST_F(ModuleSystemTest
, TestRequireNativesAfterLazyEvaluation
) {
203 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
204 env()->module_system());
205 env()->RegisterModule("lazy", "exports.x = 5;");
206 v8::Handle
<v8::Object
> object
= env()->CreateGlobal("object");
208 env()->module_system()->SetLazyField(object
, "x", "lazy", "x");
209 env()->RegisterModule("test",
211 "requireNative('assert').AssertTrue(true);");
212 env()->module_system()->Require("test");
215 TEST_F(ModuleSystemTest
, TestTransitiveRequire
) {
216 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
217 env()->module_system());
218 env()->RegisterModule("dependency", "exports.x = 5;");
219 env()->RegisterModule("lazy", "exports.output = require('dependency');");
221 v8::Handle
<v8::Object
> object
= env()->CreateGlobal("object");
223 env()->module_system()->SetLazyField(object
, "thing", "lazy", "output");
225 env()->RegisterModule("test",
226 "var assert = requireNative('assert');"
227 "assert.AssertTrue(object.thing.x == 5);");
228 env()->module_system()->Require("test");
231 TEST_F(ModuleSystemTest
, TestModulesOnlyGetEvaledOnce
) {
232 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
233 env()->module_system());
234 env()->module_system()->RegisterNativeHandler(
236 scoped_ptr
<NativeHandler
>(new CounterNatives(env()->context())));
238 env()->RegisterModule("incrementsWhenEvaled",
239 "requireNative('counter').Increment();");
240 env()->RegisterModule("test",
241 "var assert = requireNative('assert');"
242 "var counter = requireNative('counter');"
243 "assert.AssertTrue(counter.Get() == 0);"
244 "require('incrementsWhenEvaled');"
245 "assert.AssertTrue(counter.Get() == 1);"
246 "require('incrementsWhenEvaled');"
247 "assert.AssertTrue(counter.Get() == 1);");
249 env()->module_system()->Require("test");
252 TEST_F(ModuleSystemTest
, TestOverrideNativeHandler
) {
253 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
254 env()->module_system());
255 env()->OverrideNativeHandler("assert", "exports.AssertTrue = function() {};");
256 env()->RegisterModule("test", "requireNative('assert').AssertTrue(true);");
257 ExpectNoAssertionsMade();
258 env()->module_system()->Require("test");
261 TEST_F(ModuleSystemTest
, TestOverrideNonExistentNativeHandler
) {
262 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
263 env()->module_system());
264 env()->OverrideNativeHandler("thing", "exports.x = 5;");
265 env()->RegisterModule("test",
266 "var assert = requireNative('assert');"
267 "assert.AssertTrue(requireNative('thing').x == 5);");
268 env()->module_system()->Require("test");
271 TEST_F(ModuleSystemTest
, TestRequireAsync
) {
272 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
273 env()->module_system());
274 env()->RegisterModule("add",
275 "define('add', [], function() {"
276 " return { Add: function(x, y) { return x + y; } };"
278 env()->RegisterModule("math",
279 "define('math', ['add'], function(add) {"
280 " return { Add: add.Add };"
282 env()->RegisterModule(
284 "requireAsync('math').then(function(math) {"
285 " requireNative('assert').AssertTrue(math.Add(3, 5) == 8);"
287 env()->module_system()->Require("test");
288 RunResolvedPromises();
291 TEST_F(ModuleSystemTest
, TestRequireAsyncInParallel
) {
292 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
293 env()->module_system());
294 env()->RegisterModule("add",
295 "define('add', [], function() {"
296 " return { Add: function(x, y) { return x + y; } };"
298 env()->RegisterModule(
300 "define('subtract', [], function() {"
301 " return { Subtract: function(x, y) { return x - y; } };"
303 env()->RegisterModule(
305 "exports.AddAndSubtract = function(x, y, z) {"
306 " return Promise.all([requireAsync('add'),"
307 " requireAsync('subtract')"
308 " ]).then(function(modules) {"
309 " return modules[1].Subtract(modules[0].Add(x, y), z);"
312 env()->RegisterModule("test",
313 "var AddAndSubtract = require('math').AddAndSubtract;"
314 "AddAndSubtract(3, 5, 2).then(function(result) {"
315 " requireNative('assert').AssertTrue(result == 6);"
317 env()->module_system()->Require("test");
318 RunResolvedPromises();
321 TEST_F(ModuleSystemTest
, TestNestedRequireAsyncs
) {
322 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
323 env()->module_system());
324 env()->RegisterModule("first",
325 "define('first', [], function() {"
326 " return { next: 'second' };"
328 env()->RegisterModule("second",
329 "define('second', [], function() {"
330 " return { next: '' };"
332 env()->RegisterModule(
334 "requireAsync('first').then(function(module) {"
335 " return requireAsync(module.next)"
336 "}).then(function(module) {"
337 " requireNative('assert').AssertTrue(module.next === '');"
339 env()->module_system()->Require("test");
340 RunResolvedPromises();
343 TEST_F(ModuleSystemTest
, TestRequireFromAMDModule
) {
344 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
345 env()->module_system());
346 env()->RegisterModule("add",
347 "exports.Add = function(x, y) { return x + y; };");
348 env()->RegisterModule("math",
349 "define('math', [], function() {"
350 " var add = require('add');"
351 " return { Add: add.Add };"
353 env()->RegisterModule(
355 "requireAsync('math').then(function(math) {"
356 " requireNative('assert').AssertTrue(math.Add(3, 5) == 8);"
358 env()->module_system()->Require("test");
359 RunResolvedPromises();
362 TEST_F(ModuleSystemTest
, TestRequireAsyncFromAMDModule
) {
363 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
364 env()->module_system());
365 env()->RegisterModule("add",
366 "define('add', [], function() {"
367 " return { Add: function(x, y) { return x + y; } };"
369 env()->RegisterModule("math",
370 "define('math', [], function() {"
371 " function Add(x, y) {"
372 " return requireAsync('add').then(function(add) {"
373 " return add.Add(x, y);"
376 " return { Add: Add };"
378 env()->RegisterModule("test",
379 "requireAsync('math').then(function(math) {"
380 " return math.Add(3, 6);"
381 "}).then(function(result) {"
382 " requireNative('assert').AssertTrue(result == 9);"
384 env()->module_system()->Require("test");
385 RunResolvedPromises();
388 TEST_F(ModuleSystemTest
, TestRequireAsyncFromAnotherContext
) {
389 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
390 env()->module_system());
391 env()->RegisterModule(
393 "requireAsync('natives').then(function(natives) {"
394 " natives.requireAsync('ping').then(function(ping) {"
396 " }).then(function(result) {"
397 " requireNative('assert').AssertTrue(result == 'pong');"
400 scoped_ptr
<ModuleSystemTestEnvironment
> other_env
= CreateEnvironment();
401 other_env
->RegisterModule("ping",
402 "define('ping', ['natives'], function(natives) {"
403 " return function() {"
407 gin::ModuleRegistry::From(env()->context()->v8_context())->AddBuiltinModule(
408 env()->isolate(), "natives", other_env
->module_system()->NewInstance());
409 gin::ModuleRegistry::From(other_env
->context()->v8_context())
411 env()->isolate(), "natives", env()->module_system()->NewInstance());
412 env()->module_system()->Require("test");
413 RunResolvedPromises();
416 TEST_F(ModuleSystemTest
, TestRequireAsyncBetweenContexts
) {
417 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
418 env()->module_system());
419 env()->RegisterModule("pong",
420 "define('pong', [], function() {"
421 " return function() { return 'done'; };"
423 env()->RegisterModule(
425 "requireAsync('natives').then(function(natives) {"
426 " natives.requireAsync('ping').then(function(ping) {"
428 " }).then(function(pong) {"
430 " }).then(function(result) {"
431 " requireNative('assert').AssertTrue(result == 'done');"
434 scoped_ptr
<ModuleSystemTestEnvironment
> other_env
= CreateEnvironment();
435 other_env
->RegisterModule("ping",
436 "define('ping', ['natives'], function(natives) {"
437 " return function() {"
438 " return natives.requireAsync('pong');"
441 gin::ModuleRegistry::From(env()->context()->v8_context())->AddBuiltinModule(
442 env()->isolate(), "natives", other_env
->module_system()->NewInstance());
443 gin::ModuleRegistry::From(other_env
->context()->v8_context())
445 env()->isolate(), "natives", env()->module_system()->NewInstance());
446 env()->module_system()->Require("test");
447 RunResolvedPromises();
450 TEST_F(ModuleSystemTest
, TestRequireAsyncFromContextWithNoModuleRegistry
) {
451 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
452 env()->module_system());
453 env()->RegisterModule("test",
454 "requireAsync('natives').then(function(natives) {"
455 " var AssertTrue = requireNative('assert').AssertTrue;"
456 " natives.requireAsync('foo').then(function() {"
457 " AssertTrue(false);"
458 " }).catch(function(error) {"
459 " AssertTrue(error.message == "
460 " 'Extension view no longer exists');"
463 scoped_ptr
<ModuleSystemTestEnvironment
> other_env
= CreateEnvironment();
464 gin::ModuleRegistry::From(env()->context()->v8_context())->AddBuiltinModule(
465 env()->isolate(), "natives", other_env
->module_system()->NewInstance());
466 other_env
->ShutdownGin();
467 env()->module_system()->Require("test");
468 RunResolvedPromises();
471 TEST_F(ModuleSystemTest
, TestRequireAsyncFromContextWithNoModuleSystem
) {
472 ModuleSystem::NativesEnabledScope
natives_enabled_scope(
473 env()->module_system());
474 env()->RegisterModule("test",
475 "requireAsync('natives').then(function(natives) {"
476 " requireNative('assert').AssertTrue("
477 " natives.requireAsync('foo') === undefined);"
479 scoped_ptr
<ModuleSystemTestEnvironment
> other_env
= CreateEnvironment();
480 gin::ModuleRegistry::From(env()->context()->v8_context())->AddBuiltinModule(
481 env()->isolate(), "natives", other_env
->module_system()->NewInstance());
482 other_env
->ShutdownModuleSystem();
483 env()->module_system()->Require("test");
484 RunResolvedPromises();
487 } // namespace extensions