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 "chrome/test/base/module_system_test.h" 6 #include "base/memory/scoped_ptr.h" 7 #include "chrome/renderer/extensions/module_system.h" 8 9 // TODO(cduvall/kalman): Put this file in extensions namespace. 10 using extensions::ModuleSystem; 11 using extensions::NativeHandler; 12 using extensions::ObjectBackedNativeHandler; 13 14 class CounterNatives : public ObjectBackedNativeHandler { 15 public: 16 explicit CounterNatives(extensions::ChromeV8Context* context) 17 : ObjectBackedNativeHandler(context), counter_(0) { 18 RouteFunction("Get", base::Bind(&CounterNatives::Get, 19 base::Unretained(this))); 20 RouteFunction("Increment", base::Bind(&CounterNatives::Increment, 21 base::Unretained(this))); 22 } 23 24 void Get(const v8::FunctionCallbackInfo<v8::Value>& args) { 25 args.GetReturnValue().Set(static_cast<int32_t>(counter_)); 26 } 27 28 void Increment(const v8::FunctionCallbackInfo<v8::Value>& args) { 29 counter_++; 30 } 31 32 private: 33 int counter_; 34 }; 35 36 class TestExceptionHandler : public ModuleSystem::ExceptionHandler { 37 public: 38 TestExceptionHandler() 39 : handled_exception_(false) { 40 } 41 42 virtual void HandleUncaughtException(const v8::TryCatch& try_catch) OVERRIDE { 43 handled_exception_ = true; 44 } 45 46 bool handled_exception() const { return handled_exception_; } 47 48 private: 49 bool handled_exception_; 50 }; 51 52 TEST_F(ModuleSystemTest, TestExceptionHandling) { 53 ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); 54 TestExceptionHandler* handler = new TestExceptionHandler; 55 scoped_ptr<ModuleSystem::ExceptionHandler> scoped_handler(handler); 56 ASSERT_FALSE(handler->handled_exception()); 57 module_system_->SetExceptionHandlerForTest(scoped_handler.Pass()); 58 59 RegisterModule("test", "throw 'hi';"); 60 module_system_->Require("test"); 61 ASSERT_TRUE(handler->handled_exception()); 62 63 ExpectNoAssertionsMade(); 64 } 65 66 TEST_F(ModuleSystemTest, TestRequire) { 67 ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); 68 RegisterModule("add", "exports.Add = function(x, y) { return x + y; };"); 69 RegisterModule("test", 70 "var Add = require('add').Add;" 71 "requireNative('assert').AssertTrue(Add(3, 5) == 8);"); 72 module_system_->Require("test"); 73 } 74 75 TEST_F(ModuleSystemTest, TestNestedRequire) { 76 ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); 77 RegisterModule("add", "exports.Add = function(x, y) { return x + y; };"); 78 RegisterModule("double", 79 "var Add = require('add').Add;" 80 "exports.Double = function(x) { return Add(x, x); };"); 81 RegisterModule("test", 82 "var Double = require('double').Double;" 83 "requireNative('assert').AssertTrue(Double(3) == 6);"); 84 module_system_->Require("test"); 85 } 86 87 TEST_F(ModuleSystemTest, TestModuleInsulation) { 88 ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); 89 RegisterModule("x", 90 "var x = 10;" 91 "exports.X = function() { return x; };"); 92 RegisterModule("y", 93 "var x = 15;" 94 "require('x');" 95 "exports.Y = function() { return x; };"); 96 RegisterModule("test", 97 "var Y = require('y').Y;" 98 "var X = require('x').X;" 99 "var assert = requireNative('assert');" 100 "assert.AssertTrue(!this.hasOwnProperty('x'));" 101 "assert.AssertTrue(Y() == 15);" 102 "assert.AssertTrue(X() == 10);"); 103 module_system_->Require("test"); 104 } 105 106 TEST_F(ModuleSystemTest, TestNativesAreDisabledOutsideANativesEnabledScope) { 107 RegisterModule("test", 108 "var assert;" 109 "try {" 110 " assert = requireNative('assert');" 111 "} catch (e) {" 112 " var caught = true;" 113 "}" 114 "if (assert) {" 115 " assert.AssertTrue(true);" 116 "}"); 117 module_system_->Require("test"); 118 ExpectNoAssertionsMade(); 119 } 120 121 TEST_F(ModuleSystemTest, TestNativesAreEnabledWithinANativesEnabledScope) { 122 RegisterModule("test", 123 "var assert = requireNative('assert');" 124 "assert.AssertTrue(true);"); 125 126 { 127 ModuleSystem::NativesEnabledScope natives_enabled(module_system_.get()); 128 { 129 ModuleSystem::NativesEnabledScope natives_enabled_inner( 130 module_system_.get()); 131 } 132 module_system_->Require("test"); 133 } 134 } 135 136 TEST_F(ModuleSystemTest, TestLazyField) { 137 ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); 138 RegisterModule("lazy", 139 "exports.x = 5;"); 140 141 v8::Handle<v8::Object> object = CreateGlobal("object"); 142 143 module_system_->SetLazyField(object, "blah", "lazy", "x"); 144 145 RegisterModule("test", 146 "var assert = requireNative('assert');" 147 "assert.AssertTrue(object.blah == 5);"); 148 module_system_->Require("test"); 149 } 150 151 TEST_F(ModuleSystemTest, TestLazyFieldYieldingObject) { 152 ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); 153 RegisterModule("lazy", 154 "var object = {};" 155 "object.__defineGetter__('z', function() { return 1; });" 156 "object.x = 5;" 157 "object.y = function() { return 10; };" 158 "exports.object = object;"); 159 160 v8::Handle<v8::Object> object = CreateGlobal("object"); 161 162 module_system_->SetLazyField(object, "thing", "lazy", "object"); 163 164 RegisterModule("test", 165 "var assert = requireNative('assert');" 166 "assert.AssertTrue(object.thing.x == 5);" 167 "assert.AssertTrue(object.thing.y() == 10);" 168 "assert.AssertTrue(object.thing.z == 1);" 169 ); 170 module_system_->Require("test"); 171 } 172 173 TEST_F(ModuleSystemTest, TestLazyFieldIsOnlyEvaledOnce) { 174 ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); 175 module_system_->RegisterNativeHandler( 176 "counter", 177 scoped_ptr<NativeHandler>(new CounterNatives(context_.get()))); 178 RegisterModule("lazy", 179 "requireNative('counter').Increment();" 180 "exports.x = 5;"); 181 182 v8::Handle<v8::Object> object = CreateGlobal("object"); 183 184 module_system_->SetLazyField(object, "x", "lazy", "x"); 185 186 RegisterModule("test", 187 "var assert = requireNative('assert');" 188 "var counter = requireNative('counter');" 189 "assert.AssertTrue(counter.Get() == 0);" 190 "object.x;" 191 "assert.AssertTrue(counter.Get() == 1);" 192 "object.x;" 193 "assert.AssertTrue(counter.Get() == 1);"); 194 module_system_->Require("test"); 195 } 196 197 TEST_F(ModuleSystemTest, TestRequireNativesAfterLazyEvaluation) { 198 ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); 199 RegisterModule("lazy", 200 "exports.x = 5;"); 201 v8::Handle<v8::Object> object = CreateGlobal("object"); 202 203 module_system_->SetLazyField(object, "x", "lazy", "x"); 204 RegisterModule("test", 205 "object.x;" 206 "requireNative('assert').AssertTrue(true);"); 207 module_system_->Require("test"); 208 } 209 210 TEST_F(ModuleSystemTest, TestTransitiveRequire) { 211 ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); 212 RegisterModule("dependency", 213 "exports.x = 5;"); 214 RegisterModule("lazy", 215 "exports.output = require('dependency');"); 216 217 v8::Handle<v8::Object> object = CreateGlobal("object"); 218 219 module_system_->SetLazyField(object, "thing", "lazy", "output"); 220 221 RegisterModule("test", 222 "var assert = requireNative('assert');" 223 "assert.AssertTrue(object.thing.x == 5);"); 224 module_system_->Require("test"); 225 } 226 227 TEST_F(ModuleSystemTest, TestModulesOnlyGetEvaledOnce) { 228 ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); 229 module_system_->RegisterNativeHandler( 230 "counter", 231 scoped_ptr<NativeHandler>(new CounterNatives(context_.get()))); 232 233 RegisterModule("incrementsWhenEvaled", 234 "requireNative('counter').Increment();"); 235 RegisterModule("test", 236 "var assert = requireNative('assert');" 237 "var counter = requireNative('counter');" 238 "assert.AssertTrue(counter.Get() == 0);" 239 "require('incrementsWhenEvaled');" 240 "assert.AssertTrue(counter.Get() == 1);" 241 "require('incrementsWhenEvaled');" 242 "assert.AssertTrue(counter.Get() == 1);"); 243 244 module_system_->Require("test"); 245 } 246 247 TEST_F(ModuleSystemTest, TestOverrideNativeHandler) { 248 ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); 249 OverrideNativeHandler("assert", "exports.AssertTrue = function() {};"); 250 RegisterModule("test", "requireNative('assert').AssertTrue(true);"); 251 ExpectNoAssertionsMade(); 252 module_system_->Require("test"); 253 } 254 255 TEST_F(ModuleSystemTest, TestOverrideNonExistentNativeHandler) { 256 ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); 257 OverrideNativeHandler("thing", "exports.x = 5;"); 258 RegisterModule("test", 259 "var assert = requireNative('assert');" 260 "assert.AssertTrue(requireNative('thing').x == 5);"); 261 module_system_->Require("test"); 262 } 263