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 "base/files/file_path.h" 6 #include "base/strings/string_split.h" 7 #include "base/strings/string_util.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "chrome/browser/extensions/api/file_system/file_system_api.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 #include "ui/shell_dialogs/select_file_dialog.h" 12 13 using extensions::FileSystemChooseEntryFunction; 14 using extensions::api::file_system::AcceptOption; 15 16 namespace { 17 18 void CheckExtensions(const std::vector<base::FilePath::StringType>& expected, 19 const std::vector<base::FilePath::StringType>& actual) { 20 EXPECT_EQ(expected.size(), actual.size()); 21 if (expected.size() != actual.size()) 22 return; 23 24 for (size_t i = 0; i < expected.size(); ++i) { 25 EXPECT_EQ(expected[i], actual[i]); 26 } 27 } 28 29 AcceptOption* BuildAcceptOption(const std::string& description, 30 const std::string& mime_types, 31 const std::string& extensions) { 32 AcceptOption* option = new AcceptOption(); 33 34 if (!description.empty()) 35 option->description.reset(new std::string(description)); 36 37 if (!mime_types.empty()) { 38 option->mime_types.reset(new std::vector<std::string>()); 39 base::SplitString(mime_types, ',', option->mime_types.get()); 40 } 41 42 if (!extensions.empty()) { 43 option->extensions.reset(new std::vector<std::string>()); 44 base::SplitString(extensions, ',', option->extensions.get()); 45 } 46 47 return option; 48 } 49 50 #if defined(OS_WIN) 51 #define ToStringType base::UTF8ToWide 52 #else 53 #define ToStringType 54 #endif 55 56 } // namespace 57 58 class FileSystemApiUnitTest : public testing::Test { 59 }; 60 61 TEST_F(FileSystemApiUnitTest, FileSystemChooseEntryFunctionFileTypeInfoTest) { 62 // AcceptsAllTypes is ignored when no other extensions are available. 63 ui::SelectFileDialog::FileTypeInfo file_type_info; 64 bool acceptsAllTypes = false; 65 FileSystemChooseEntryFunction::BuildFileTypeInfo(&file_type_info, 66 base::FilePath::StringType(), NULL, &acceptsAllTypes); 67 EXPECT_TRUE(file_type_info.include_all_files); 68 EXPECT_TRUE(file_type_info.extensions.empty()); 69 70 // Test grouping of multiple types. 71 file_type_info = ui::SelectFileDialog::FileTypeInfo(); 72 std::vector<linked_ptr<AcceptOption> > options; 73 options.push_back(linked_ptr<AcceptOption>(BuildAcceptOption( 74 std::string(), "application/x-chrome-extension", "jso"))); 75 acceptsAllTypes = false; 76 FileSystemChooseEntryFunction::BuildFileTypeInfo(&file_type_info, 77 base::FilePath::StringType(), &options, &acceptsAllTypes); 78 EXPECT_FALSE(file_type_info.include_all_files); 79 ASSERT_EQ(file_type_info.extensions.size(), (size_t) 1); 80 EXPECT_TRUE(file_type_info.extension_description_overrides[0].empty()) << 81 "No override must be specified for boring accept types"; 82 // Note here (and below) that the expectedTypes are sorted, because we use a 83 // set internally to generate the output: thus, the output is sorted. 84 std::vector<base::FilePath::StringType> expectedTypes; 85 expectedTypes.push_back(ToStringType("crx")); 86 expectedTypes.push_back(ToStringType("jso")); 87 CheckExtensions(expectedTypes, file_type_info.extensions[0]); 88 89 // Test that not satisfying the extension will force all types. 90 file_type_info = ui::SelectFileDialog::FileTypeInfo(); 91 options.clear(); 92 options.push_back(linked_ptr<AcceptOption>(BuildAcceptOption( 93 std::string(), std::string(), "unrelated"))); 94 acceptsAllTypes = false; 95 FileSystemChooseEntryFunction::BuildFileTypeInfo(&file_type_info, 96 ToStringType(".jso"), &options, &acceptsAllTypes); 97 EXPECT_TRUE(file_type_info.include_all_files); 98 99 // Test multiple list entries, all containing their own types. 100 file_type_info = ui::SelectFileDialog::FileTypeInfo(); 101 options.clear(); 102 options.push_back(linked_ptr<AcceptOption>( 103 BuildAcceptOption(std::string(), std::string(), "jso,js"))); 104 options.push_back(linked_ptr<AcceptOption>( 105 BuildAcceptOption(std::string(), std::string(), "cpp,cc"))); 106 acceptsAllTypes = false; 107 FileSystemChooseEntryFunction::BuildFileTypeInfo(&file_type_info, 108 base::FilePath::StringType(), &options, &acceptsAllTypes); 109 ASSERT_EQ(file_type_info.extensions.size(), options.size()); 110 111 expectedTypes.clear(); 112 expectedTypes.push_back(ToStringType("js")); 113 expectedTypes.push_back(ToStringType("jso")); 114 CheckExtensions(expectedTypes, file_type_info.extensions[0]); 115 116 expectedTypes.clear(); 117 expectedTypes.push_back(ToStringType("cc")); 118 expectedTypes.push_back(ToStringType("cpp")); 119 CheckExtensions(expectedTypes, file_type_info.extensions[1]); 120 121 // Test accept type that causes description override. 122 file_type_info = ui::SelectFileDialog::FileTypeInfo(); 123 options.clear(); 124 options.push_back(linked_ptr<AcceptOption>( 125 BuildAcceptOption(std::string(), "image/*", "html"))); 126 acceptsAllTypes = false; 127 FileSystemChooseEntryFunction::BuildFileTypeInfo(&file_type_info, 128 base::FilePath::StringType(), &options, &acceptsAllTypes); 129 ASSERT_EQ(file_type_info.extension_description_overrides.size(), (size_t) 1); 130 EXPECT_FALSE(file_type_info.extension_description_overrides[0].empty()) << 131 "Accept type \"image/*\" must generate description override"; 132 133 // Test multiple accept types that cause description override causes us to 134 // still present the default. 135 file_type_info = ui::SelectFileDialog::FileTypeInfo(); 136 options.clear(); 137 options.push_back(linked_ptr<AcceptOption>(BuildAcceptOption( 138 std::string(), "image/*,audio/*,video/*", std::string()))); 139 acceptsAllTypes = false; 140 FileSystemChooseEntryFunction::BuildFileTypeInfo(&file_type_info, 141 base::FilePath::StringType(), &options, &acceptsAllTypes); 142 ASSERT_EQ(file_type_info.extension_description_overrides.size(), (size_t) 1); 143 EXPECT_TRUE(file_type_info.extension_description_overrides[0].empty()); 144 145 // Test explicit description override. 146 file_type_info = ui::SelectFileDialog::FileTypeInfo(); 147 options.clear(); 148 options.push_back(linked_ptr<AcceptOption>( 149 BuildAcceptOption("File Types 101", "image/jpeg", std::string()))); 150 acceptsAllTypes = false; 151 FileSystemChooseEntryFunction::BuildFileTypeInfo(&file_type_info, 152 base::FilePath::StringType(), &options, &acceptsAllTypes); 153 EXPECT_EQ(file_type_info.extension_description_overrides[0], 154 base::UTF8ToUTF16("File Types 101")); 155 } 156 157 TEST_F(FileSystemApiUnitTest, FileSystemChooseEntryFunctionSuggestionTest) { 158 std::string opt_name; 159 base::FilePath suggested_name; 160 base::FilePath::StringType suggested_extension; 161 162 opt_name = std::string("normal_path.txt"); 163 FileSystemChooseEntryFunction::BuildSuggestion(&opt_name, &suggested_name, 164 &suggested_extension); 165 EXPECT_FALSE(suggested_name.IsAbsolute()); 166 EXPECT_EQ(suggested_name.MaybeAsASCII(), "normal_path.txt"); 167 EXPECT_EQ(suggested_extension, ToStringType("txt")); 168 169 // We should provide just the basename, i.e., "path". 170 opt_name = std::string("/a/bad/path"); 171 FileSystemChooseEntryFunction::BuildSuggestion(&opt_name, &suggested_name, 172 &suggested_extension); 173 EXPECT_FALSE(suggested_name.IsAbsolute()); 174 EXPECT_EQ(suggested_name.MaybeAsASCII(), "path"); 175 EXPECT_TRUE(suggested_extension.empty()); 176 177 #if !defined(OS_WIN) 178 // TODO(thorogood): Fix this test on Windows. 179 // Filter out absolute paths with no basename. 180 opt_name = std::string("/"); 181 FileSystemChooseEntryFunction::BuildSuggestion(&opt_name, &suggested_name, 182 &suggested_extension); 183 EXPECT_FALSE(suggested_name.IsAbsolute()); 184 EXPECT_TRUE(suggested_name.MaybeAsASCII().empty()); 185 EXPECT_TRUE(suggested_extension.empty()); 186 #endif 187 } 188