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)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/shell_dialogs/selected_file_info.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const SelectFileDialogExtension::RoutingID kDefaultRoutingID =
141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    SelectFileDialogExtension::RoutingID();
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Must be a class so it can be a friend of SelectFileDialogExtension.
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SelectFileDialogExtensionTest : public testing::Test {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SelectFileDialogExtensionTest() {}
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~SelectFileDialogExtensionTest() {}
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static SelectFileDialogExtension* CreateDialog(
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ui::SelectFileDialog::Listener* listener) {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SelectFileDialogExtension* dialog = new SelectFileDialogExtension(listener,
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                                      NULL);
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Simulate the dialog opening.
291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_FALSE(SelectFileDialogExtension::PendingExists(kDefaultRoutingID));
301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    dialog->AddPending(kDefaultRoutingID);
311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_TRUE(SelectFileDialogExtension::PendingExists(kDefaultRoutingID));
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return dialog;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SelectFileDialogExtensionTest);
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Test listener for a SelectFileDialog.
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class TestListener : public ui::SelectFileDialog::Listener {
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TestListener() : selected_(false), file_index_(-1) {}
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~TestListener() {}
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool selected() const { return selected_; }
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int file_index() const { return file_index_; }
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // ui::SelectFileDialog::Listener implementation
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void FileSelected(const base::FilePath& path,
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            int index,
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            void* params) OVERRIDE {
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    selected_ = true;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    file_index_ = index;
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool selected_;
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int file_index_;
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TestListener);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Client of a SelectFileDialog that deletes itself whenever the dialog
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// is closed. This is a common pattern in UI code.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SelfDeletingClient : public ui::SelectFileDialog::Listener {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SelfDeletingClient() {
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dialog_ = SelectFileDialogExtensionTest::CreateDialog(this);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~SelfDeletingClient() {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (dialog_.get())
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dialog_->ListenerDestroyed();
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SelectFileDialogExtension* dialog() const { return dialog_.get(); }
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ui::SelectFileDialog::Listener implementation
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void FileSelected(const base::FilePath& path,
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            int index,
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            void* params) OVERRIDE {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete this;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<SelectFileDialogExtension> dialog_;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(SelectFileDialogExtensionTest, FileSelected) {
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int kFileIndex = 5;
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<TestListener> listener(new TestListener);
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<SelectFileDialogExtension> dialog =
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      CreateDialog(listener.get());
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Simulate selecting a file.
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::SelectedFileInfo info;
961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SelectFileDialogExtension::OnFileSelected(kDefaultRoutingID, info,
971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                            kFileIndex);
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Simulate closing the dialog so the listener gets invoked.
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dialog->ExtensionDialogClosing(NULL);
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(listener->selected());
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(kFileIndex, listener->file_index());
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(SelectFileDialogExtensionTest, FileSelectionCanceled) {
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<TestListener> listener(new TestListener);
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<SelectFileDialogExtension> dialog =
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      CreateDialog(listener.get());
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Simulate cancelling the dialog.
1091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SelectFileDialogExtension::OnFileSelectionCanceled(kDefaultRoutingID);
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Simulate closing the dialog so the listener gets invoked.
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dialog->ExtensionDialogClosing(NULL);
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_FALSE(listener->selected());
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(-1, listener->file_index());
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SelectFileDialogExtensionTest, SelfDeleting) {
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SelfDeletingClient* client = new SelfDeletingClient();
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ensure we don't crash or trip an Address Sanitizer warning about
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // use-after-free.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::SelectedFileInfo file_info;
1211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SelectFileDialogExtension::OnFileSelected(kDefaultRoutingID, file_info, 0);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Simulate closing the dialog so the listener gets invoked.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  client->dialog()->ExtensionDialogClosing(NULL);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
125