15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/select_file_dialog_extension.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/scoped_temp_dir.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" // ASCIIToUTF16 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/platform_thread.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/component_loader.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_browsertest.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_test_message_listener.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_navigator.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_window.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_paths.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_context.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_types.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/storage_partition.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/test/test_utils.h" 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/shell_dialogs/select_file_dialog.h" 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/shell_dialogs/selected_file_info.h" 3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "webkit/browser/fileapi/external_mount_points.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserContext; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Mock listener used by test below. 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MockSelectFileDialogListener : public ui::SelectFileDialog::Listener { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MockSelectFileDialogListener() 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : file_selected_(false), 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canceled_(false), 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params_(NULL) { 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool file_selected() const { return file_selected_; } 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool canceled() const { return canceled_; } 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath path() const { return path_; } 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* params() const { return params_; } 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ui::SelectFileDialog::Listener implementation. 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void FileSelected(const base::FilePath& path, 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* params) OVERRIDE { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_selected_ = true; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path_ = path; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params_ = params; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void FileSelectedWithExtraInfo( 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ui::SelectedFileInfo& selected_file_info, 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* params) OVERRIDE { 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FileSelected(selected_file_info.local_path, index, params); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void MultiFilesSelected( 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::vector<base::FilePath>& files, void* params) OVERRIDE {} 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void FileSelectionCanceled(void* params) OVERRIDE { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canceled_ = true; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params_ = params; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool file_selected_; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool canceled_; 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath path_; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* params_; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(MockSelectFileDialogListener); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SelectFileDialogExtensionBrowserTest : public ExtensionBrowserTest { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum DialogButtonType { 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DIALOG_BTN_OK, 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DIALOG_BTN_CANCEL 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void SetUp() OVERRIDE { 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extensions::ComponentLoader::EnableBackgroundExtensionsForTesting(); 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create the dialog wrapper object, but don't show it yet. 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listener_.reset(new MockSelectFileDialogListener()); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dialog_ = new SelectFileDialogExtension(listener_.get(), NULL); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have to provide at least one mount point. 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // File manager looks for "Downloads" mount point, so use this name. 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath tmp_path; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PathService::Get(base::DIR_TEMP, &tmp_path); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(tmp_dir_.CreateUniqueTempDirUnderPath(tmp_path)); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) downloads_dir_ = tmp_dir_.path().Append("Downloads"); 99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::CreateDirectory(downloads_dir_); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Must run after our setup because it actually runs the test. 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionBrowserTest::SetUp(); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void TearDown() OVERRIDE { 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionBrowserTest::TearDown(); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Delete the dialog first, as it holds a pointer to the listener. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dialog_ = NULL; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listener_.reset(); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) second_dialog_ = NULL; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) second_listener_.reset(); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Creates a file system mount point for a directory. 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void AddMountPoint(const base::FilePath& path) { 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string mount_point_name = path.BaseName().AsUTF8Unsafe(); 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fileapi::ExternalMountPoints* mount_points = 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserContext::GetMountPoints(browser()->profile()); 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The Downloads mount point already exists so it must be removed before 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // adding the test mount point (which will also be mapped as Downloads). 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mount_points->RevokeFileSystem(mount_point_name); 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_TRUE(mount_points->RegisterFileSystem( 125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) mount_point_name, fileapi::kFileSystemTypeNativeLocal, 126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) fileapi::FileSystemMountOption(), path)); 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void CheckJavascriptErrors() { 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::RenderViewHost* host = dialog_->GetRenderViewHost(); 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<base::Value> value = 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::ExecuteScriptAndGetValue(host, "window.JSErrorCount"); 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int js_error_count = 0; 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(value->GetAsInteger(&js_error_count)); 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_EQ(0, js_error_count); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OpenDialog(ui::SelectFileDialog::Type dialog_type, 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& file_path, 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::NativeWindow& owning_window, 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& additional_message) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Spawn a dialog to open a file. The dialog will signal that it is ready 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // via chrome.test.sendMessage() in the extension JavaScript. 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionTestMessageListener init_listener("worker-initialized", 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false /* will_reply */); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<ExtensionTestMessageListener> additional_listener; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!additional_message.empty()) { 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) additional_listener.reset( 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new ExtensionTestMessageListener(additional_message, false)); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dialog_->SelectFile(dialog_type, 154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16() /* title */, 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_path, 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL /* file_types */, 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0 /* file_type_index */, 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE_PATH_LITERAL("") /* default_extension */, 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) owning_window, 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this /* params */); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "Waiting for JavaScript ready message."; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(init_listener.WaitUntilSatisfied()); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (additional_listener.get()) { 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "Waiting for JavaScript " << additional_message 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " message."; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(additional_listener->WaitUntilSatisfied()); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Dialog should be running now. 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(dialog_->IsRunning(owning_window)); 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_NO_FATAL_FAILURE(CheckJavascriptErrors()); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void TryOpeningSecondDialog(const gfx::NativeWindow& owning_window) { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) second_listener_.reset(new MockSelectFileDialogListener()); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) second_dialog_ = new SelectFileDialogExtension(second_listener_.get(), 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // At the moment we don't really care about dialog type, but we have to put 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // some dialog type. 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) second_dialog_->SelectFile(ui::SelectFileDialog::SELECT_OPEN_FILE, 185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16() /* title */, 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath() /* default_path */, 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL /* file_types */, 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0 /* file_type_index */, 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE_PATH_LITERAL("") /* default_extension */, 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) owning_window, 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this /* params */); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CloseDialog(DialogButtonType button_type, 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::NativeWindow& owning_window) { 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Inject JavaScript to click the cancel button and wait for notification 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that the window has closed. 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::WindowedNotificationObserver host_destroyed( 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationService::AllSources()); 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::RenderViewHost* host = dialog_->GetRenderViewHost(); 202a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 main_frame; 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string button_class = 204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (button_type == DIALOG_BTN_OK) ? ".button-panel .ok" : 205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ".button-panel .cancel"; 206a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 script = ASCIIToUTF16( 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "console.log(\'Test JavaScript injected.\');" 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "document.querySelector(\'" + button_class + "\').click();"); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The file selection handler closes the dialog and does not return control 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to JavaScript, so do not wait for return values. 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) host->ExecuteJavascriptInWebFrame(main_frame, script); 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "Waiting for window close notification."; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) host_destroyed.Wait(); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Dialog no longer believes it is running. 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_FALSE(dialog_->IsRunning(owning_window)); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<MockSelectFileDialogListener> listener_; 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<SelectFileDialogExtension> dialog_; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<MockSelectFileDialogListener> second_listener_; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<SelectFileDialogExtension> second_dialog_; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::ScopedTempDir tmp_dir_; 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath downloads_dir_; 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest, CreateAndDestroy) { 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Browser window must be up for us to test dialog window parent. 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::NativeWindow native_window = browser()->window()->GetNativeWindow(); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(native_window != NULL); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Before we call SelectFile, dialog is not running/visible. 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_FALSE(dialog_->IsRunning(native_window)); 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest, DestroyListener) { 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Some users of SelectFileDialog destroy their listener before cleaning 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // up the dialog. Make sure we don't crash. 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dialog_->ListenerDestroyed(); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listener_.reset(); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(jamescook): Add a test for selecting a file for an <input type='file'/> 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// page element, as that uses different memory management pathways. 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// crbug.com/98791 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest, 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SelectFileAndCancel) { 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddMountPoint(downloads_dir_); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::NativeWindow owning_window = browser()->window()->GetNativeWindow(); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // base::FilePath() for default path. 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_OPEN_FILE, 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath(), owning_window, "")); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Press cancel button. 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CloseDialog(DIALOG_BTN_CANCEL, owning_window); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Listener should have been informed of the cancellation. 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_FALSE(listener_->file_selected()); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(listener_->canceled()); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_EQ(this, listener_->params()); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest, 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SelectFileAndOpen) { 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddMountPoint(downloads_dir_); 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath test_file = 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) downloads_dir_.AppendASCII("file_manager_test.html"); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create an empty file to give us something to select. 276a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) FILE* fp = base::OpenFile(test_file, "w"); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(fp != NULL); 278a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ASSERT_TRUE(base::CloseFile(fp)); 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::NativeWindow owning_window = browser()->window()->GetNativeWindow(); 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Spawn a dialog to open a file. Provide the path to the file so the dialog 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will automatically select it. Ensure that the OK button is enabled by 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // waiting for chrome.test.sendMessage('selection-change-complete'). 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The extension starts a Web Worker to read file metadata, so it may send 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 'selection-change-complete' before 'worker-initialized'. This is OK. 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_OPEN_FILE, 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) test_file, owning_window, 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "selection-change-complete")); 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Click open button. 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CloseDialog(DIALOG_BTN_OK, owning_window); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Listener should have been informed that the file was opened. 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(listener_->file_selected()); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_FALSE(listener_->canceled()); 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_EQ(test_file, listener_->path()); 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_EQ(this, listener_->params()); 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest, 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SelectFileAndSave) { 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddMountPoint(downloads_dir_); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath test_file = 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) downloads_dir_.AppendASCII("file_manager_test.html"); 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::NativeWindow owning_window = browser()->window()->GetNativeWindow(); 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Spawn a dialog to save a file, providing a suggested path. 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ensure "Save" button is enabled by waiting for notification from 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // chrome.test.sendMessage(). 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The extension starts a Web Worker to read file metadata, so it may send 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 'directory-change-complete' before 'worker-initialized'. This is OK. 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_SAVEAS_FILE, 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) test_file, owning_window, 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "directory-change-complete")); 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Click save button. 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CloseDialog(DIALOG_BTN_OK, owning_window); 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Listener should have been informed that the file was selected. 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(listener_->file_selected()); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_FALSE(listener_->canceled()); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_EQ(test_file, listener_->path()); 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_EQ(this, listener_->params()); 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest, 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OpenSingletonTabAndCancel) { 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddMountPoint(downloads_dir_); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::NativeWindow owning_window = browser()->window()->GetNativeWindow(); 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_OPEN_FILE, 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath(), owning_window, "")); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Open a singleton tab in background. 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::NavigateParams p(browser(), GURL("www.google.com"), 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::PAGE_TRANSITION_LINK); 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p.window_action = chrome::NavigateParams::SHOW_WINDOW; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p.disposition = SINGLETON_TAB; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::Navigate(&p); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Press cancel button. 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CloseDialog(DIALOG_BTN_CANCEL, owning_window); 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Listener should have been informed of the cancellation. 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_FALSE(listener_->file_selected()); 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(listener_->canceled()); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_EQ(this, listener_->params()); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest, 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OpenTwoDialogs) { 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddMountPoint(downloads_dir_); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::NativeWindow owning_window = browser()->window()->GetNativeWindow(); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_OPEN_FILE, 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath(), owning_window, "")); 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TryOpeningSecondDialog(owning_window); 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Second dialog should not be running. 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_FALSE(second_dialog_->IsRunning(owning_window)); 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Click cancel button. 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CloseDialog(DIALOG_BTN_CANCEL, owning_window); 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Listener should have been informed of the cancellation. 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_FALSE(listener_->file_selected()); 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(listener_->canceled()); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_EQ(this, listener_->params()); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 376