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/browser/ui/views/select_file_dialog_extension.h" 6 7#include "base/files/file_path.h" 8#include "testing/gtest/include/gtest/gtest.h" 9#include "ui/shell_dialogs/selected_file_info.h" 10 11namespace { 12 13const SelectFileDialogExtension::RoutingID kDefaultRoutingID = 14 SelectFileDialogExtension::RoutingID(); 15 16} // namespace 17 18// Must be a class so it can be a friend of SelectFileDialogExtension. 19class SelectFileDialogExtensionTest : public testing::Test { 20 public: 21 SelectFileDialogExtensionTest() {} 22 virtual ~SelectFileDialogExtensionTest() {} 23 24 static SelectFileDialogExtension* CreateDialog( 25 ui::SelectFileDialog::Listener* listener) { 26 SelectFileDialogExtension* dialog = new SelectFileDialogExtension(listener, 27 NULL); 28 // Simulate the dialog opening. 29 EXPECT_FALSE(SelectFileDialogExtension::PendingExists(kDefaultRoutingID)); 30 dialog->AddPending(kDefaultRoutingID); 31 EXPECT_TRUE(SelectFileDialogExtension::PendingExists(kDefaultRoutingID)); 32 return dialog; 33 } 34 35 private: 36 DISALLOW_COPY_AND_ASSIGN(SelectFileDialogExtensionTest); 37}; 38 39// Test listener for a SelectFileDialog. 40class TestListener : public ui::SelectFileDialog::Listener { 41 public: 42 TestListener() : selected_(false), file_index_(-1) {} 43 virtual ~TestListener() {} 44 45 bool selected() const { return selected_; } 46 int file_index() const { return file_index_; } 47 48 // ui::SelectFileDialog::Listener implementation 49 virtual void FileSelected(const base::FilePath& path, 50 int index, 51 void* params) OVERRIDE { 52 selected_ = true; 53 file_index_ = index; 54 } 55 56 private: 57 bool selected_; 58 int file_index_; 59 60 DISALLOW_COPY_AND_ASSIGN(TestListener); 61}; 62 63// Client of a SelectFileDialog that deletes itself whenever the dialog 64// is closed. This is a common pattern in UI code. 65class SelfDeletingClient : public ui::SelectFileDialog::Listener { 66 public: 67 SelfDeletingClient() { 68 dialog_ = SelectFileDialogExtensionTest::CreateDialog(this); 69 } 70 71 virtual ~SelfDeletingClient() { 72 if (dialog_.get()) 73 dialog_->ListenerDestroyed(); 74 } 75 76 SelectFileDialogExtension* dialog() const { return dialog_.get(); } 77 78 // ui::SelectFileDialog::Listener implementation 79 virtual void FileSelected(const base::FilePath& path, 80 int index, 81 void* params) OVERRIDE { 82 delete this; 83 } 84 85 private: 86 scoped_refptr<SelectFileDialogExtension> dialog_; 87}; 88 89TEST_F(SelectFileDialogExtensionTest, FileSelected) { 90 const int kFileIndex = 5; 91 scoped_ptr<TestListener> listener(new TestListener); 92 scoped_refptr<SelectFileDialogExtension> dialog = 93 CreateDialog(listener.get()); 94 // Simulate selecting a file. 95 ui::SelectedFileInfo info; 96 SelectFileDialogExtension::OnFileSelected(kDefaultRoutingID, info, 97 kFileIndex); 98 // Simulate closing the dialog so the listener gets invoked. 99 dialog->ExtensionDialogClosing(NULL); 100 EXPECT_TRUE(listener->selected()); 101 EXPECT_EQ(kFileIndex, listener->file_index()); 102} 103 104TEST_F(SelectFileDialogExtensionTest, FileSelectionCanceled) { 105 scoped_ptr<TestListener> listener(new TestListener); 106 scoped_refptr<SelectFileDialogExtension> dialog = 107 CreateDialog(listener.get()); 108 // Simulate cancelling the dialog. 109 SelectFileDialogExtension::OnFileSelectionCanceled(kDefaultRoutingID); 110 // Simulate closing the dialog so the listener gets invoked. 111 dialog->ExtensionDialogClosing(NULL); 112 EXPECT_FALSE(listener->selected()); 113 EXPECT_EQ(-1, listener->file_index()); 114} 115 116TEST_F(SelectFileDialogExtensionTest, SelfDeleting) { 117 SelfDeletingClient* client = new SelfDeletingClient(); 118 // Ensure we don't crash or trip an Address Sanitizer warning about 119 // use-after-free. 120 ui::SelectedFileInfo file_info; 121 SelectFileDialogExtension::OnFileSelected(kDefaultRoutingID, file_info, 0); 122 // Simulate closing the dialog so the listener gets invoked. 123 client->dialog()->ExtensionDialogClosing(NULL); 124} 125