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 "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: | |
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: | |
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 | |
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 ModuleSystemTestEnvironment::AssertNatives | |
66 : public ObjectBackedNativeHandler { | |
67 public: | |
68 explicit AssertNatives(extensions::ChromeV8Context* context) | |
69 : ObjectBackedNativeHandler(context), | |
70 assertion_made_(false), | |
71 failed_(false) { | |
72 RouteFunction("AssertTrue", base::Bind(&AssertNatives::AssertTrue, | |
73 base::Unretained(this))); | |
74 RouteFunction("AssertFalse", base::Bind(&AssertNatives::AssertFalse, | |
75 base::Unretained(this))); | |
76 } | |
77 | |
78 bool assertion_made() { return assertion_made_; } | |
79 bool failed() { return failed_; } | |
80 | |
81 void AssertTrue(const v8::FunctionCallbackInfo<v8::Value>& args) { | |
82 CHECK_EQ(1, args.Length()); | |
83 assertion_made_ = true; | |
84 failed_ = failed_ || !args[0]->ToBoolean()->Value(); | |
85 } | |
86 | |
87 void AssertFalse(const v8::FunctionCallbackInfo<v8::Value>& args) { | |
88 CHECK_EQ(1, args.Length()); | |
89 assertion_made_ = true; | |
90 failed_ = failed_ || args[0]->ToBoolean()->Value(); | |
91 } | |
92 | |
93 private: | |
94 bool assertion_made_; | |
95 bool failed_; | |
96 }; | |
97 | |
98 // Source map that operates on std::strings. | |
99 class ModuleSystemTestEnvironment::StringSourceMap | |
100 : public extensions::ModuleSystem::SourceMap { | |
101 public: | |
102 StringSourceMap() {} | |
103 virtual ~StringSourceMap() {} | |
104 | |
105 virtual v8::Handle<v8::Value> GetSource(v8::Isolate* isolate, | |
106 const std::string& name) OVERRIDE { | |
107 if (source_map_.count(name) == 0) | |
108 return v8::Undefined(isolate); | |
109 return v8::String::NewFromUtf8(isolate, source_map_[name].c_str()); | |
110 } | |
111 | |
112 virtual bool Contains(const std::string& name) OVERRIDE { | |
113 return source_map_.count(name); | |
114 } | |
115 | |
116 void RegisterModule(const std::string& name, const std::string& source) { | |
117 CHECK_EQ(0u, source_map_.count(name)) << "Module " << name << " not found"; | |
118 source_map_[name] = source; | |
119 } | |
120 | |
121 private: | |
122 std::map<std::string, std::string> source_map_; | |
123 }; | |
124 | |
125 ModuleSystemTestEnvironment::ModuleSystemTestEnvironment( | |
126 gin::IsolateHolder* isolate_holder) | |
127 : isolate_holder_(isolate_holder), | |
128 context_holder_(new gin::ContextHolder(isolate_holder_->isolate())), | |
129 handle_scope_(isolate_holder_->isolate()), | |
130 source_map_(new StringSourceMap()) { | |
131 context_holder_->SetContext( | |
132 v8::Context::New(isolate_holder->isolate(), | |
133 g_v8_extension_configurator.Get().GetConfiguration())); | |
134 context_.reset(new extensions::ChromeV8Context( | |
135 context_holder_->context(), | |
136 NULL, // WebFrame | |
137 NULL, // Extension | |
138 extensions::Feature::UNSPECIFIED_CONTEXT)); | |
139 context_->v8_context()->Enter(); | |
140 assert_natives_ = new AssertNatives(context_.get()); | |
141 | |
142 { | |
143 scoped_ptr<ModuleSystem> module_system( | |
144 new ModuleSystem(context_.get(), source_map_.get())); | |
145 context_->set_module_system(module_system.Pass()); | |
146 } | |
147 ModuleSystem* module_system = context_->module_system(); | |
148 module_system->RegisterNativeHandler("assert", scoped_ptr<NativeHandler>( | |
149 assert_natives_)); | |
150 module_system->RegisterNativeHandler("logging", scoped_ptr<NativeHandler>( | |
151 new extensions::LoggingNativeHandler(context_.get()))); | |
152 module_system->RegisterNativeHandler("utils", scoped_ptr<NativeHandler>( | |
153 new extensions::UtilsNativeHandler(context_.get()))); | |
154 module_system->SetExceptionHandlerForTest( | |
155 scoped_ptr<ModuleSystem::ExceptionHandler>(new FailsOnException)); | |
156 } | |
157 | |
158 ModuleSystemTestEnvironment::~ModuleSystemTestEnvironment() { | |
159 if (context_) | |
160 context_->v8_context()->Exit(); | |
161 } | |
162 | |
163 void ModuleSystemTestEnvironment::RegisterModule(const std::string& name, | |
164 const std::string& code) { | |
165 source_map_->RegisterModule(name, code); | |
166 } | |
167 | |
168 void ModuleSystemTestEnvironment::RegisterModule(const std::string& name, | |
169 int resource_id) { | |
170 const std::string& code = ResourceBundle::GetSharedInstance(). | |
171 GetRawDataResource(resource_id).as_string(); | |
172 source_map_->RegisterModule(name, code); | |
173 } | |
174 | |
175 void ModuleSystemTestEnvironment::OverrideNativeHandler( | |
176 const std::string& name, | |
177 const std::string& code) { | |
178 RegisterModule(name, code); | |
179 context_->module_system()->OverrideNativeHandlerForTest(name); | |
180 } | |
181 | |
182 void ModuleSystemTestEnvironment::RegisterTestFile( | |
183 const std::string& module_name, | |
184 const std::string& file_name) { | |
185 base::FilePath test_js_file_path; | |
186 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_js_file_path)); | |
187 test_js_file_path = test_js_file_path.AppendASCII("extensions") | |
188 .AppendASCII(file_name); | |
189 std::string test_js; | |
190 ASSERT_TRUE(base::ReadFileToString(test_js_file_path, &test_js)); | |
191 source_map_->RegisterModule(module_name, test_js); | |
192 } | |
193 | |
194 void ModuleSystemTestEnvironment::ShutdownGin() { | |
195 context_holder_.reset(); | |
196 } | |
197 | |
198 void ModuleSystemTestEnvironment::ShutdownModuleSystem() { | |
199 context_->v8_context()->Exit(); | |
200 context_.reset(); | |
201 } | |
202 | |
203 v8::Handle<v8::Object> ModuleSystemTestEnvironment::CreateGlobal( | |
204 const std::string& name) { | |
205 v8::Isolate* isolate = isolate_holder_->isolate(); | |
206 v8::EscapableHandleScope handle_scope(isolate); | |
207 v8::Local<v8::Object> object = v8::Object::New(isolate); | |
208 isolate->GetCurrentContext()->Global()->Set( | |
209 v8::String::NewFromUtf8(isolate, name.c_str()), object); | |
210 return handle_scope.Escape(object); | |
211 } | |
212 | |
213 ModuleSystemTest::ModuleSystemTest() | |
214 : isolate_holder_(v8::Isolate::GetCurrent(), NULL), | |
215 env_(CreateEnvironment()), | |
216 should_assertions_be_made_(true) { | |
217 } | |
218 | |
219 ModuleSystemTest::~ModuleSystemTest() { | |
220 } | |
221 | |
222 void ModuleSystemTest::TearDown() { | |
223 // All tests must assert at least once unless otherwise specified. | |
224 EXPECT_EQ(should_assertions_be_made_, | |
225 env_->assert_natives()->assertion_made()); | |
226 EXPECT_FALSE(env_->assert_natives()->failed()); | |
227 } | |
228 | |
229 scoped_ptr<ModuleSystemTestEnvironment> ModuleSystemTest::CreateEnvironment() { | |
230 return make_scoped_ptr(new ModuleSystemTestEnvironment(&isolate_holder_)); | |
231 } | |
232 | |
233 void ModuleSystemTest::ExpectNoAssertionsMade() { | |
234 should_assertions_be_made_ = false; | |
235 } | |
236 | |
237 void ModuleSystemTest::RunResolvedPromises() { | |
238 isolate_holder_.isolate()->RunMicrotasks(); | |
239 } | |
OLD | NEW |