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