| 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));
|
| +}
|
|
|