Home | History | Annotate | Download | only in base
      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:
     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:
     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 
     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:
     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 
     76   bool assertion_made() { return assertion_made_; }
     77   bool failed() { return failed_; }
     78 
     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 
     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:
     99   StringSourceMap() {}
    100   virtual ~StringSourceMap() {}
    101 
    102   virtual v8::Handle<v8::Value> GetSource(const std::string& name) OVERRIDE {
    103     if (source_map_.count(name) == 0)
    104       return v8::Undefined();
    105     return v8::String::New(source_map_[name].c_str());
    106   }
    107 
    108   virtual bool Contains(const std::string& name) OVERRIDE {
    109     return source_map_.count(name);
    110   }
    111 
    112   void RegisterModule(const std::string& name, const std::string& source) {
    113     CHECK_EQ(0u, source_map_.count(name)) << "Module " << name << " not found";
    114     source_map_[name] = source;
    115   }
    116 
    117  private:
    118   std::map<std::string, std::string> source_map_;
    119 };
    120 
    121 ModuleSystemTest::ModuleSystemTest()
    122     : isolate_(v8::Isolate::GetCurrent()),
    123       handle_scope_(isolate_),
    124       context_(
    125           new extensions::ChromeV8Context(
    126               v8::Context::New(
    127                   isolate_,
    128                   g_v8_extension_configurator.Get().GetConfiguration()),
    129               NULL,  // WebFrame
    130               NULL,  // Extension
    131               extensions::Feature::UNSPECIFIED_CONTEXT)),
    132       source_map_(new StringSourceMap()),
    133       should_assertions_be_made_(true) {
    134   context_->v8_context()->Enter();
    135   assert_natives_ = new AssertNatives(context_.get());
    136   module_system_.reset(new ModuleSystem(context_.get(), source_map_.get()));
    137   module_system_->RegisterNativeHandler("assert", scoped_ptr<NativeHandler>(
    138       assert_natives_));
    139   module_system_->RegisterNativeHandler("logging", scoped_ptr<NativeHandler>(
    140       new extensions::LoggingNativeHandler(context_.get())));
    141   module_system_->SetExceptionHandlerForTest(
    142       scoped_ptr<ModuleSystem::ExceptionHandler>(new FailsOnException));
    143 }
    144 
    145 ModuleSystemTest::~ModuleSystemTest() {
    146   module_system_.reset();
    147   context_->v8_context()->Exit();
    148 }
    149 
    150 void ModuleSystemTest::RegisterModule(const std::string& name,
    151                                       const std::string& code) {
    152   source_map_->RegisterModule(name, code);
    153 }
    154 
    155 void ModuleSystemTest::RegisterModule(const std::string& name,
    156                                       int resource_id) {
    157   const std::string& code = ResourceBundle::GetSharedInstance().
    158       GetRawDataResource(resource_id).as_string();
    159   source_map_->RegisterModule(name, code);
    160 }
    161 
    162 void ModuleSystemTest::OverrideNativeHandler(const std::string& name,
    163                                              const std::string& code) {
    164   RegisterModule(name, code);
    165   module_system_->OverrideNativeHandlerForTest(name);
    166 }
    167 
    168 void ModuleSystemTest::RegisterTestFile(const std::string& module_name,
    169                                         const std::string& file_name) {
    170   base::FilePath test_js_file_path;
    171   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_js_file_path));
    172   test_js_file_path = test_js_file_path.AppendASCII("extensions")
    173                                        .AppendASCII(file_name);
    174   std::string test_js;
    175   ASSERT_TRUE(file_util::ReadFileToString(test_js_file_path, &test_js));
    176   source_map_->RegisterModule(module_name, test_js);
    177 }
    178 
    179 void ModuleSystemTest::TearDown() {
    180   // All tests must assert at least once unless otherwise specified.
    181   EXPECT_EQ(should_assertions_be_made_,
    182             assert_natives_->assertion_made());
    183   EXPECT_FALSE(assert_natives_->failed());
    184 }
    185 
    186 void ModuleSystemTest::ExpectNoAssertionsMade() {
    187   should_assertions_be_made_ = false;
    188 }
    189 
    190 v8::Handle<v8::Object> ModuleSystemTest::CreateGlobal(const std::string& name) {
    191   v8::HandleScope handle_scope;
    192   v8::Handle<v8::Object> object = v8::Object::New();
    193   v8::Context::GetCurrent()->Global()->Set(v8::String::New(name.c_str()),
    194                                            object);
    195   return handle_scope.Close(object);
    196 }
    197