Adding Peter Thatcher to the owners file.
[chromium-blink-merge.git] / extensions / renderer / module_system_unittest.cc
blob23ad2547b52c8a253c8021fc266ffa929505661c
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() : handled_exception_(false) {}
39 void HandleUncaughtException(const v8::TryCatch& try_catch) override {
40 handled_exception_ = true;
43 bool handled_exception() const { return handled_exception_; }
45 private:
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",
93 "var x = 10;"
94 "exports.X = function() { return x; };");
95 env()->RegisterModule("y",
96 "var x = 15;"
97 "require('x');"
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",
111 "var assert;"
112 "try {"
113 " assert = requireNative('assert');"
114 "} catch (e) {"
115 " var caught = true;"
117 "if (assert) {"
118 " assert.AssertTrue(true);"
119 "}");
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(
158 "lazy",
159 "var object = {};"
160 "object.__defineGetter__('z', function() { return 1; });"
161 "object.x = 5;"
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(
181 "counter",
182 scoped_ptr<NativeHandler>(new CounterNatives(env()->context())));
183 env()->RegisterModule("lazy",
184 "requireNative('counter').Increment();"
185 "exports.x = 5;");
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);"
195 "object.x;"
196 "assert.AssertTrue(counter.Get() == 1);"
197 "object.x;"
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",
210 "object.x;"
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(
235 "counter",
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; } };"
277 "});");
278 env()->RegisterModule("math",
279 "define('math', ['add'], function(add) {"
280 " return { Add: add.Add };"
281 "});");
282 env()->RegisterModule(
283 "test",
284 "requireAsync('math').then(function(math) {"
285 " requireNative('assert').AssertTrue(math.Add(3, 5) == 8);"
286 "});");
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; } };"
297 "});");
298 env()->RegisterModule(
299 "subtract",
300 "define('subtract', [], function() {"
301 " return { Subtract: function(x, y) { return x - y; } };"
302 "});");
303 env()->RegisterModule(
304 "math",
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);"
310 " });"
311 "};");
312 env()->RegisterModule("test",
313 "var AddAndSubtract = require('math').AddAndSubtract;"
314 "AddAndSubtract(3, 5, 2).then(function(result) {"
315 " requireNative('assert').AssertTrue(result == 6);"
316 "});");
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' };"
327 "});");
328 env()->RegisterModule("second",
329 "define('second', [], function() {"
330 " return { next: '' };"
331 "});");
332 env()->RegisterModule(
333 "test",
334 "requireAsync('first').then(function(module) {"
335 " return requireAsync(module.next)"
336 "}).then(function(module) {"
337 " requireNative('assert').AssertTrue(module.next === '');"
338 "});");
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 };"
352 "});");
353 env()->RegisterModule(
354 "test",
355 "requireAsync('math').then(function(math) {"
356 " requireNative('assert').AssertTrue(math.Add(3, 5) == 8);"
357 "});");
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; } };"
368 "});");
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);"
374 " });"
375 " }"
376 " return { Add: Add };"
377 "});");
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);"
383 "});");
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(
392 "test",
393 "requireAsync('natives').then(function(natives) {"
394 " natives.requireAsync('ping').then(function(ping) {"
395 " return ping();"
396 " }).then(function(result) {"
397 " requireNative('assert').AssertTrue(result == 'pong');"
398 " });"
399 "});");
400 scoped_ptr<ModuleSystemTestEnvironment> other_env = CreateEnvironment();
401 other_env->RegisterModule("ping",
402 "define('ping', ['natives'], function(natives) {"
403 " return function() {"
404 " return 'pong';"
405 " }"
406 "});");
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())
410 ->AddBuiltinModule(
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'; };"
422 "});");
423 env()->RegisterModule(
424 "test",
425 "requireAsync('natives').then(function(natives) {"
426 " natives.requireAsync('ping').then(function(ping) {"
427 " return ping();"
428 " }).then(function(pong) {"
429 " return pong();"
430 " }).then(function(result) {"
431 " requireNative('assert').AssertTrue(result == 'done');"
432 " });"
433 "});");
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');"
439 " }"
440 "});");
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())
444 ->AddBuiltinModule(
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');"
461 " });"
462 "});");
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);"
478 "});");
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