blob: 20e1bba2794f09107a6f593b5144b39e5ea04a14 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "file_selector_plugin.h"
#include <flutter/method_call.h>
#include <flutter/method_result_functions.h>
#include <flutter/plugin_registrar_windows.h>
#include <flutter/standard_method_codec.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <windows.h>
#include <functional>
#include <memory>
#include <string>
#include <variant>
#include "file_dialog_controller.h"
#include "string_utils.h"
#include "test/test_file_dialog_controller.h"
#include "test/test_utils.h"
namespace file_selector_windows {
namespace test {
namespace {
using flutter::EncodableList;
using flutter::EncodableMap;
using flutter::EncodableValue;
using flutter::MethodCall;
using ::testing::DoAll;
using ::testing::Pointee;
using ::testing::Return;
using ::testing::SetArgPointee;
class MockMethodResult : public flutter::MethodResult<> {
public:
MOCK_METHOD(void, SuccessInternal, (const EncodableValue* result),
(override));
MOCK_METHOD(void, ErrorInternal,
(const std::string& error_code, const std::string& error_message,
const EncodableValue* details),
(override));
MOCK_METHOD(void, NotImplementedInternal, (), (override));
};
} // namespace
TEST(FileSelectorPlugin, TestOpenSimple) {
const HWND fake_window = reinterpret_cast<HWND>(1337);
ScopedTestShellItem fake_selected_file;
IShellItemArrayPtr fake_result_array;
::SHCreateShellItemArrayFromShellItem(fake_selected_file.file(),
IID_PPV_ARGS(&fake_result_array));
std::unique_ptr<MockMethodResult> result =
std::make_unique<MockMethodResult>();
bool shown = false;
MockShow show_validator = [&shown, fake_result_array, fake_window](
const TestFileDialogController& dialog,
HWND parent) {
shown = true;
EXPECT_EQ(parent, fake_window);
// Validate options.
FILEOPENDIALOGOPTIONS options;
dialog.GetOptions(&options);
EXPECT_EQ(options & FOS_ALLOWMULTISELECT, 0U);
EXPECT_EQ(options & FOS_PICKFOLDERS, 0U);
return MockShowResult(fake_result_array);
};
EncodableValue expected_paths(EncodableList({
EncodableValue(Utf8FromUtf16(fake_selected_file.path())),
}));
// Expect the mock path.
EXPECT_CALL(*result, SuccessInternal(Pointee(expected_paths)));
FileSelectorPlugin plugin(
[fake_window] { return fake_window; },
std::make_unique<TestFileDialogControllerFactory>(show_validator));
plugin.HandleMethodCall(
MethodCall("openFile", std::make_unique<EncodableValue>(EncodableMap())),
std::move(result));
EXPECT_TRUE(shown);
}
TEST(FileSelectorPlugin, TestOpenWithArguments) {
const HWND fake_window = reinterpret_cast<HWND>(1337);
ScopedTestShellItem fake_selected_file;
IShellItemArrayPtr fake_result_array;
::SHCreateShellItemArrayFromShellItem(fake_selected_file.file(),
IID_PPV_ARGS(&fake_result_array));
std::unique_ptr<MockMethodResult> result =
std::make_unique<MockMethodResult>();
bool shown = false;
MockShow show_validator = [&shown, fake_result_array, fake_window](
const TestFileDialogController& dialog,
HWND parent) {
shown = true;
EXPECT_EQ(parent, fake_window);
// Validate arguments.
EXPECT_EQ(dialog.GetDefaultFolderPath(), L"C:\\Program Files");
EXPECT_EQ(dialog.GetFileName(), L"a name");
EXPECT_EQ(dialog.GetOkButtonLabel(), L"Open it!");
return MockShowResult(fake_result_array);
};
EncodableValue expected_paths(EncodableList({
EncodableValue(Utf8FromUtf16(fake_selected_file.path())),
}));
// Expect the mock path.
EXPECT_CALL(*result, SuccessInternal(Pointee(expected_paths)));
FileSelectorPlugin plugin(
[fake_window] { return fake_window; },
std::make_unique<TestFileDialogControllerFactory>(show_validator));
plugin.HandleMethodCall(
MethodCall(
"openFile",
std::make_unique<EncodableValue>(EncodableMap({
// This directory must exist.
{EncodableValue("initialDirectory"),
EncodableValue("C:\\Program Files")},
{EncodableValue("suggestedName"), EncodableValue("a name")},
{EncodableValue("confirmButtonText"), EncodableValue("Open it!")},
}))),
std::move(result));
EXPECT_TRUE(shown);
}
TEST(FileSelectorPlugin, TestOpenMultiple) {
const HWND fake_window = reinterpret_cast<HWND>(1337);
ScopedTestFileIdList fake_selected_file_1;
ScopedTestFileIdList fake_selected_file_2;
LPCITEMIDLIST fake_selected_files[] = {
fake_selected_file_1.file(),
fake_selected_file_2.file(),
};
IShellItemArrayPtr fake_result_array;
::SHCreateShellItemArrayFromIDLists(2, fake_selected_files,
&fake_result_array);
std::unique_ptr<MockMethodResult> result =
std::make_unique<MockMethodResult>();
bool shown = false;
MockShow show_validator = [&shown, fake_result_array, fake_window](
const TestFileDialogController& dialog,
HWND parent) {
shown = true;
EXPECT_EQ(parent, fake_window);
// Validate options.
FILEOPENDIALOGOPTIONS options;
dialog.GetOptions(&options);
EXPECT_NE(options & FOS_ALLOWMULTISELECT, 0U);
EXPECT_EQ(options & FOS_PICKFOLDERS, 0U);
return MockShowResult(fake_result_array);
};
EncodableValue expected_paths(EncodableList({
EncodableValue(Utf8FromUtf16(fake_selected_file_1.path())),
EncodableValue(Utf8FromUtf16(fake_selected_file_2.path())),
}));
// Expect the mock path.
EXPECT_CALL(*result, SuccessInternal(Pointee(expected_paths)));
FileSelectorPlugin plugin(
[fake_window] { return fake_window; },
std::make_unique<TestFileDialogControllerFactory>(show_validator));
plugin.HandleMethodCall(
MethodCall("openFile",
std::make_unique<EncodableValue>(EncodableMap({
{EncodableValue("multiple"), EncodableValue(true)},
}))),
std::move(result));
EXPECT_TRUE(shown);
}
TEST(FileSelectorPlugin, TestOpenWithFilter) {
const HWND fake_window = reinterpret_cast<HWND>(1337);
ScopedTestShellItem fake_selected_file;
IShellItemArrayPtr fake_result_array;
::SHCreateShellItemArrayFromShellItem(fake_selected_file.file(),
IID_PPV_ARGS(&fake_result_array));
std::unique_ptr<MockMethodResult> result =
std::make_unique<MockMethodResult>();
const EncodableValue text_group = EncodableValue(EncodableMap({
{EncodableValue("label"), EncodableValue("Text")},
{EncodableValue("extensions"), EncodableValue(EncodableList({
EncodableValue("txt"),
EncodableValue("json"),
}))},
}));
const EncodableValue image_group = EncodableValue(EncodableMap({
{EncodableValue("label"), EncodableValue("Images")},
{EncodableValue("extensions"), EncodableValue(EncodableList({
EncodableValue("png"),
EncodableValue("gif"),
EncodableValue("jpeg"),
}))},
}));
const EncodableValue any_group = EncodableValue(EncodableMap({
{EncodableValue("label"), EncodableValue("Any")},
}));
bool shown = false;
MockShow show_validator = [&shown, fake_result_array, fake_window](
const TestFileDialogController& dialog,
HWND parent) {
shown = true;
EXPECT_EQ(parent, fake_window);
// Validate filter.
const std::vector<DialogFilter>& filters = dialog.GetFileTypes();
EXPECT_EQ(filters.size(), 3U);
if (filters.size() == 3U) {
EXPECT_EQ(filters[0].name, L"Text");
EXPECT_EQ(filters[0].spec, L"*.txt;*.json");
EXPECT_EQ(filters[1].name, L"Images");
EXPECT_EQ(filters[1].spec, L"*.png;*.gif;*.jpeg");
EXPECT_EQ(filters[2].name, L"Any");
EXPECT_EQ(filters[2].spec, L"*.*");
}
return MockShowResult(fake_result_array);
};
EncodableValue expected_paths(EncodableList({
EncodableValue(Utf8FromUtf16(fake_selected_file.path())),
}));
// Expect the mock path.
EXPECT_CALL(*result, SuccessInternal(Pointee(expected_paths)));
FileSelectorPlugin plugin(
[fake_window] { return fake_window; },
std::make_unique<TestFileDialogControllerFactory>(show_validator));
plugin.HandleMethodCall(
MethodCall("openFile", std::make_unique<EncodableValue>(EncodableMap({
{EncodableValue("acceptedTypeGroups"),
EncodableValue(EncodableList({
text_group,
image_group,
any_group,
}))},
}))),
std::move(result));
EXPECT_TRUE(shown);
}
TEST(FileSelectorPlugin, TestOpenCancel) {
const HWND fake_window = reinterpret_cast<HWND>(1337);
std::unique_ptr<MockMethodResult> result =
std::make_unique<MockMethodResult>();
bool shown = false;
MockShow show_validator = [&shown, fake_window](
const TestFileDialogController& dialog,
HWND parent) {
shown = true;
return MockShowResult();
};
// Cancel should return a null for the paths.
EncodableValue expected_paths;
// Expect the mock path.
EXPECT_CALL(*result, SuccessInternal(Pointee(expected_paths)));
FileSelectorPlugin plugin(
[fake_window] { return fake_window; },
std::make_unique<TestFileDialogControllerFactory>(show_validator));
plugin.HandleMethodCall(
MethodCall("openFile", std::make_unique<EncodableValue>(EncodableMap())),
std::move(result));
EXPECT_TRUE(shown);
}
TEST(FileSelectorPlugin, TestSaveSimple) {
const HWND fake_window = reinterpret_cast<HWND>(1337);
ScopedTestShellItem fake_selected_file;
std::unique_ptr<MockMethodResult> result =
std::make_unique<MockMethodResult>();
bool shown = false;
MockShow show_validator =
[&shown, fake_result = fake_selected_file.file(), fake_window](
const TestFileDialogController& dialog, HWND parent) {
shown = true;
EXPECT_EQ(parent, fake_window);
// Validate options.
FILEOPENDIALOGOPTIONS options;
dialog.GetOptions(&options);
EXPECT_EQ(options & FOS_ALLOWMULTISELECT, 0U);
EXPECT_EQ(options & FOS_PICKFOLDERS, 0U);
return MockShowResult(fake_result);
};
EncodableValue expected_path(Utf8FromUtf16(fake_selected_file.path()));
// Expect the mock path.
EXPECT_CALL(*result, SuccessInternal(Pointee(expected_path)));
FileSelectorPlugin plugin(
[fake_window] { return fake_window; },
std::make_unique<TestFileDialogControllerFactory>(show_validator));
plugin.HandleMethodCall(
MethodCall("getSavePath",
std::make_unique<EncodableValue>(EncodableMap())),
std::move(result));
EXPECT_TRUE(shown);
}
TEST(FileSelectorPlugin, TestSaveWithArguments) {
const HWND fake_window = reinterpret_cast<HWND>(1337);
ScopedTestShellItem fake_selected_file;
std::unique_ptr<MockMethodResult> result =
std::make_unique<MockMethodResult>();
bool shown = false;
MockShow show_validator =
[&shown, fake_result = fake_selected_file.file(), fake_window](
const TestFileDialogController& dialog, HWND parent) {
shown = true;
EXPECT_EQ(parent, fake_window);
// Validate arguments.
EXPECT_EQ(dialog.GetDefaultFolderPath(), L"C:\\Program Files");
EXPECT_EQ(dialog.GetOkButtonLabel(), L"Save it!");
return MockShowResult(fake_result);
};
EncodableValue expected_path(Utf8FromUtf16(fake_selected_file.path()));
// Expect the mock path.
EXPECT_CALL(*result, SuccessInternal(Pointee(expected_path)));
FileSelectorPlugin plugin(
[fake_window] { return fake_window; },
std::make_unique<TestFileDialogControllerFactory>(show_validator));
plugin.HandleMethodCall(
MethodCall(
"getSavePath",
std::make_unique<EncodableValue>(EncodableMap({
// This directory must exist.
{EncodableValue("initialDirectory"),
EncodableValue("C:\\Program Files")},
{EncodableValue("confirmButtonText"), EncodableValue("Save it!")},
}))),
std::move(result));
EXPECT_TRUE(shown);
}
TEST(FileSelectorPlugin, TestSaveCancel) {
const HWND fake_window = reinterpret_cast<HWND>(1337);
std::unique_ptr<MockMethodResult> result =
std::make_unique<MockMethodResult>();
bool shown = false;
MockShow show_validator = [&shown, fake_window](
const TestFileDialogController& dialog,
HWND parent) {
shown = true;
return MockShowResult();
};
// Cancel should return a null for the path.
EncodableValue expected_path;
// Expect the mock path.
EXPECT_CALL(*result, SuccessInternal(Pointee(expected_path)));
FileSelectorPlugin plugin(
[fake_window] { return fake_window; },
std::make_unique<TestFileDialogControllerFactory>(show_validator));
plugin.HandleMethodCall(
MethodCall("getSavePath",
std::make_unique<EncodableValue>(EncodableMap())),
std::move(result));
EXPECT_TRUE(shown);
}
TEST(FileSelectorPlugin, TestGetDirectorySimple) {
const HWND fake_window = reinterpret_cast<HWND>(1337);
IShellItemPtr fake_selected_directory;
// This must be a directory that actually exists.
::SHCreateItemFromParsingName(L"C:\\Program Files", nullptr,
IID_PPV_ARGS(&fake_selected_directory));
IShellItemArrayPtr fake_result_array;
::SHCreateShellItemArrayFromShellItem(fake_selected_directory,
IID_PPV_ARGS(&fake_result_array));
std::unique_ptr<MockMethodResult> result =
std::make_unique<MockMethodResult>();
bool shown = false;
MockShow show_validator = [&shown, fake_result_array, fake_window](
const TestFileDialogController& dialog,
HWND parent) {
shown = true;
EXPECT_EQ(parent, fake_window);
// Validate options.
FILEOPENDIALOGOPTIONS options;
dialog.GetOptions(&options);
EXPECT_EQ(options & FOS_ALLOWMULTISELECT, 0U);
EXPECT_NE(options & FOS_PICKFOLDERS, 0U);
return MockShowResult(fake_result_array);
};
EncodableValue expected_path("C:\\Program Files");
// Expect the mock path.
EXPECT_CALL(*result, SuccessInternal(Pointee(expected_path)));
FileSelectorPlugin plugin(
[fake_window] { return fake_window; },
std::make_unique<TestFileDialogControllerFactory>(show_validator));
plugin.HandleMethodCall(
MethodCall("getDirectoryPath",
std::make_unique<EncodableValue>(EncodableMap())),
std::move(result));
EXPECT_TRUE(shown);
}
TEST(FileSelectorPlugin, TestGetDirectoryCancel) {
const HWND fake_window = reinterpret_cast<HWND>(1337);
std::unique_ptr<MockMethodResult> result =
std::make_unique<MockMethodResult>();
bool shown = false;
MockShow show_validator = [&shown, fake_window](
const TestFileDialogController& dialog,
HWND parent) {
shown = true;
return MockShowResult();
};
// Cancel should return a null for the path.
EncodableValue expected_path;
// Expect the mock path.
EXPECT_CALL(*result, SuccessInternal(Pointee(expected_path)));
FileSelectorPlugin plugin(
[fake_window] { return fake_window; },
std::make_unique<TestFileDialogControllerFactory>(show_validator));
plugin.HandleMethodCall(
MethodCall("getDirectoryPath",
std::make_unique<EncodableValue>(EncodableMap())),
std::move(result));
EXPECT_TRUE(shown);
}
} // namespace test
} // namespace file_selector_windows