OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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. | |
4 | |
5 #include "base/memory/scoped_ptr.h" | |
6 #include "chrome/test/base/module_system_test.h" | |
7 #include "extensions/renderer/module_system.h" | |
8 #include "gin/modules/module_registry.h" | |
9 | |
10 // TODO(cduvall/kalman): Put this file in extensions namespace. | |
11 using extensions::ModuleSystem; | |
12 using extensions::NativeHandler; | |
13 using extensions::ObjectBackedNativeHandler; | |
14 | |
15 class CounterNatives : public ObjectBackedNativeHandler { | |
16 public: | |
17 explicit CounterNatives(extensions::ChromeV8Context* context) | |
18 : ObjectBackedNativeHandler(context), counter_(0) { | |
19 RouteFunction("Get", base::Bind(&CounterNatives::Get, | |
20 base::Unretained(this))); | |
21 RouteFunction("Increment", base::Bind(&CounterNatives::Increment, | |
22 base::Unretained(this))); | |
23 } | |
24 | |
25 void Get(const v8::FunctionCallbackInfo<v8::Value>& args) { | |
26 args.GetReturnValue().Set(static_cast<int32_t>(counter_)); | |
27 } | |
28 | |
29 void Increment(const v8::FunctionCallbackInfo<v8::Value>& args) { | |
30 counter_++; | |
31 } | |
32 | |
33 private: | |
34 int counter_; | |
35 }; | |
36 | |
37 class TestExceptionHandler : public ModuleSystem::ExceptionHandler { | |
38 public: | |
39 TestExceptionHandler() | |
40 : handled_exception_(false) { | |
41 } | |
42 | |
43 virtual void HandleUncaughtException(const v8::TryCatch& try_catch) OVERRIDE { | |
44 handled_exception_ = true; | |
45 } | |
46 | |
47 bool handled_exception() const { return handled_exception_; } | |
48 | |
49 private: | |
50 bool handled_exception_; | |
51 }; | |
52 | |
53 TEST_F(ModuleSystemTest, TestExceptionHandling) { | |
54 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
55 env()->module_system()); | |
56 TestExceptionHandler* handler = new TestExceptionHandler; | |
57 scoped_ptr<ModuleSystem::ExceptionHandler> scoped_handler(handler); | |
58 ASSERT_FALSE(handler->handled_exception()); | |
59 env()->module_system()->SetExceptionHandlerForTest(scoped_handler.Pass()); | |
60 | |
61 env()->RegisterModule("test", "throw 'hi';"); | |
62 env()->module_system()->Require("test"); | |
63 ASSERT_TRUE(handler->handled_exception()); | |
64 | |
65 ExpectNoAssertionsMade(); | |
66 } | |
67 | |
68 TEST_F(ModuleSystemTest, TestRequire) { | |
69 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
70 env()->module_system()); | |
71 env()->RegisterModule("add", | |
72 "exports.Add = function(x, y) { return x + y; };"); | |
73 env()->RegisterModule("test", | |
74 "var Add = require('add').Add;" | |
75 "requireNative('assert').AssertTrue(Add(3, 5) == 8);"); | |
76 env()->module_system()->Require("test"); | |
77 } | |
78 | |
79 TEST_F(ModuleSystemTest, TestNestedRequire) { | |
80 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
81 env()->module_system()); | |
82 env()->RegisterModule("add", | |
83 "exports.Add = function(x, y) { return x + y; };"); | |
84 env()->RegisterModule("double", | |
85 "var Add = require('add').Add;" | |
86 "exports.Double = function(x) { return Add(x, x); };"); | |
87 env()->RegisterModule("test", | |
88 "var Double = require('double').Double;" | |
89 "requireNative('assert').AssertTrue(Double(3) == 6);"); | |
90 env()->module_system()->Require("test"); | |
91 } | |
92 | |
93 TEST_F(ModuleSystemTest, TestModuleInsulation) { | |
94 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
95 env()->module_system()); | |
96 env()->RegisterModule("x", | |
97 "var x = 10;" | |
98 "exports.X = function() { return x; };"); | |
99 env()->RegisterModule("y", | |
100 "var x = 15;" | |
101 "require('x');" | |
102 "exports.Y = function() { return x; };"); | |
103 env()->RegisterModule("test", | |
104 "var Y = require('y').Y;" | |
105 "var X = require('x').X;" | |
106 "var assert = requireNative('assert');" | |
107 "assert.AssertTrue(!this.hasOwnProperty('x'));" | |
108 "assert.AssertTrue(Y() == 15);" | |
109 "assert.AssertTrue(X() == 10);"); | |
110 env()->module_system()->Require("test"); | |
111 } | |
112 | |
113 TEST_F(ModuleSystemTest, TestNativesAreDisabledOutsideANativesEnabledScope) { | |
114 env()->RegisterModule("test", | |
115 "var assert;" | |
116 "try {" | |
117 " assert = requireNative('assert');" | |
118 "} catch (e) {" | |
119 " var caught = true;" | |
120 "}" | |
121 "if (assert) {" | |
122 " assert.AssertTrue(true);" | |
123 "}"); | |
124 env()->module_system()->Require("test"); | |
125 ExpectNoAssertionsMade(); | |
126 } | |
127 | |
128 TEST_F(ModuleSystemTest, TestNativesAreEnabledWithinANativesEnabledScope) { | |
129 env()->RegisterModule("test", | |
130 "var assert = requireNative('assert');" | |
131 "assert.AssertTrue(true);"); | |
132 | |
133 { | |
134 ModuleSystem::NativesEnabledScope natives_enabled(env()->module_system()); | |
135 { | |
136 ModuleSystem::NativesEnabledScope natives_enabled_inner( | |
137 env()->module_system()); | |
138 } | |
139 env()->module_system()->Require("test"); | |
140 } | |
141 } | |
142 | |
143 TEST_F(ModuleSystemTest, TestLazyField) { | |
144 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
145 env()->module_system()); | |
146 env()->RegisterModule("lazy", "exports.x = 5;"); | |
147 | |
148 v8::Handle<v8::Object> object = env()->CreateGlobal("object"); | |
149 | |
150 env()->module_system()->SetLazyField(object, "blah", "lazy", "x"); | |
151 | |
152 env()->RegisterModule("test", | |
153 "var assert = requireNative('assert');" | |
154 "assert.AssertTrue(object.blah == 5);"); | |
155 env()->module_system()->Require("test"); | |
156 } | |
157 | |
158 TEST_F(ModuleSystemTest, TestLazyFieldYieldingObject) { | |
159 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
160 env()->module_system()); | |
161 env()->RegisterModule( | |
162 "lazy", | |
163 "var object = {};" | |
164 "object.__defineGetter__('z', function() { return 1; });" | |
165 "object.x = 5;" | |
166 "object.y = function() { return 10; };" | |
167 "exports.object = object;"); | |
168 | |
169 v8::Handle<v8::Object> object = env()->CreateGlobal("object"); | |
170 | |
171 env()->module_system()->SetLazyField(object, "thing", "lazy", "object"); | |
172 | |
173 env()->RegisterModule("test", | |
174 "var assert = requireNative('assert');" | |
175 "assert.AssertTrue(object.thing.x == 5);" | |
176 "assert.AssertTrue(object.thing.y() == 10);" | |
177 "assert.AssertTrue(object.thing.z == 1);"); | |
178 env()->module_system()->Require("test"); | |
179 } | |
180 | |
181 TEST_F(ModuleSystemTest, TestLazyFieldIsOnlyEvaledOnce) { | |
182 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
183 env()->module_system()); | |
184 env()->module_system()->RegisterNativeHandler( | |
185 "counter", | |
186 scoped_ptr<NativeHandler>(new CounterNatives(env()->context()))); | |
187 env()->RegisterModule("lazy", | |
188 "requireNative('counter').Increment();" | |
189 "exports.x = 5;"); | |
190 | |
191 v8::Handle<v8::Object> object = env()->CreateGlobal("object"); | |
192 | |
193 env()->module_system()->SetLazyField(object, "x", "lazy", "x"); | |
194 | |
195 env()->RegisterModule("test", | |
196 "var assert = requireNative('assert');" | |
197 "var counter = requireNative('counter');" | |
198 "assert.AssertTrue(counter.Get() == 0);" | |
199 "object.x;" | |
200 "assert.AssertTrue(counter.Get() == 1);" | |
201 "object.x;" | |
202 "assert.AssertTrue(counter.Get() == 1);"); | |
203 env()->module_system()->Require("test"); | |
204 } | |
205 | |
206 TEST_F(ModuleSystemTest, TestRequireNativesAfterLazyEvaluation) { | |
207 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
208 env()->module_system()); | |
209 env()->RegisterModule("lazy", "exports.x = 5;"); | |
210 v8::Handle<v8::Object> object = env()->CreateGlobal("object"); | |
211 | |
212 env()->module_system()->SetLazyField(object, "x", "lazy", "x"); | |
213 env()->RegisterModule("test", | |
214 "object.x;" | |
215 "requireNative('assert').AssertTrue(true);"); | |
216 env()->module_system()->Require("test"); | |
217 } | |
218 | |
219 TEST_F(ModuleSystemTest, TestTransitiveRequire) { | |
220 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
221 env()->module_system()); | |
222 env()->RegisterModule("dependency", "exports.x = 5;"); | |
223 env()->RegisterModule("lazy", "exports.output = require('dependency');"); | |
224 | |
225 v8::Handle<v8::Object> object = env()->CreateGlobal("object"); | |
226 | |
227 env()->module_system()->SetLazyField(object, "thing", "lazy", "output"); | |
228 | |
229 env()->RegisterModule("test", | |
230 "var assert = requireNative('assert');" | |
231 "assert.AssertTrue(object.thing.x == 5);"); | |
232 env()->module_system()->Require("test"); | |
233 } | |
234 | |
235 TEST_F(ModuleSystemTest, TestModulesOnlyGetEvaledOnce) { | |
236 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
237 env()->module_system()); | |
238 env()->module_system()->RegisterNativeHandler( | |
239 "counter", | |
240 scoped_ptr<NativeHandler>(new CounterNatives(env()->context()))); | |
241 | |
242 env()->RegisterModule("incrementsWhenEvaled", | |
243 "requireNative('counter').Increment();"); | |
244 env()->RegisterModule("test", | |
245 "var assert = requireNative('assert');" | |
246 "var counter = requireNative('counter');" | |
247 "assert.AssertTrue(counter.Get() == 0);" | |
248 "require('incrementsWhenEvaled');" | |
249 "assert.AssertTrue(counter.Get() == 1);" | |
250 "require('incrementsWhenEvaled');" | |
251 "assert.AssertTrue(counter.Get() == 1);"); | |
252 | |
253 env()->module_system()->Require("test"); | |
254 } | |
255 | |
256 TEST_F(ModuleSystemTest, TestOverrideNativeHandler) { | |
257 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
258 env()->module_system()); | |
259 env()->OverrideNativeHandler("assert", "exports.AssertTrue = function() {};"); | |
260 env()->RegisterModule("test", "requireNative('assert').AssertTrue(true);"); | |
261 ExpectNoAssertionsMade(); | |
262 env()->module_system()->Require("test"); | |
263 } | |
264 | |
265 TEST_F(ModuleSystemTest, TestOverrideNonExistentNativeHandler) { | |
266 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
267 env()->module_system()); | |
268 env()->OverrideNativeHandler("thing", "exports.x = 5;"); | |
269 env()->RegisterModule("test", | |
270 "var assert = requireNative('assert');" | |
271 "assert.AssertTrue(requireNative('thing').x == 5);"); | |
272 env()->module_system()->Require("test"); | |
273 } | |
274 | |
275 TEST_F(ModuleSystemTest, TestRequireAsync) { | |
276 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
277 env()->module_system()); | |
278 env()->RegisterModule("add", | |
279 "define('add', [], function() {" | |
280 " return { Add: function(x, y) { return x + y; } };" | |
281 "});"); | |
282 env()->RegisterModule("math", | |
283 "define('math', ['add'], function(add) {" | |
284 " return { Add: add.Add };" | |
285 "});"); | |
286 env()->RegisterModule( | |
287 "test", | |
288 "requireAsync('math').then(function(math) {" | |
289 " requireNative('assert').AssertTrue(math.Add(3, 5) == 8);" | |
290 "});"); | |
291 env()->module_system()->Require("test"); | |
292 RunResolvedPromises(); | |
293 } | |
294 | |
295 TEST_F(ModuleSystemTest, TestRequireAsyncInParallel) { | |
296 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
297 env()->module_system()); | |
298 env()->RegisterModule("add", | |
299 "define('add', [], function() {" | |
300 " return { Add: function(x, y) { return x + y; } };" | |
301 "});"); | |
302 env()->RegisterModule( | |
303 "subtract", | |
304 "define('subtract', [], function() {" | |
305 " return { Subtract: function(x, y) { return x - y; } };" | |
306 "});"); | |
307 env()->RegisterModule( | |
308 "math", | |
309 "exports.AddAndSubtract = function(x, y, z) {" | |
310 " return Promise.all([requireAsync('add')," | |
311 " requireAsync('subtract')" | |
312 " ]).then(function(modules) {" | |
313 " return modules[1].Subtract(modules[0].Add(x, y), z);" | |
314 " });" | |
315 "};"); | |
316 env()->RegisterModule("test", | |
317 "var AddAndSubtract = require('math').AddAndSubtract;" | |
318 "AddAndSubtract(3, 5, 2).then(function(result) {" | |
319 " requireNative('assert').AssertTrue(result == 6);" | |
320 "});"); | |
321 env()->module_system()->Require("test"); | |
322 RunResolvedPromises(); | |
323 } | |
324 | |
325 TEST_F(ModuleSystemTest, TestNestedRequireAsyncs) { | |
326 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
327 env()->module_system()); | |
328 env()->RegisterModule("first", | |
329 "define('first', [], function() {" | |
330 " return { next: 'second' };" | |
331 "});"); | |
332 env()->RegisterModule("second", | |
333 "define('second', [], function() {" | |
334 " return { next: '' };" | |
335 "});"); | |
336 env()->RegisterModule( | |
337 "test", | |
338 "requireAsync('first').then(function(module) {" | |
339 " return requireAsync(module.next)" | |
340 "}).then(function(module) {" | |
341 " requireNative('assert').AssertTrue(module.next === '');" | |
342 "});"); | |
343 env()->module_system()->Require("test"); | |
344 RunResolvedPromises(); | |
345 } | |
346 | |
347 TEST_F(ModuleSystemTest, TestRequireFromAMDModule) { | |
348 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
349 env()->module_system()); | |
350 env()->RegisterModule("add", | |
351 "exports.Add = function(x, y) { return x + y; };"); | |
352 env()->RegisterModule("math", | |
353 "define('math', [], function() {" | |
354 " var add = require('add');" | |
355 " return { Add: add.Add };" | |
356 "});"); | |
357 env()->RegisterModule( | |
358 "test", | |
359 "requireAsync('math').then(function(math) {" | |
360 " requireNative('assert').AssertTrue(math.Add(3, 5) == 8);" | |
361 "});"); | |
362 env()->module_system()->Require("test"); | |
363 RunResolvedPromises(); | |
364 } | |
365 | |
366 TEST_F(ModuleSystemTest, TestRequireAsyncFromAMDModule) { | |
367 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
368 env()->module_system()); | |
369 env()->RegisterModule("add", | |
370 "define('add', [], function() {" | |
371 " return { Add: function(x, y) { return x + y; } };" | |
372 "});"); | |
373 env()->RegisterModule("math", | |
374 "define('math', [], function() {" | |
375 " function Add(x, y) {" | |
376 " return requireAsync('add').then(function(add) {" | |
377 " return add.Add(x, y);" | |
378 " });" | |
379 " }" | |
380 " return { Add: Add };" | |
381 "});"); | |
382 env()->RegisterModule("test", | |
383 "requireAsync('math').then(function(math) {" | |
384 " return math.Add(3, 6);" | |
385 "}).then(function(result) {" | |
386 " requireNative('assert').AssertTrue(result == 9);" | |
387 "});"); | |
388 env()->module_system()->Require("test"); | |
389 RunResolvedPromises(); | |
390 } | |
391 | |
392 TEST_F(ModuleSystemTest, TestRequireAsyncFromAnotherContext) { | |
393 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
394 env()->module_system()); | |
395 env()->RegisterModule( | |
396 "test", | |
397 "requireAsync('natives').then(function(natives) {" | |
398 " natives.requireAsync('ping').then(function(ping) {" | |
399 " return ping();" | |
400 " }).then(function(result) {" | |
401 " requireNative('assert').AssertTrue(result == 'pong');" | |
402 " });" | |
403 "});"); | |
404 scoped_ptr<ModuleSystemTestEnvironment> other_env = CreateEnvironment(); | |
405 other_env->RegisterModule("ping", | |
406 "define('ping', ['natives'], function(natives) {" | |
407 " return function() {" | |
408 " return 'pong';" | |
409 " }" | |
410 "});"); | |
411 gin::ModuleRegistry::From(env()->context()->v8_context())->AddBuiltinModule( | |
412 env()->isolate(), "natives", other_env->module_system()->NewInstance()); | |
413 gin::ModuleRegistry::From(other_env->context()->v8_context()) | |
414 ->AddBuiltinModule( | |
415 env()->isolate(), "natives", env()->module_system()->NewInstance()); | |
416 env()->module_system()->Require("test"); | |
417 RunResolvedPromises(); | |
418 } | |
419 | |
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())->AddBuiltinModule( | |
446 env()->isolate(), "natives", other_env->module_system()->NewInstance()); | |
447 gin::ModuleRegistry::From(other_env->context()->v8_context()) | |
448 ->AddBuiltinModule( | |
449 env()->isolate(), "natives", env()->module_system()->NewInstance()); | |
450 env()->module_system()->Require("test"); | |
451 RunResolvedPromises(); | |
452 } | |
453 | |
454 TEST_F(ModuleSystemTest, TestRequireAsyncFromContextWithNoModuleRegistry) { | |
455 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
456 env()->module_system()); | |
457 env()->RegisterModule("test", | |
458 "requireAsync('natives').then(function(natives) {" | |
459 " var AssertTrue = requireNative('assert').AssertTrue;" | |
460 " natives.requireAsync('foo').then(function() {" | |
461 " AssertTrue(false);" | |
462 " }).catch(function(error) {" | |
463 " AssertTrue(error.message == " | |
464 " 'Extension view no longer exists');" | |
465 " });" | |
466 "});"); | |
467 scoped_ptr<ModuleSystemTestEnvironment> other_env = CreateEnvironment(); | |
468 gin::ModuleRegistry::From(env()->context()->v8_context())->AddBuiltinModule( | |
469 env()->isolate(), "natives", other_env->module_system()->NewInstance()); | |
470 other_env->ShutdownGin(); | |
471 env()->module_system()->Require("test"); | |
472 RunResolvedPromises(); | |
473 } | |
474 | |
475 TEST_F(ModuleSystemTest, TestRequireAsyncFromContextWithNoModuleSystem) { | |
476 ModuleSystem::NativesEnabledScope natives_enabled_scope( | |
477 env()->module_system()); | |
478 env()->RegisterModule("test", | |
479 "requireAsync('natives').then(function(natives) {" | |
480 " requireNative('assert').AssertTrue(" | |
481 " natives.requireAsync('foo') === undefined);" | |
482 "});"); | |
483 scoped_ptr<ModuleSystemTestEnvironment> other_env = CreateEnvironment(); | |
484 gin::ModuleRegistry::From(env()->context()->v8_context())->AddBuiltinModule( | |
485 env()->isolate(), "natives", other_env->module_system()->NewInstance()); | |
486 other_env->ShutdownModuleSystem(); | |
487 env()->module_system()->Require("test"); | |
488 RunResolvedPromises(); | |
489 } | |
OLD | NEW |