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