• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
7 #include "base/callback.h"
8 #include "base/file_util.h"
9 #include "base/files/file_path.h"
10 #include "base/lazy_instance.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/path_service.h"
13 #include "base/stl_util.h"
14 #include "base/strings/string_piece.h"
15 #include "chrome/common/chrome_paths.h"
16 #include "chrome/renderer/extensions/chrome_v8_context.h"
17 #include "extensions/renderer/logging_native_handler.h"
18 #include "extensions/renderer/object_backed_native_handler.h"
19 #include "extensions/renderer/safe_builtins.h"
20 #include "extensions/renderer/utils_native_handler.h"
21 #include "ui/base/resource/resource_bundle.h"
22 
23 #include <map>
24 #include <string>
25 
26 using extensions::ModuleSystem;
27 using extensions::NativeHandler;
28 using extensions::ObjectBackedNativeHandler;
29 
30 namespace {
31 
32 class FailsOnException : public ModuleSystem::ExceptionHandler {
33  public:
HandleUncaughtException(const v8::TryCatch & try_catch)34   virtual void HandleUncaughtException(const v8::TryCatch& try_catch) OVERRIDE {
35     FAIL() << "Uncaught exception: " << CreateExceptionString(try_catch);
36   }
37 };
38 
39 class V8ExtensionConfigurator {
40  public:
V8ExtensionConfigurator()41   V8ExtensionConfigurator()
42       : safe_builtins_(extensions::SafeBuiltins::CreateV8Extension()),
43         names_(1, safe_builtins_->name()),
44         configuration_(new v8::ExtensionConfiguration(
45             names_.size(), vector_as_array(&names_))) {
46     v8::RegisterExtension(safe_builtins_.get());
47   }
48 
GetConfiguration()49   v8::ExtensionConfiguration* GetConfiguration() {
50     return configuration_.get();
51   }
52 
53  private:
54   scoped_ptr<v8::Extension> safe_builtins_;
55   std::vector<const char*> names_;
56   scoped_ptr<v8::ExtensionConfiguration> configuration_;
57 };
58 
59 base::LazyInstance<V8ExtensionConfigurator>::Leaky g_v8_extension_configurator =
60     LAZY_INSTANCE_INITIALIZER;
61 
62 }  // namespace
63 
64 // Native JS functions for doing asserts.
65 class ModuleSystemTest::AssertNatives : public ObjectBackedNativeHandler {
66  public:
AssertNatives(extensions::ChromeV8Context * context)67   explicit AssertNatives(extensions::ChromeV8Context* context)
68       : ObjectBackedNativeHandler(context),
69         assertion_made_(false),
70         failed_(false) {
71     RouteFunction("AssertTrue", base::Bind(&AssertNatives::AssertTrue,
72         base::Unretained(this)));
73     RouteFunction("AssertFalse", base::Bind(&AssertNatives::AssertFalse,
74         base::Unretained(this)));
75   }
76 
assertion_made()77   bool assertion_made() { return assertion_made_; }
failed()78   bool failed() { return failed_; }
79 
AssertTrue(const v8::FunctionCallbackInfo<v8::Value> & args)80   void AssertTrue(const v8::FunctionCallbackInfo<v8::Value>& args) {
81     CHECK_EQ(1, args.Length());
82     assertion_made_ = true;
83     failed_ = failed_ || !args[0]->ToBoolean()->Value();
84   }
85 
AssertFalse(const v8::FunctionCallbackInfo<v8::Value> & args)86   void AssertFalse(const v8::FunctionCallbackInfo<v8::Value>& args) {
87     CHECK_EQ(1, args.Length());
88     assertion_made_ = true;
89     failed_ = failed_ || args[0]->ToBoolean()->Value();
90   }
91 
92  private:
93   bool assertion_made_;
94   bool failed_;
95 };
96 
97 // Source map that operates on std::strings.
98 class ModuleSystemTest::StringSourceMap : public ModuleSystem::SourceMap {
99  public:
StringSourceMap()100   StringSourceMap() {}
~StringSourceMap()101   virtual ~StringSourceMap() {}
102 
GetSource(v8::Isolate * isolate,const std::string & name)103   virtual v8::Handle<v8::Value> GetSource(v8::Isolate* isolate,
104                                           const std::string& name) OVERRIDE {
105     if (source_map_.count(name) == 0)
106       return v8::Undefined(isolate);
107     return v8::String::NewFromUtf8(isolate, source_map_[name].c_str());
108   }
109 
Contains(const std::string & name)110   virtual bool Contains(const std::string& name) OVERRIDE {
111     return source_map_.count(name);
112   }
113 
RegisterModule(const std::string & name,const std::string & source)114   void RegisterModule(const std::string& name, const std::string& source) {
115     CHECK_EQ(0u, source_map_.count(name)) << "Module " << name << " not found";
116     source_map_[name] = source;
117   }
118 
119  private:
120   std::map<std::string, std::string> source_map_;
121 };
122 
ModuleSystemTest()123 ModuleSystemTest::ModuleSystemTest()
124     : isolate_(v8::Isolate::GetCurrent()),
125       handle_scope_(isolate_),
126       context_(
127           new extensions::ChromeV8Context(
128               v8::Context::New(
129                   isolate_,
130                   g_v8_extension_configurator.Get().GetConfiguration()),
131               NULL,  // WebFrame
132               NULL,  // Extension
133               extensions::Feature::UNSPECIFIED_CONTEXT)),
134       source_map_(new StringSourceMap()),
135       should_assertions_be_made_(true) {
136   context_->v8_context()->Enter();
137   assert_natives_ = new AssertNatives(context_.get());
138 
139   {
140     scoped_ptr<ModuleSystem> module_system(
141         new ModuleSystem(context_.get(), source_map_.get()));
142     context_->set_module_system(module_system.Pass());
143   }
144   ModuleSystem* module_system = context_->module_system();
145   module_system->RegisterNativeHandler("assert", scoped_ptr<NativeHandler>(
146       assert_natives_));
147   module_system->RegisterNativeHandler("logging", scoped_ptr<NativeHandler>(
148       new extensions::LoggingNativeHandler(context_.get())));
149   module_system->RegisterNativeHandler("utils", scoped_ptr<NativeHandler>(
150       new extensions::UtilsNativeHandler(context_.get())));
151   module_system->SetExceptionHandlerForTest(
152       scoped_ptr<ModuleSystem::ExceptionHandler>(new FailsOnException));
153 }
154 
~ModuleSystemTest()155 ModuleSystemTest::~ModuleSystemTest() {
156   context_->v8_context()->Exit();
157 }
158 
RegisterModule(const std::string & name,const std::string & code)159 void ModuleSystemTest::RegisterModule(const std::string& name,
160                                       const std::string& code) {
161   source_map_->RegisterModule(name, code);
162 }
163 
RegisterModule(const std::string & name,int resource_id)164 void ModuleSystemTest::RegisterModule(const std::string& name,
165                                       int resource_id) {
166   const std::string& code = ResourceBundle::GetSharedInstance().
167       GetRawDataResource(resource_id).as_string();
168   source_map_->RegisterModule(name, code);
169 }
170 
OverrideNativeHandler(const std::string & name,const std::string & code)171 void ModuleSystemTest::OverrideNativeHandler(const std::string& name,
172                                              const std::string& code) {
173   RegisterModule(name, code);
174   context_->module_system()->OverrideNativeHandlerForTest(name);
175 }
176 
RegisterTestFile(const std::string & module_name,const std::string & file_name)177 void ModuleSystemTest::RegisterTestFile(const std::string& module_name,
178                                         const std::string& file_name) {
179   base::FilePath test_js_file_path;
180   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_js_file_path));
181   test_js_file_path = test_js_file_path.AppendASCII("extensions")
182                                        .AppendASCII(file_name);
183   std::string test_js;
184   ASSERT_TRUE(base::ReadFileToString(test_js_file_path, &test_js));
185   source_map_->RegisterModule(module_name, test_js);
186 }
187 
TearDown()188 void ModuleSystemTest::TearDown() {
189   // All tests must assert at least once unless otherwise specified.
190   EXPECT_EQ(should_assertions_be_made_,
191             assert_natives_->assertion_made());
192   EXPECT_FALSE(assert_natives_->failed());
193 }
194 
ExpectNoAssertionsMade()195 void ModuleSystemTest::ExpectNoAssertionsMade() {
196   should_assertions_be_made_ = false;
197 }
198 
CreateGlobal(const std::string & name)199 v8::Handle<v8::Object> ModuleSystemTest::CreateGlobal(const std::string& name) {
200   v8::Isolate* isolate = v8::Isolate::GetCurrent();
201   v8::EscapableHandleScope handle_scope(isolate);
202   v8::Local<v8::Object> object = v8::Object::New(isolate);
203   isolate->GetCurrentContext()->Global()->Set(
204       v8::String::NewFromUtf8(isolate, name.c_str()), object);
205   return handle_scope.Escape(object);
206 }
207