10391b444d634102f0567c01b9959d6a946fdae1
[platform/framework/web/crosswalk.git] / src / extensions / renderer / module_system_unittest.cc
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.
4
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"
9
10 namespace extensions {
11
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)));
21   }
22
23   void Get(const v8::FunctionCallbackInfo<v8::Value>& args) {
24     args.GetReturnValue().Set(static_cast<int32_t>(counter_));
25   }
26
27   void Increment(const v8::FunctionCallbackInfo<v8::Value>& args) {
28     counter_++;
29   }
30
31  private:
32   int counter_;
33 };
34
35 class TestExceptionHandler : public ModuleSystem::ExceptionHandler {
36  public:
37   TestExceptionHandler() : handled_exception_(false) {}
38
39   virtual void HandleUncaughtException(const v8::TryCatch& try_catch) OVERRIDE {
40     handled_exception_ = true;
41   }
42
43   bool handled_exception() const { return handled_exception_; }
44
45  private:
46   bool handled_exception_;
47 };
48
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());
56
57   env()->RegisterModule("test", "throw 'hi';");
58   env()->module_system()->Require("test");
59   ASSERT_TRUE(handler->handled_exception());
60
61   ExpectNoAssertionsMade();
62 }
63
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");
73 }
74
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");
87 }
88
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");
107 }
108
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;"
116                         "}"
117                         "if (assert) {"
118                         "  assert.AssertTrue(true);"
119                         "}");
120   env()->module_system()->Require("test");
121   ExpectNoAssertionsMade();
122 }
123
124 TEST_F(ModuleSystemTest, TestNativesAreEnabledWithinANativesEnabledScope) {
125   env()->RegisterModule("test",
126                         "var assert = requireNative('assert');"
127                         "assert.AssertTrue(true);");
128
129   {
130     ModuleSystem::NativesEnabledScope natives_enabled(env()->module_system());
131     {
132       ModuleSystem::NativesEnabledScope natives_enabled_inner(
133           env()->module_system());
134     }
135     env()->module_system()->Require("test");
136   }
137 }
138
139 TEST_F(ModuleSystemTest, TestLazyField) {
140   ModuleSystem::NativesEnabledScope natives_enabled_scope(
141       env()->module_system());
142   env()->RegisterModule("lazy", "exports.x = 5;");
143
144   v8::Handle<v8::Object> object = env()->CreateGlobal("object");
145
146   env()->module_system()->SetLazyField(object, "blah", "lazy", "x");
147
148   env()->RegisterModule("test",
149                         "var assert = requireNative('assert');"
150                         "assert.AssertTrue(object.blah == 5);");
151   env()->module_system()->Require("test");
152 }
153
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;");
164
165   v8::Handle<v8::Object> object = env()->CreateGlobal("object");
166
167   env()->module_system()->SetLazyField(object, "thing", "lazy", "object");
168
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");
175 }
176
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;");
186
187   v8::Handle<v8::Object> object = env()->CreateGlobal("object");
188
189   env()->module_system()->SetLazyField(object, "x", "lazy", "x");
190
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");
200 }
201
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");
207
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");
213 }
214
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');");
220
221   v8::Handle<v8::Object> object = env()->CreateGlobal("object");
222
223   env()->module_system()->SetLazyField(object, "thing", "lazy", "output");
224
225   env()->RegisterModule("test",
226                         "var assert = requireNative('assert');"
227                         "assert.AssertTrue(object.thing.x == 5);");
228   env()->module_system()->Require("test");
229 }
230
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())));
237
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);");
248
249   env()->module_system()->Require("test");
250 }
251
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");
259 }
260
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");
269 }
270
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();
289 }
290
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();
319 }
320
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();
341 }
342
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();
360 }
361
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();
386 }
387
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();
414 }
415
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();
448 }
449
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();
469 }
470
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();
485 }
486
487 }  // namespace extensions