Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / extensions / renderer / module_system_unittest.cc
blobc5c916eb103f0c4e6ecf7d528441b425bad8303a
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 {
13 public:
14 explicit CounterNatives(ScriptContext* context)
15 : ObjectBackedNativeHandler(context), counter_(0) {
16 RouteFunction("Get",
17 base::Bind(&CounterNatives::Get, base::Unretained(this)));
18 RouteFunction(
19 "Increment",
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) {
28 counter_++;
31 private:
32 int counter_;
35 class TestExceptionHandler : public ModuleSystem::ExceptionHandler {
36 public:
37 TestExceptionHandler()
38 : ModuleSystem::ExceptionHandler(nullptr), handled_exception_(false) {}
40 void HandleUncaughtException(const v8::TryCatch& try_catch) override {
41 handled_exception_ = true;
44 bool handled_exception() const { return handled_exception_; }
46 private:
47 bool handled_exception_;
50 TEST_F(ModuleSystemTest, TestExceptionHandling) {
51 ModuleSystem::NativesEnabledScope natives_enabled_scope(
52 env()->module_system());
53 TestExceptionHandler* handler = new TestExceptionHandler;
54 scoped_ptr<ModuleSystem::ExceptionHandler> scoped_handler(handler);
55 ASSERT_FALSE(handler->handled_exception());
56 env()->module_system()->SetExceptionHandlerForTest(scoped_handler.Pass());
58 env()->RegisterModule("test", "throw 'hi';");
59 env()->module_system()->Require("test");
60 ASSERT_TRUE(handler->handled_exception());
62 ExpectNoAssertionsMade();
65 TEST_F(ModuleSystemTest, TestRequire) {
66 ModuleSystem::NativesEnabledScope natives_enabled_scope(
67 env()->module_system());
68 env()->RegisterModule("add",
69 "exports.Add = function(x, y) { return x + y; };");
70 env()->RegisterModule("test",
71 "var Add = require('add').Add;"
72 "requireNative('assert').AssertTrue(Add(3, 5) == 8);");
73 env()->module_system()->Require("test");
76 TEST_F(ModuleSystemTest, TestNestedRequire) {
77 ModuleSystem::NativesEnabledScope natives_enabled_scope(
78 env()->module_system());
79 env()->RegisterModule("add",
80 "exports.Add = function(x, y) { return x + y; };");
81 env()->RegisterModule("double",
82 "var Add = require('add').Add;"
83 "exports.Double = function(x) { return Add(x, x); };");
84 env()->RegisterModule("test",
85 "var Double = require('double').Double;"
86 "requireNative('assert').AssertTrue(Double(3) == 6);");
87 env()->module_system()->Require("test");
90 TEST_F(ModuleSystemTest, TestModuleInsulation) {
91 ModuleSystem::NativesEnabledScope natives_enabled_scope(
92 env()->module_system());
93 env()->RegisterModule("x",
94 "var x = 10;"
95 "exports.X = function() { return x; };");
96 env()->RegisterModule("y",
97 "var x = 15;"
98 "require('x');"
99 "exports.Y = function() { return x; };");
100 env()->RegisterModule("test",
101 "var Y = require('y').Y;"
102 "var X = require('x').X;"
103 "var assert = requireNative('assert');"
104 "assert.AssertTrue(!this.hasOwnProperty('x'));"
105 "assert.AssertTrue(Y() == 15);"
106 "assert.AssertTrue(X() == 10);");
107 env()->module_system()->Require("test");
110 TEST_F(ModuleSystemTest, TestNativesAreDisabledOutsideANativesEnabledScope) {
111 env()->RegisterModule("test",
112 "var assert;"
113 "try {"
114 " assert = requireNative('assert');"
115 "} catch (e) {"
116 " var caught = true;"
118 "if (assert) {"
119 " assert.AssertTrue(true);"
120 "}");
121 env()->module_system()->Require("test");
122 ExpectNoAssertionsMade();
125 TEST_F(ModuleSystemTest, TestNativesAreEnabledWithinANativesEnabledScope) {
126 env()->RegisterModule("test",
127 "var assert = requireNative('assert');"
128 "assert.AssertTrue(true);");
131 ModuleSystem::NativesEnabledScope natives_enabled(env()->module_system());
133 ModuleSystem::NativesEnabledScope natives_enabled_inner(
134 env()->module_system());
136 env()->module_system()->Require("test");
140 TEST_F(ModuleSystemTest, TestLazyField) {
141 ModuleSystem::NativesEnabledScope natives_enabled_scope(
142 env()->module_system());
143 env()->RegisterModule("lazy", "exports.x = 5;");
145 v8::Local<v8::Object> object = env()->CreateGlobal("object");
147 env()->module_system()->SetLazyField(object, "blah", "lazy", "x");
149 env()->RegisterModule("test",
150 "var assert = requireNative('assert');"
151 "assert.AssertTrue(object.blah == 5);");
152 env()->module_system()->Require("test");
155 TEST_F(ModuleSystemTest, TestLazyFieldYieldingObject) {
156 ModuleSystem::NativesEnabledScope natives_enabled_scope(
157 env()->module_system());
158 env()->RegisterModule(
159 "lazy",
160 "var object = {};"
161 "object.__defineGetter__('z', function() { return 1; });"
162 "object.x = 5;"
163 "object.y = function() { return 10; };"
164 "exports.object = object;");
166 v8::Local<v8::Object> object = env()->CreateGlobal("object");
168 env()->module_system()->SetLazyField(object, "thing", "lazy", "object");
170 env()->RegisterModule("test",
171 "var assert = requireNative('assert');"
172 "assert.AssertTrue(object.thing.x == 5);"
173 "assert.AssertTrue(object.thing.y() == 10);"
174 "assert.AssertTrue(object.thing.z == 1);");
175 env()->module_system()->Require("test");
178 TEST_F(ModuleSystemTest, TestLazyFieldIsOnlyEvaledOnce) {
179 ModuleSystem::NativesEnabledScope natives_enabled_scope(
180 env()->module_system());
181 env()->module_system()->RegisterNativeHandler(
182 "counter",
183 scoped_ptr<NativeHandler>(new CounterNatives(env()->context())));
184 env()->RegisterModule("lazy",
185 "requireNative('counter').Increment();"
186 "exports.x = 5;");
188 v8::Local<v8::Object> object = env()->CreateGlobal("object");
190 env()->module_system()->SetLazyField(object, "x", "lazy", "x");
192 env()->RegisterModule("test",
193 "var assert = requireNative('assert');"
194 "var counter = requireNative('counter');"
195 "assert.AssertTrue(counter.Get() == 0);"
196 "object.x;"
197 "assert.AssertTrue(counter.Get() == 1);"
198 "object.x;"
199 "assert.AssertTrue(counter.Get() == 1);");
200 env()->module_system()->Require("test");
203 TEST_F(ModuleSystemTest, TestRequireNativesAfterLazyEvaluation) {
204 ModuleSystem::NativesEnabledScope natives_enabled_scope(
205 env()->module_system());
206 env()->RegisterModule("lazy", "exports.x = 5;");
207 v8::Local<v8::Object> object = env()->CreateGlobal("object");
209 env()->module_system()->SetLazyField(object, "x", "lazy", "x");
210 env()->RegisterModule("test",
211 "object.x;"
212 "requireNative('assert').AssertTrue(true);");
213 env()->module_system()->Require("test");
216 TEST_F(ModuleSystemTest, TestTransitiveRequire) {
217 ModuleSystem::NativesEnabledScope natives_enabled_scope(
218 env()->module_system());
219 env()->RegisterModule("dependency", "exports.x = 5;");
220 env()->RegisterModule("lazy", "exports.output = require('dependency');");
222 v8::Local<v8::Object> object = env()->CreateGlobal("object");
224 env()->module_system()->SetLazyField(object, "thing", "lazy", "output");
226 env()->RegisterModule("test",
227 "var assert = requireNative('assert');"
228 "assert.AssertTrue(object.thing.x == 5);");
229 env()->module_system()->Require("test");
232 TEST_F(ModuleSystemTest, TestModulesOnlyGetEvaledOnce) {
233 ModuleSystem::NativesEnabledScope natives_enabled_scope(
234 env()->module_system());
235 env()->module_system()->RegisterNativeHandler(
236 "counter",
237 scoped_ptr<NativeHandler>(new CounterNatives(env()->context())));
239 env()->RegisterModule("incrementsWhenEvaled",
240 "requireNative('counter').Increment();");
241 env()->RegisterModule("test",
242 "var assert = requireNative('assert');"
243 "var counter = requireNative('counter');"
244 "assert.AssertTrue(counter.Get() == 0);"
245 "require('incrementsWhenEvaled');"
246 "assert.AssertTrue(counter.Get() == 1);"
247 "require('incrementsWhenEvaled');"
248 "assert.AssertTrue(counter.Get() == 1);");
250 env()->module_system()->Require("test");
253 TEST_F(ModuleSystemTest, TestOverrideNativeHandler) {
254 ModuleSystem::NativesEnabledScope natives_enabled_scope(
255 env()->module_system());
256 env()->OverrideNativeHandler("assert", "exports.AssertTrue = function() {};");
257 env()->RegisterModule("test", "requireNative('assert').AssertTrue(true);");
258 ExpectNoAssertionsMade();
259 env()->module_system()->Require("test");
262 TEST_F(ModuleSystemTest, TestOverrideNonExistentNativeHandler) {
263 ModuleSystem::NativesEnabledScope natives_enabled_scope(
264 env()->module_system());
265 env()->OverrideNativeHandler("thing", "exports.x = 5;");
266 env()->RegisterModule("test",
267 "var assert = requireNative('assert');"
268 "assert.AssertTrue(requireNative('thing').x == 5);");
269 env()->module_system()->Require("test");
272 TEST_F(ModuleSystemTest, TestRequireAsync) {
273 ModuleSystem::NativesEnabledScope natives_enabled_scope(
274 env()->module_system());
275 env()->RegisterModule("add",
276 "define('add', [], function() {"
277 " return { Add: function(x, y) { return x + y; } };"
278 "});");
279 env()->RegisterModule("math",
280 "define('math', ['add'], function(add) {"
281 " return { Add: add.Add };"
282 "});");
283 env()->RegisterModule(
284 "test",
285 "requireAsync('math').then(function(math) {"
286 " requireNative('assert').AssertTrue(math.Add(3, 5) == 8);"
287 "});");
288 env()->module_system()->Require("test");
289 RunResolvedPromises();
292 TEST_F(ModuleSystemTest, TestRequireAsyncInParallel) {
293 ModuleSystem::NativesEnabledScope natives_enabled_scope(
294 env()->module_system());
295 env()->RegisterModule("add",
296 "define('add', [], function() {"
297 " return { Add: function(x, y) { return x + y; } };"
298 "});");
299 env()->RegisterModule(
300 "subtract",
301 "define('subtract', [], function() {"
302 " return { Subtract: function(x, y) { return x - y; } };"
303 "});");
304 env()->RegisterModule(
305 "math",
306 "exports.AddAndSubtract = function(x, y, z) {"
307 " return Promise.all([requireAsync('add'),"
308 " requireAsync('subtract')"
309 " ]).then(function(modules) {"
310 " return modules[1].Subtract(modules[0].Add(x, y), z);"
311 " });"
312 "};");
313 env()->RegisterModule("test",
314 "var AddAndSubtract = require('math').AddAndSubtract;"
315 "AddAndSubtract(3, 5, 2).then(function(result) {"
316 " requireNative('assert').AssertTrue(result == 6);"
317 "});");
318 env()->module_system()->Require("test");
319 RunResolvedPromises();
322 TEST_F(ModuleSystemTest, TestNestedRequireAsyncs) {
323 ModuleSystem::NativesEnabledScope natives_enabled_scope(
324 env()->module_system());
325 env()->RegisterModule("first",
326 "define('first', [], function() {"
327 " return { next: 'second' };"
328 "});");
329 env()->RegisterModule("second",
330 "define('second', [], function() {"
331 " return { next: '' };"
332 "});");
333 env()->RegisterModule(
334 "test",
335 "requireAsync('first').then(function(module) {"
336 " return requireAsync(module.next)"
337 "}).then(function(module) {"
338 " requireNative('assert').AssertTrue(module.next === '');"
339 "});");
340 env()->module_system()->Require("test");
341 RunResolvedPromises();
344 TEST_F(ModuleSystemTest, TestRequireFromAMDModule) {
345 ModuleSystem::NativesEnabledScope natives_enabled_scope(
346 env()->module_system());
347 env()->RegisterModule("add",
348 "exports.Add = function(x, y) { return x + y; };");
349 env()->RegisterModule("math",
350 "define('math', [], function() {"
351 " var add = require('add');"
352 " return { Add: add.Add };"
353 "});");
354 env()->RegisterModule(
355 "test",
356 "requireAsync('math').then(function(math) {"
357 " requireNative('assert').AssertTrue(math.Add(3, 5) == 8);"
358 "});");
359 env()->module_system()->Require("test");
360 RunResolvedPromises();
363 TEST_F(ModuleSystemTest, TestRequireAsyncFromAMDModule) {
364 ModuleSystem::NativesEnabledScope natives_enabled_scope(
365 env()->module_system());
366 env()->RegisterModule("add",
367 "define('add', [], function() {"
368 " return { Add: function(x, y) { return x + y; } };"
369 "});");
370 env()->RegisterModule("math",
371 "define('math', [], function() {"
372 " function Add(x, y) {"
373 " return requireAsync('add').then(function(add) {"
374 " return add.Add(x, y);"
375 " });"
376 " }"
377 " return { Add: Add };"
378 "});");
379 env()->RegisterModule("test",
380 "requireAsync('math').then(function(math) {"
381 " return math.Add(3, 6);"
382 "}).then(function(result) {"
383 " requireNative('assert').AssertTrue(result == 9);"
384 "});");
385 env()->module_system()->Require("test");
386 RunResolvedPromises();
389 TEST_F(ModuleSystemTest, TestRequireAsyncFromAnotherContext) {
390 ModuleSystem::NativesEnabledScope natives_enabled_scope(
391 env()->module_system());
392 env()->RegisterModule(
393 "test",
394 "requireAsync('natives').then(function(natives) {"
395 " natives.requireAsync('ping').then(function(ping) {"
396 " return ping();"
397 " }).then(function(result) {"
398 " requireNative('assert').AssertTrue(result == 'pong');"
399 " });"
400 "});");
401 scoped_ptr<ModuleSystemTestEnvironment> other_env = CreateEnvironment();
402 other_env->RegisterModule("ping",
403 "define('ping', ['natives'], function(natives) {"
404 " return function() {"
405 " return 'pong';"
406 " }"
407 "});");
408 gin::ModuleRegistry::From(env()->context()->v8_context())
409 ->AddBuiltinModule(
410 env()->isolate(), "natives",
411 other_env->module_system()->NewInstance());
412 gin::ModuleRegistry::From(other_env->context()->v8_context())
413 ->AddBuiltinModule(
414 env()->isolate(), "natives",
415 env()->module_system()->NewInstance());
416 env()->module_system()->Require("test");
417 RunResolvedPromises();
420 TEST_F(ModuleSystemTest, TestRequireAsyncBetweenContexts) {
421 ModuleSystem::NativesEnabledScope natives_enabled_scope(
422 env()->module_system());
423 env()->RegisterModule("pong",
424 "define('pong', [], function() {"
425 " return function() { return 'done'; };"
426 "});");
427 env()->RegisterModule(
428 "test",
429 "requireAsync('natives').then(function(natives) {"
430 " natives.requireAsync('ping').then(function(ping) {"
431 " return ping();"
432 " }).then(function(pong) {"
433 " return pong();"
434 " }).then(function(result) {"
435 " requireNative('assert').AssertTrue(result == 'done');"
436 " });"
437 "});");
438 scoped_ptr<ModuleSystemTestEnvironment> other_env = CreateEnvironment();
439 other_env->RegisterModule("ping",
440 "define('ping', ['natives'], function(natives) {"
441 " return function() {"
442 " return natives.requireAsync('pong');"
443 " }"
444 "});");
445 gin::ModuleRegistry::From(env()->context()->v8_context())
446 ->AddBuiltinModule(
447 env()->isolate(), "natives",
448 other_env->module_system()->NewInstance());
449 gin::ModuleRegistry::From(other_env->context()->v8_context())
450 ->AddBuiltinModule(
451 env()->isolate(), "natives",
452 env()->module_system()->NewInstance());
453 env()->module_system()->Require("test");
454 RunResolvedPromises();
457 TEST_F(ModuleSystemTest, TestRequireAsyncFromContextWithNoModuleRegistry) {
458 ModuleSystem::NativesEnabledScope natives_enabled_scope(
459 env()->module_system());
460 env()->RegisterModule("test",
461 "requireAsync('natives').then(function(natives) {"
462 " var AssertTrue = requireNative('assert').AssertTrue;"
463 " natives.requireAsync('foo').then(function() {"
464 " AssertTrue(false);"
465 " }).catch(function(error) {"
466 " AssertTrue(error.message == "
467 " 'Extension view no longer exists');"
468 " });"
469 "});");
470 scoped_ptr<ModuleSystemTestEnvironment> other_env = CreateEnvironment();
471 gin::ModuleRegistry::From(env()->context()->v8_context())
472 ->AddBuiltinModule(
473 env()->isolate(), "natives",
474 other_env->module_system()->NewInstance());
475 other_env->ShutdownGin();
476 env()->module_system()->Require("test");
477 RunResolvedPromises();
480 TEST_F(ModuleSystemTest, TestRequireAsyncFromContextWithNoModuleSystem) {
481 ModuleSystem::NativesEnabledScope natives_enabled_scope(
482 env()->module_system());
483 env()->RegisterModule("test",
484 "requireAsync('natives').then(function(natives) {"
485 " requireNative('assert').AssertTrue("
486 " natives.requireAsync('foo') === undefined);"
487 "});");
488 scoped_ptr<ModuleSystemTestEnvironment> other_env = CreateEnvironment();
489 gin::ModuleRegistry::From(env()->context()->v8_context())
490 ->AddBuiltinModule(
491 env()->isolate(), "natives",
492 other_env->module_system()->NewInstance());
493 other_env->ShutdownModuleSystem();
494 env()->module_system()->Require("test");
495 RunResolvedPromises();
498 } // namespace extensions