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.
5 #include "chrome/test/base/module_system_test.h"
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"
26 using extensions::ModuleSystem
;
27 using extensions::NativeHandler
;
28 using extensions::ObjectBackedNativeHandler
;
32 class FailsOnException
: public ModuleSystem::ExceptionHandler
{
34 virtual void HandleUncaughtException(const v8::TryCatch
& try_catch
) OVERRIDE
{
35 FAIL() << "Uncaught exception: " << CreateExceptionString(try_catch
);
39 class 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());
49 v8::ExtensionConfiguration
* GetConfiguration() {
50 return configuration_
.get();
54 scoped_ptr
<v8::Extension
> safe_builtins_
;
55 std::vector
<const char*> names_
;
56 scoped_ptr
<v8::ExtensionConfiguration
> configuration_
;
59 base::LazyInstance
<V8ExtensionConfigurator
>::Leaky g_v8_extension_configurator
=
60 LAZY_INSTANCE_INITIALIZER
;
64 // Native JS functions for doing asserts.
65 class ModuleSystemTest::AssertNatives
: public ObjectBackedNativeHandler
{
67 explicit AssertNatives(extensions::ChromeV8Context
* context
)
68 : ObjectBackedNativeHandler(context
),
69 assertion_made_(false),
71 RouteFunction("AssertTrue", base::Bind(&AssertNatives::AssertTrue
,
72 base::Unretained(this)));
73 RouteFunction("AssertFalse", base::Bind(&AssertNatives::AssertFalse
,
74 base::Unretained(this)));
77 bool assertion_made() { return assertion_made_
; }
78 bool failed() { return failed_
; }
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();
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();
97 // Source map that operates on std::strings.
98 class ModuleSystemTest::StringSourceMap
: public ModuleSystem::SourceMap
{
101 virtual ~StringSourceMap() {}
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());
110 virtual bool Contains(const std::string
& name
) OVERRIDE
{
111 return source_map_
.count(name
);
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
;
120 std::map
<std::string
, std::string
> source_map_
;
123 ModuleSystemTest::ModuleSystemTest()
124 : isolate_(v8::Isolate::GetCurrent()),
125 handle_scope_(isolate_
),
127 new extensions::ChromeV8Context(
130 g_v8_extension_configurator
.Get().GetConfiguration()),
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());
140 scoped_ptr
<ModuleSystem
> module_system(
141 new ModuleSystem(context_
.get(), source_map_
.get()));
142 context_
->set_module_system(module_system
.Pass());
144 ModuleSystem
* module_system
= context_
->module_system();
145 module_system
->RegisterNativeHandler("assert", scoped_ptr
<NativeHandler
>(
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
));
155 ModuleSystemTest::~ModuleSystemTest() {
156 context_
->v8_context()->Exit();
159 void ModuleSystemTest::RegisterModule(const std::string
& name
,
160 const std::string
& code
) {
161 source_map_
->RegisterModule(name
, code
);
164 void ModuleSystemTest::RegisterModule(const std::string
& name
,
166 const std::string
& code
= ResourceBundle::GetSharedInstance().
167 GetRawDataResource(resource_id
).as_string();
168 source_map_
->RegisterModule(name
, code
);
171 void ModuleSystemTest::OverrideNativeHandler(const std::string
& name
,
172 const std::string
& code
) {
173 RegisterModule(name
, code
);
174 context_
->module_system()->OverrideNativeHandlerForTest(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
);
184 ASSERT_TRUE(base::ReadFileToString(test_js_file_path
, &test_js
));
185 source_map_
->RegisterModule(module_name
, test_js
);
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());
195 void ModuleSystemTest::ExpectNoAssertionsMade() {
196 should_assertions_be_made_
= false;
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
);