Index: chrome/browser/ui/webui/web_ui_browsertest.cc |
diff --git a/chrome/browser/ui/webui/web_ui_browsertest.cc b/chrome/browser/ui/webui/web_ui_browsertest.cc |
index 3817612619a61c8a7daf4884bbc5cab12a9f0e53..86cc191e28a2d6d7f662cefc02f3e21710539f10 100644 |
--- a/chrome/browser/ui/webui/web_ui_browsertest.cc |
+++ b/chrome/browser/ui/webui/web_ui_browsertest.cc |
@@ -6,21 +6,55 @@ |
#include <string> |
#include <vector> |
+#include "base/file_util.h" |
+#include "base/lazy_instance.h" |
#include "base/path_service.h" |
#include "base/utf_string_conversions.h" |
#include "base/values.h" |
#include "chrome/browser/ui/browser.h" |
#include "chrome/common/chrome_paths.h" |
#include "chrome/common/url_constants.h" |
+#include "chrome/test/out_of_proc_test_runner.h" |
#include "chrome/test/ui_test_utils.h" |
#include "content/browser/tab_contents/tab_contents.h" |
#include "content/browser/webui/web_ui.h" |
#include "ui/base/resource/resource_bundle.h" |
+#include "v8/include/v8.h" |
-static const FilePath::CharType* kWebUILibraryJS = |
- FILE_PATH_LITERAL("test_api.js"); |
-static const FilePath::CharType* kWebUITestFolder = FILE_PATH_LITERAL("webui"); |
-static std::vector<std::string> error_messages_; |
+namespace { |
+const FilePath::StringType kWebUILibraryJS = FILE_PATH_LITERAL("test_api.js"); |
+const FilePath::StringType kWebUITestFolder = FILE_PATH_LITERAL("webui"); |
+const FilePath::StringType kSrcBaseName = FILE_PATH_LITERAL("src"); |
+const FilePath::StringType kBuildBaseName = FILE_PATH_LITERAL("build"); |
+ |
+base::LazyInstance<std::vector<std::string> > error_messages_( |
+ base::LINKER_INITIALIZED); |
+ |
+// This method is called before the system is initialized, and we can't use |
+// PathService. In order to support both automated builds and engineers on |
+// multiple platforms, we look down for a src dir if we are within a build |
+// directory and up for src if we are not. |
+FilePath GetTestDataDirectory() { |
+ FilePath test_data_directory; |
+ EXPECT_TRUE(file_util::GetCurrentDirectory(&test_data_directory)); |
+ DLOG(INFO) << "test_data_directory = " << test_data_directory.value(); |
+ if (test_data_directory.BaseName().value() == kBuildBaseName) { |
+ FilePath src_subdir = test_data_directory.Append(kSrcBaseName); |
+ if (file_util::PathExists(test_data_directory.Append(kSrcBaseName))) |
+ test_data_directory = src_subdir; |
+ } |
+ while (test_data_directory.BaseName().value() != kSrcBaseName) { |
+ FilePath dir_name = test_data_directory.DirName(); |
+ if (test_data_directory == dir_name) |
+ break; |
+ test_data_directory = dir_name; |
+ } |
+ EXPECT_EQ(kSrcBaseName, test_data_directory.BaseName().value()); |
+ test_data_directory = test_data_directory.Append(FILE_PATH_LITERAL("chrome")); |
+ test_data_directory = test_data_directory.Append(FILE_PATH_LITERAL("test")); |
+ test_data_directory = test_data_directory.Append(FILE_PATH_LITERAL("data")); |
+ return test_data_directory.Append(kWebUITestFolder); |
+} |
// Intercepts all log messages. |
bool LogHandler(int severity, |
@@ -29,7 +63,7 @@ bool LogHandler(int severity, |
size_t message_start, |
const std::string& str) { |
if (severity == logging::LOG_ERROR) { |
- error_messages_.push_back(str); |
+ error_messages_.Get().push_back(str); |
return true; |
} else { |
// For debugging messages while developing tests. |
@@ -37,6 +71,122 @@ bool LogHandler(int severity, |
} |
} |
+// Read the specified |library| into |content|, prepending |test_data_directory| |
+// when |library| is relative. |
+void ReadLibraryToString(const FilePath& test_data_directory, |
+ const FilePath& library, |
+ std::string* content) { |
+ ASSERT_TRUE(content); |
+ if (library.IsAbsolute()) |
+ ASSERT_TRUE(file_util::ReadFileToString(library, content)); |
+ else |
+ ASSERT_TRUE(file_util::ReadFileToString(test_data_directory.Append(library), |
+ content)); |
+} |
+ |
+// Gets functions defined in |library_path| starting with "test". Results are |
+// stored in |testFuncs|, which may not be NULL. |
+bool GetTestFuncs(const FilePath& library_path, |
+ std::vector<std::string>* testFuncs) { |
+ DCHECK(testFuncs); |
+ |
+ // For export of test_api functions. |
+ std::string content = "var window = {};"; |
+ ReadLibraryToString(GetTestDataDirectory(), library_path, &content); |
+ content.append("this;"); |
+ |
+ // Run the script, dispose the context, and check the results. |
+ v8::HandleScope handle_scope; |
+ v8::Persistent<v8::Context> context = v8::Context::New(); |
+ v8::Context::Scope context_scope(context); |
+ v8::Handle<v8::String> source = v8::String::New(content.data(), |
+ content.size()); |
+ v8::Handle<v8::Script> script = v8::Script::Compile(source); |
+ v8::TryCatch trycatch; |
+ v8::Handle<v8::Value> result = script->Run(); |
+ context.Dispose(); |
+ if (result.IsEmpty()) { |
+ v8::Handle<v8::Value> exception = trycatch.Exception(); |
+ v8::String::AsciiValue exception_str(exception); |
+ NOTREACHED() << "Exception: " << *exception_str; |
+ return false; |
+ } |
+ |
+ // Examine the resulting object for properties which are functions, and push |
+ // them into |testFuncs|. |
+ v8::Local<v8::Object> result_obj = result->ToObject(); |
+ v8::Local<v8::Array> property_names = result_obj->GetPropertyNames(); |
+ for (uint32_t index = 0; index < property_names->Length(); ++index) { |
+ v8::Local<v8::String> property_name( |
+ property_names->Get(index).As<v8::String>()); |
+ if (!result_obj->HasOwnProperty(property_name)) |
+ continue; |
+ v8::Local<v8::Value> value = result_obj->Get(property_name); |
+ if (value.IsEmpty() || !value->IsFunction()) |
+ continue; |
+ v8::String::AsciiValue property_name_ascii(property_name); |
+ testFuncs->push_back(std::string(*property_name_ascii, |
+ property_name_ascii.length())); |
+ } |
+ return true; |
+} |
+ |
+// Since v8 cannot get an isolation thread at linker initialization time on |
+// non-linux systems, we defer the registry until runtime. |
+class WebUITestCallback : public ::test::RegisterTestCallback { |
+ public: |
+ WebUITestCallback( |
+ const ::FilePath& library_path, |
+ const char* test_case_name, const char* name, |
+ const char* type_param, |
+ const char* value_param, |
+ ::testing::internal::TypeId fixture_class_id, |
+ ::testing::internal::SetUpTestCaseFunc set_up_tc, |
+ ::testing::internal::TearDownTestCaseFunc tear_down_tc, |
+ ::testing::internal::TestMetaFactoryBase<std::string>* meta_factory) |
+ : library_path_(library_path), |
+ test_case_name_(test_case_name), |
+ name_(name), |
+ type_param_(type_param), |
+ value_param_(value_param), |
+ fixture_class_id_(fixture_class_id), |
+ set_up_tc_(set_up_tc), |
+ tear_down_tc_(tear_down_tc), |
+ meta_factory_(meta_factory) {} |
+ |
+ private: |
+ virtual void RegisterTest() const { |
+ std::vector<std::string> testFuncs; |
+ EXPECT_TRUE(GetTestFuncs(library_path_, &testFuncs)); |
+ for (std::vector<std::string>::const_iterator it = testFuncs.begin(); |
+ it != testFuncs.end(); ++it) { |
+ std::string test_name = *it + "/" + name_; |
+ ::testing::internal::MakeAndRegisterTestInfo( |
+ test_case_name_.c_str(), test_name.c_str(), |
+ type_param_.c_str(), |
+ value_param_.c_str(), |
+ fixture_class_id_, |
+ set_up_tc_, |
+ tear_down_tc_, |
+ meta_factory_->CreateTestFactory(*it)); |
+ } |
+ } |
+ |
+ ::FilePath library_path_; |
+ std::string test_case_name_; |
+ std::string name_; |
+ std::string type_param_; |
+ std::string value_param_; |
+ ::testing::internal::TypeId fixture_class_id_; |
+ ::testing::internal::SetUpTestCaseFunc set_up_tc_; |
+ ::testing::internal::TearDownTestCaseFunc tear_down_tc_; |
+ ::testing::internal::TestMetaFactoryBase<std::string>* meta_factory_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(WebUITestCallback); |
+}; |
+ |
+} // namespace |
+ |
WebUIBrowserTest::~WebUIBrowserTest() {} |
bool WebUIBrowserTest::RunJavascriptFunction(const std::string& function_name) { |
@@ -95,8 +245,7 @@ WebUIBrowserTest::WebUIBrowserTest() |
: test_handler_(new WebUITestHandler()) {} |
void WebUIBrowserTest::SetUpInProcessBrowserTestFixture() { |
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory_)); |
- test_data_directory_ = test_data_directory_.Append(kWebUITestFolder); |
+ test_data_directory_ = GetTestDataDirectory(); |
// TODO(dtseng): should this be part of every BrowserTest or just WebUI test. |
FilePath resources_pack_path; |
@@ -110,22 +259,33 @@ WebUIMessageHandler* WebUIBrowserTest::GetMockMessageHandler() { |
return NULL; |
} |
-void WebUIBrowserTest::BuildJavascriptLibraries(std::string* content) { |
+int WebUIBrowserTest::AddJSToRegistry( |
+ const FilePath& library_path, |
+ const char* test_case_name, const char* name, |
+ const char* type_param, |
+ const char* value_param, |
+ ::testing::internal::TypeId fixture_class_id, |
+ ::testing::internal::SetUpTestCaseFunc set_up_tc, |
+ ::testing::internal::TearDownTestCaseFunc tear_down_tc, |
+ ::testing::internal::TestMetaFactoryBase<std::string>* meta_factory) { |
+ test::AddRegisterTestCallback(new WebUITestCallback( |
+ library_path, test_case_name, name, type_param, value_param, |
+ fixture_class_id, set_up_tc, tear_down_tc, meta_factory)); |
+ |
+ return 0; |
+} |
+ |
+ |
+void WebUIBrowserTest::BuildJavascriptLibraries(std::string* content) const { |
ASSERT_TRUE(content != NULL); |
- std::string library_content, src_content; |
+ std::string library_content; |
- std::vector<FilePath>::iterator user_libraries_iterator; |
- for (user_libraries_iterator = user_libraries.begin(); |
- user_libraries_iterator != user_libraries.end(); |
+ std::vector<FilePath>::const_iterator user_libraries_iterator; |
+ for (user_libraries_iterator = user_libraries_.begin(); |
+ user_libraries_iterator != user_libraries_.end(); |
++user_libraries_iterator) { |
- if (user_libraries_iterator->IsAbsolute()) { |
- ASSERT_TRUE(file_util::ReadFileToString(*user_libraries_iterator, |
- &library_content)); |
- } else { |
- ASSERT_TRUE(file_util::ReadFileToString( |
- test_data_directory_.Append(*user_libraries_iterator), |
- &library_content)); |
- } |
+ ReadLibraryToString(test_data_directory_, *user_libraries_iterator, |
+ &library_content); |
content->append(library_content); |
content->append(";\n"); |
} |
@@ -170,10 +330,10 @@ bool WebUIBrowserTest::RunJavascriptUsingHandler( |
bool result = test_handler_->RunJavascript(content, is_test); |
logging::SetLogMessageHandler(NULL); |
- if (error_messages_.size() > 0) { |
+ if (error_messages_.Get().size() > 0) { |
LOG(ERROR) << "Encountered javascript console error(s)"; |
result = false; |
- error_messages_.clear(); |
+ error_messages_.Get().clear(); |
} |
return result; |
} |
@@ -190,11 +350,11 @@ void WebUIBrowserTest::SetupHandlers() { |
} |
void WebUIBrowserTest::AddLibrary(const FilePath& library_path) { |
- user_libraries.push_back(library_path); |
+ user_libraries_.push_back(library_path); |
} |
IN_PROC_BROWSER_TEST_F(WebUIBrowserTest, TestSamplePass) { |
- AddLibrary(FilePath(FILE_PATH_LITERAL("sample_downloads.js"))); |
+ AddLibrary(FilePath(FILE_PATH_LITERAL("sample_passing.js"))); |
// Navigate to UI. |
// TODO(dtseng): make accessor for subclasses to return? |
@@ -202,5 +362,24 @@ IN_PROC_BROWSER_TEST_F(WebUIBrowserTest, TestSamplePass) { |
ASSERT_TRUE(RunJavascriptTest("testAssertFalse")); |
ASSERT_TRUE(RunJavascriptTest("testInitialFocus")); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(WebUIBrowserTest, TestSampleFail) { |
+ AddLibrary(FilePath(FILE_PATH_LITERAL("sample_failing.js"))); |
+ |
+ // Navigate to UI. |
+ // TODO(dtseng): make accessor for subclasses to return? |
+ ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIDownloadsURL)); |
+ |
ASSERT_FALSE(RunJavascriptTest("testConsoleError")); |
} |
+ |
+WEB_UI_BROWSER_TEST_JS(WebUIBrowserTest, TestJSPass, |
+ FILE_PATH_LITERAL("sample_passing.js")) { |
+ ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIDownloadsURL)); |
+} |
+ |
+WEB_UI_BROWSER_TEST_JS_FALSE(WebUIBrowserTest, TestJSFail, |
+ FILE_PATH_LITERAL("sample_failing.js")) { |
+ ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIDownloadsURL)); |
+} |