[M120 Migration]Fix for crash during chrome exit
[platform/framework/web/chromium-efl.git] / chrome / browser / file_select_helper_unittest.cc
1 // Copyright 2012 The Chromium Authors
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/file_select_helper.h"
6
7 #include <stddef.h>
8
9 #include <string>
10 #include <utility>
11 #include <vector>
12
13 #include "base/command_line.h"
14 #include "base/files/file_path.h"
15 #include "base/files/file_util.h"
16 #include "base/files/scoped_temp_dir.h"
17 #include "base/memory/raw_ptr.h"
18 #include "base/path_service.h"
19 #include "base/process/launch.h"
20 #include "build/build_config.h"
21 #include "chrome/common/chrome_paths.h"
22 #include "chrome/test/base/testing_profile.h"
23 #include "content/public/browser/file_select_listener.h"
24 #include "content/public/test/browser_task_environment.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "ui/shell_dialogs/selected_file_info.h"
27
28 using blink::mojom::FileChooserParams;
29
30 #if BUILDFLAG(ENTERPRISE_CLOUD_CONTENT_ANALYSIS)
31 namespace {
32
33 // A listener that remembers the list of files chosen.  The |files| argument
34 // to the ctor must outlive the listener.
35 class TestFileSelectListener : public content::FileSelectListener {
36  public:
37   explicit TestFileSelectListener(
38       std::vector<blink::mojom::FileChooserFileInfoPtr>* files)
39       : files_(files) {}
40
41  private:
42   ~TestFileSelectListener() override = default;
43   // content::FileSelectListener overrides.
44   void FileSelected(std::vector<blink::mojom::FileChooserFileInfoPtr> files,
45                     const base::FilePath& base_dir,
46                     blink::mojom::FileChooserParams::Mode mode) override {
47     *files_ = std::move(files);
48   }
49   void FileSelectionCanceled() override {}
50
51   raw_ptr<std::vector<blink::mojom::FileChooserFileInfoPtr>> files_;
52 };
53
54 // Fill in the arguments to be passed to the ContentAnalysisCompletionCallback()
55 // method based on a list of paths and the desired result for each path.
56 // This function simulates a path either passing the deep scan (status of true)
57 // or failing (status of false).
58 void PrepareContentAnalysisCompletionCallbackArgs(
59     std::vector<base::FilePath> paths,
60     std::vector<bool> status,
61     std::vector<blink::mojom::FileChooserFileInfoPtr>* orig_files,
62     enterprise_connectors::ContentAnalysisDelegate::Data* data,
63     enterprise_connectors::ContentAnalysisDelegate::Result* result) {
64   DCHECK_EQ(status.size(), paths.size());
65
66   if (orig_files) {
67     for (auto& path : paths) {
68       orig_files->push_back(blink::mojom::FileChooserFileInfo::NewNativeFile(
69           blink::mojom::NativeFileInfo::New(path,
70                                             path.BaseName().AsUTF16Unsafe())));
71     }
72   }
73
74   data->paths = std::move(paths);
75   result->paths_results = std::move(status);
76 }
77
78 }  // namespace
79 #endif  // BUILDFLAG(ENTERPRISE_CLOUD_CONTENT_ANALYSIS)
80
81 class FileSelectHelperTest : public testing::Test {
82  public:
83   FileSelectHelperTest() {}
84
85   FileSelectHelperTest(const FileSelectHelperTest&) = delete;
86   FileSelectHelperTest& operator=(const FileSelectHelperTest&) = delete;
87
88  protected:
89   void SetUp() override {
90     ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &data_dir_));
91     data_dir_ = data_dir_.AppendASCII("file_select_helper");
92     ASSERT_TRUE(base::PathExists(data_dir_));
93   }
94
95   // The path to input data used in tests.
96   base::FilePath data_dir_;
97 };
98
99 TEST_F(FileSelectHelperTest, IsAcceptTypeValid) {
100   EXPECT_TRUE(FileSelectHelper::IsAcceptTypeValid("a/b"));
101   EXPECT_TRUE(FileSelectHelper::IsAcceptTypeValid("abc/def"));
102   EXPECT_TRUE(FileSelectHelper::IsAcceptTypeValid("abc/*"));
103   EXPECT_TRUE(FileSelectHelper::IsAcceptTypeValid(".a"));
104   EXPECT_TRUE(FileSelectHelper::IsAcceptTypeValid(".abc"));
105
106   EXPECT_FALSE(FileSelectHelper::IsAcceptTypeValid("."));
107   EXPECT_FALSE(FileSelectHelper::IsAcceptTypeValid("/"));
108   EXPECT_FALSE(FileSelectHelper::IsAcceptTypeValid("ABC/*"));
109   EXPECT_FALSE(FileSelectHelper::IsAcceptTypeValid("abc/def "));
110 }
111
112 #if BUILDFLAG(IS_MAC)
113 TEST_F(FileSelectHelperTest, ZipPackage) {
114   // Zip the package.
115   const char app_name[] = "CalculatorFake.app";
116   base::FilePath src = data_dir_.Append(app_name);
117   base::FilePath dest = FileSelectHelper::ZipPackage(src);
118   ASSERT_FALSE(dest.empty());
119   ASSERT_TRUE(base::PathExists(dest));
120
121   base::ScopedTempDir temp_dir;
122   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
123
124   // Unzip the package into a temporary directory.
125   base::CommandLine cl(base::FilePath("/usr/bin/unzip"));
126   cl.AppendArg(dest.value().c_str());
127   cl.AppendArg("-d");
128   cl.AppendArg(temp_dir.GetPath().value().c_str());
129   std::string output;
130   EXPECT_TRUE(base::GetAppOutput(cl, &output));
131
132   // Verify that several key files haven't changed.
133   const char* files_to_verify[] = {"Contents/Info.plist",
134                                    "Contents/MacOS/Calculator",
135                                    "Contents/_CodeSignature/CodeResources"};
136   size_t file_count = std::size(files_to_verify);
137   for (size_t i = 0; i < file_count; i++) {
138     const char* relative_path = files_to_verify[i];
139     base::FilePath orig_file = src.Append(relative_path);
140     base::FilePath final_file =
141         temp_dir.GetPath().Append(app_name).Append(relative_path);
142     EXPECT_TRUE(base::ContentsEqual(orig_file, final_file));
143   }
144 }
145 #endif  // BUILDFLAG(IS_MAC)
146
147 TEST_F(FileSelectHelperTest, GetSanitizedFileName) {
148   // The empty path should be preserved.
149   EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("")),
150             FileSelectHelper::GetSanitizedFileName(base::FilePath()));
151
152   EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("ascii.txt")),
153             FileSelectHelper::GetSanitizedFileName(
154                 base::FilePath(FILE_PATH_LITERAL("ascii.txt"))));
155   EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("trailing-spaces_")),
156             FileSelectHelper::GetSanitizedFileName(
157                 base::FilePath(FILE_PATH_LITERAL("trailing-spaces "))));
158   EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("path_components_in_name")),
159             FileSelectHelper::GetSanitizedFileName(
160                 base::FilePath(FILE_PATH_LITERAL("path/components/in/name"))));
161
162 #if BUILDFLAG(IS_WIN)
163   // Invalid UTF-16. However, note that on Windows, the invalid UTF-16 will pass
164   // through without error.
165   base::FilePath::CharType kBadName[] = {0xd801, 0xdc37, 0xdc17, 0};
166 #else
167   // Invalid UTF-8
168   base::FilePath::CharType kBadName[] = {'\xe3', '\x81', '\x81',
169                                          '\x81', '\x82', '\0'};
170 #endif
171   base::FilePath bad_filename(kBadName);
172   ASSERT_FALSE(bad_filename.empty());
173   // The only thing we are testing is that if the source filename was non-empty,
174   // the resulting filename is also not empty. Invalid encoded filenames can
175   // cause conversions to fail. Such failures shouldn't cause the resulting
176   // filename to disappear.
177   EXPECT_FALSE(FileSelectHelper::GetSanitizedFileName(bad_filename).empty());
178 }
179
180 TEST_F(FileSelectHelperTest, LastSelectedDirectory) {
181   content::BrowserTaskEnvironment task_environment;
182   TestingProfile profile;
183   scoped_refptr<FileSelectHelper> file_select_helper =
184       new FileSelectHelper(&profile);
185
186   const int index = 0;
187   void* params = nullptr;
188
189   const base::FilePath dir_path_1 = data_dir_.AppendASCII("dir1");
190   const base::FilePath dir_path_2 = data_dir_.AppendASCII("dir2");
191   const base::FilePath file_path_1 = dir_path_1.AppendASCII("file1.txt");
192   const base::FilePath file_path_2 = dir_path_1.AppendASCII("file2.txt");
193   const base::FilePath file_path_3 = dir_path_2.AppendASCII("file3.txt");
194   std::vector<base::FilePath> files;  // Both in dir1.
195   files.push_back(file_path_1);
196   files.push_back(file_path_2);
197   std::vector<base::FilePath> dirs;
198   dirs.push_back(dir_path_1);
199   dirs.push_back(dir_path_2);
200
201   // Modes where the parent of the selection is remembered.
202   const std::vector<FileChooserParams::Mode> modes = {
203       FileChooserParams::Mode::kOpen, FileChooserParams::Mode::kOpenMultiple,
204       FileChooserParams::Mode::kSave,
205   };
206
207   for (const auto& mode : modes) {
208     file_select_helper->dialog_mode_ = mode;
209
210     file_select_helper->AddRef();  // Normally called by RunFileChooser().
211     file_select_helper->FileSelected(file_path_1, index, params);
212     EXPECT_EQ(dir_path_1, profile.last_selected_directory());
213
214     file_select_helper->AddRef();  // Normally called by RunFileChooser().
215     file_select_helper->FileSelected(file_path_2, index, params);
216     EXPECT_EQ(dir_path_1, profile.last_selected_directory());
217
218     file_select_helper->AddRef();  // Normally called by RunFileChooser().
219     file_select_helper->FileSelected(file_path_3, index, params);
220     EXPECT_EQ(dir_path_2, profile.last_selected_directory());
221
222     file_select_helper->AddRef();  // Normally called by RunFileChooser().
223     file_select_helper->MultiFilesSelected(files, params);
224     EXPECT_EQ(dir_path_1, profile.last_selected_directory());
225   }
226
227   // Type where the selected folder itself is remembered.
228   file_select_helper->dialog_mode_ = FileChooserParams::Mode::kUploadFolder;
229
230   file_select_helper->AddRef();  // Normally called by RunFileChooser().
231   file_select_helper->FileSelected(dir_path_1, index, params);
232   EXPECT_EQ(dir_path_1, profile.last_selected_directory());
233
234   file_select_helper->AddRef();  // Normally called by RunFileChooser().
235   file_select_helper->FileSelected(dir_path_2, index, params);
236   EXPECT_EQ(dir_path_2, profile.last_selected_directory());
237
238   file_select_helper->AddRef();  // Normally called by RunFileChooser().
239   file_select_helper->MultiFilesSelected(dirs, params);
240   EXPECT_EQ(dir_path_1, profile.last_selected_directory());
241 }
242
243 // The following tests depend on the enterprise cloud content analysis feature
244 // set.
245 #if BUILDFLAG(ENTERPRISE_CLOUD_CONTENT_ANALYSIS)
246
247 TEST_F(FileSelectHelperTest, ContentAnalysisCompletionCallback_NoFiles) {
248   content::BrowserTaskEnvironment task_environment;
249   TestingProfile profile;
250   scoped_refptr<FileSelectHelper> file_select_helper =
251       new FileSelectHelper(&profile);
252
253   std::vector<blink::mojom::FileChooserFileInfoPtr> files;
254   auto listener = base::MakeRefCounted<TestFileSelectListener>(&files);
255   file_select_helper->SetFileSelectListenerForTesting(std::move(listener));
256   file_select_helper->DontAbortOnMissingWebContentsForTesting();
257
258   std::vector<blink::mojom::FileChooserFileInfoPtr> orig_files;
259   enterprise_connectors::ContentAnalysisDelegate::Data data;
260   enterprise_connectors::ContentAnalysisDelegate::Result result;
261   file_select_helper->AddRef();  // Normally called by RunFileChooser().
262   file_select_helper->ContentAnalysisCompletionCallback(std::move(orig_files),
263                                                         data, result);
264
265   EXPECT_EQ(0u, files.size());
266 }
267
268 TEST_F(FileSelectHelperTest, ContentAnalysisCompletionCallback_OneOKFile) {
269   content::BrowserTaskEnvironment task_environment;
270   TestingProfile profile;
271   scoped_refptr<FileSelectHelper> file_select_helper =
272       new FileSelectHelper(&profile);
273
274   std::vector<blink::mojom::FileChooserFileInfoPtr> files;
275   auto listener = base::MakeRefCounted<TestFileSelectListener>(&files);
276   file_select_helper->SetFileSelectListenerForTesting(std::move(listener));
277   file_select_helper->DontAbortOnMissingWebContentsForTesting();
278
279   std::vector<blink::mojom::FileChooserFileInfoPtr> orig_files;
280   enterprise_connectors::ContentAnalysisDelegate::Data data;
281   enterprise_connectors::ContentAnalysisDelegate::Result result;
282   PrepareContentAnalysisCompletionCallbackArgs(
283       {data_dir_.AppendASCII("foo.doc")}, {true}, &orig_files, &data, &result);
284
285   file_select_helper->AddRef();  // Normally called by RunFileChooser().
286   file_select_helper->ContentAnalysisCompletionCallback(std::move(orig_files),
287                                                         data, result);
288
289   EXPECT_EQ(1u, files.size());
290 }
291
292 TEST_F(FileSelectHelperTest, ContentAnalysisCompletionCallback_TwoOKFiles) {
293   content::BrowserTaskEnvironment task_environment;
294   TestingProfile profile;
295   scoped_refptr<FileSelectHelper> file_select_helper =
296       new FileSelectHelper(&profile);
297
298   std::vector<blink::mojom::FileChooserFileInfoPtr> files;
299   auto listener = base::MakeRefCounted<TestFileSelectListener>(&files);
300   file_select_helper->SetFileSelectListenerForTesting(std::move(listener));
301   file_select_helper->DontAbortOnMissingWebContentsForTesting();
302
303   std::vector<blink::mojom::FileChooserFileInfoPtr> orig_files;
304   enterprise_connectors::ContentAnalysisDelegate::Data data;
305   enterprise_connectors::ContentAnalysisDelegate::Result result;
306   PrepareContentAnalysisCompletionCallbackArgs(
307       {data_dir_.AppendASCII("foo.doc"), data_dir_.AppendASCII("bar.doc")},
308       {true, true}, &orig_files, &data, &result);
309
310   file_select_helper->AddRef();  // Normally called by RunFileChooser().
311   file_select_helper->ContentAnalysisCompletionCallback(std::move(orig_files),
312                                                         data, result);
313
314   EXPECT_EQ(2u, files.size());
315 }
316
317 TEST_F(FileSelectHelperTest, ContentAnalysisCompletionCallback_TwoBadFiles) {
318   content::BrowserTaskEnvironment task_environment;
319   TestingProfile profile;
320   scoped_refptr<FileSelectHelper> file_select_helper =
321       new FileSelectHelper(&profile);
322
323   std::vector<blink::mojom::FileChooserFileInfoPtr> files;
324   auto listener = base::MakeRefCounted<TestFileSelectListener>(&files);
325   file_select_helper->SetFileSelectListenerForTesting(std::move(listener));
326   file_select_helper->DontAbortOnMissingWebContentsForTesting();
327
328   std::vector<blink::mojom::FileChooserFileInfoPtr> orig_files;
329   enterprise_connectors::ContentAnalysisDelegate::Data data;
330   enterprise_connectors::ContentAnalysisDelegate::Result result;
331   PrepareContentAnalysisCompletionCallbackArgs(
332       {data_dir_.AppendASCII("foo.doc"), data_dir_.AppendASCII("bar.doc")},
333       {false, false}, &orig_files, &data, &result);
334
335   file_select_helper->AddRef();  // Normally called by RunFileChooser().
336   file_select_helper->ContentAnalysisCompletionCallback(std::move(orig_files),
337                                                         data, result);
338
339   EXPECT_EQ(0u, files.size());
340 }
341
342 TEST_F(FileSelectHelperTest, ContentAnalysisCompletionCallback_OKBadFiles) {
343   content::BrowserTaskEnvironment task_environment;
344   TestingProfile profile;
345   scoped_refptr<FileSelectHelper> file_select_helper =
346       new FileSelectHelper(&profile);
347
348   std::vector<blink::mojom::FileChooserFileInfoPtr> files;
349   auto listener = base::MakeRefCounted<TestFileSelectListener>(&files);
350   file_select_helper->SetFileSelectListenerForTesting(std::move(listener));
351   file_select_helper->DontAbortOnMissingWebContentsForTesting();
352
353   std::vector<blink::mojom::FileChooserFileInfoPtr> orig_files;
354   enterprise_connectors::ContentAnalysisDelegate::Data data;
355   enterprise_connectors::ContentAnalysisDelegate::Result result;
356   PrepareContentAnalysisCompletionCallbackArgs(
357       {data_dir_.AppendASCII("foo.doc"), data_dir_.AppendASCII("bar.doc")},
358       {false, true}, &orig_files, &data, &result);
359
360   file_select_helper->AddRef();  // Normally called by RunFileChooser().
361   file_select_helper->ContentAnalysisCompletionCallback(std::move(orig_files),
362                                                         data, result);
363
364   ASSERT_EQ(1u, files.size());
365   EXPECT_EQ(data_dir_.AppendASCII("bar.doc"),
366             files[0]->get_native_file()->file_path);
367 }
368
369 TEST_F(FileSelectHelperTest,
370        ContentAnalysisCompletionCallback_SystemFilesSkipped) {
371   content::BrowserTaskEnvironment task_environment;
372   TestingProfile profile;
373   scoped_refptr<FileSelectHelper> file_select_helper =
374       new FileSelectHelper(&profile);
375
376   std::vector<blink::mojom::FileChooserFileInfoPtr> files;
377   auto listener = base::MakeRefCounted<TestFileSelectListener>(&files);
378   file_select_helper->SetFileSelectListenerForTesting(std::move(listener));
379   file_select_helper->DontAbortOnMissingWebContentsForTesting();
380
381   std::vector<blink::mojom::FileChooserFileInfoPtr> orig_files;
382   enterprise_connectors::ContentAnalysisDelegate::Data data;
383   enterprise_connectors::ContentAnalysisDelegate::Result result;
384
385   for (int i = 0; i < 5; ++i) {
386     orig_files.push_back(blink::mojom::FileChooserFileInfo::NewFileSystem(
387         blink::mojom::FileSystemFileInfo::New()));
388   }
389
390   file_select_helper->AddRef();  // Normally called by RunFileChooser().
391   file_select_helper->ContentAnalysisCompletionCallback(std::move(orig_files),
392                                                         data, result);
393
394   ASSERT_EQ(5u, files.size());
395   for (int i = 0; i < 5; ++i)
396     EXPECT_TRUE(files[i]->is_file_system());
397 }
398
399 TEST_F(FileSelectHelperTest,
400        ContentAnalysisCompletionCallback_SystemOKBadFiles) {
401   content::BrowserTaskEnvironment task_environment;
402   TestingProfile profile;
403   scoped_refptr<FileSelectHelper> file_select_helper =
404       new FileSelectHelper(&profile);
405
406   std::vector<blink::mojom::FileChooserFileInfoPtr> files;
407   auto listener = base::MakeRefCounted<TestFileSelectListener>(&files);
408   file_select_helper->SetFileSelectListenerForTesting(std::move(listener));
409   file_select_helper->DontAbortOnMissingWebContentsForTesting();
410
411   std::vector<blink::mojom::FileChooserFileInfoPtr> orig_files;
412   enterprise_connectors::ContentAnalysisDelegate::Data data;
413   enterprise_connectors::ContentAnalysisDelegate::Result result;
414
415   // Add 1 non-native file at the start and end of the files list, which should
416   // be skipped.
417   orig_files.push_back(blink::mojom::FileChooserFileInfo::NewFileSystem(
418       blink::mojom::FileSystemFileInfo::New()));
419   PrepareContentAnalysisCompletionCallbackArgs(
420       {data_dir_.AppendASCII("foo.doc"), data_dir_.AppendASCII("bar.doc")},
421       {false, true}, &orig_files, &data, &result);
422   orig_files.push_back(blink::mojom::FileChooserFileInfo::NewFileSystem(
423       blink::mojom::FileSystemFileInfo::New()));
424
425   file_select_helper->AddRef();  // Normally called by RunFileChooser().
426   file_select_helper->ContentAnalysisCompletionCallback(std::move(orig_files),
427                                                         data, result);
428
429   ASSERT_EQ(3u, files.size());
430   EXPECT_TRUE(files[0]->is_file_system());
431   EXPECT_TRUE(files[1]->is_native_file());
432   EXPECT_EQ(data_dir_.AppendASCII("bar.doc"),
433             files[1]->get_native_file()->file_path);
434   EXPECT_TRUE(files[2]->is_file_system());
435 }
436
437 TEST_F(FileSelectHelperTest,
438        ContentAnalysisCompletionCallback_FolderUpload_OK) {
439   content::BrowserTaskEnvironment task_environment;
440   TestingProfile profile;
441   scoped_refptr<FileSelectHelper> file_select_helper =
442       new FileSelectHelper(&profile);
443
444   std::vector<blink::mojom::FileChooserFileInfoPtr> files;
445   auto listener = base::MakeRefCounted<TestFileSelectListener>(&files);
446   file_select_helper->SetFileSelectListenerForTesting(std::move(listener));
447   file_select_helper->DontAbortOnMissingWebContentsForTesting();
448
449   std::vector<blink::mojom::FileChooserFileInfoPtr> orig_files;
450   enterprise_connectors::ContentAnalysisDelegate::Data data;
451   enterprise_connectors::ContentAnalysisDelegate::Result result;
452
453   // Set the dialog type to folder upload to test folder handling logic.
454   file_select_helper->dialog_type_ = ui::SelectFileDialog::SELECT_UPLOAD_FOLDER;
455   PrepareContentAnalysisCompletionCallbackArgs(
456       {data_dir_.AppendASCII("foo.doc"), data_dir_.AppendASCII("bar.doc")},
457       {true, true}, &orig_files, &data, &result);
458
459   // Calling the content analysis completion callback would normally
460   // release `file_select_helper`, so we add a reference and validate that
461   // it goes down to 1 after the call.
462   file_select_helper->AddRef();
463   EXPECT_FALSE(file_select_helper->HasOneRef());
464   file_select_helper->ContentAnalysisCompletionCallback(std::move(orig_files),
465                                                         data, result);
466
467   EXPECT_TRUE(file_select_helper->HasOneRef());
468   EXPECT_EQ(2u, files.size());
469 }
470
471 TEST_F(FileSelectHelperTest,
472        ContentAnalysisCompletionCallback_FolderUpload_Bad) {
473   content::BrowserTaskEnvironment task_environment;
474   TestingProfile profile;
475   scoped_refptr<FileSelectHelper> file_select_helper =
476       new FileSelectHelper(&profile);
477
478   std::vector<blink::mojom::FileChooserFileInfoPtr> files;
479   auto listener = base::MakeRefCounted<TestFileSelectListener>(&files);
480   file_select_helper->SetFileSelectListenerForTesting(std::move(listener));
481   file_select_helper->DontAbortOnMissingWebContentsForTesting();
482
483   std::vector<blink::mojom::FileChooserFileInfoPtr> orig_files;
484   enterprise_connectors::ContentAnalysisDelegate::Data data;
485   enterprise_connectors::ContentAnalysisDelegate::Result result;
486
487   // Set the dialog type to folder upload to test folder handling logic.
488   file_select_helper->dialog_type_ = ui::SelectFileDialog::SELECT_UPLOAD_FOLDER;
489   PrepareContentAnalysisCompletionCallbackArgs(
490       {data_dir_.AppendASCII("foo.doc"), data_dir_.AppendASCII("bar.doc")},
491       {false, false}, &orig_files, &data, &result);
492
493   // Calling the content analysis completion callback would normally
494   // release `file_select_helper`, so we add a reference and validate that
495   // it goes down to 1 after the call.
496   file_select_helper->AddRef();
497   EXPECT_FALSE(file_select_helper->HasOneRef());
498   file_select_helper->ContentAnalysisCompletionCallback(std::move(orig_files),
499                                                         data, result);
500   EXPECT_TRUE(file_select_helper->HasOneRef());
501   EXPECT_EQ(0u, files.size());
502 }
503
504 TEST_F(FileSelectHelperTest,
505        ContentAnalysisCompletionCallback_FolderUpload_OKBad) {
506   content::BrowserTaskEnvironment task_environment;
507   TestingProfile profile;
508   scoped_refptr<FileSelectHelper> file_select_helper =
509       new FileSelectHelper(&profile);
510
511   std::vector<blink::mojom::FileChooserFileInfoPtr> files;
512   auto listener = base::MakeRefCounted<TestFileSelectListener>(&files);
513   file_select_helper->SetFileSelectListenerForTesting(std::move(listener));
514   file_select_helper->DontAbortOnMissingWebContentsForTesting();
515
516   std::vector<blink::mojom::FileChooserFileInfoPtr> orig_files;
517   enterprise_connectors::ContentAnalysisDelegate::Data data;
518   enterprise_connectors::ContentAnalysisDelegate::Result result;
519
520   // Set the dialog type to folder upload to test folder handling logic.
521   file_select_helper->dialog_type_ = ui::SelectFileDialog::SELECT_UPLOAD_FOLDER;
522   PrepareContentAnalysisCompletionCallbackArgs(
523       {data_dir_.AppendASCII("foo.doc"), data_dir_.AppendASCII("bar.doc")},
524       {true, false}, &orig_files, &data, &result);
525
526   // Calling the content analysis completion callback would normally
527   // release `file_select_helper`, so we add a reference and validate that
528   // it goes down to 1 after the call.
529   file_select_helper->AddRef();
530   EXPECT_FALSE(file_select_helper->HasOneRef());
531   file_select_helper->ContentAnalysisCompletionCallback(std::move(orig_files),
532                                                         data, result);
533
534   EXPECT_TRUE(file_select_helper->HasOneRef());
535   // Files should be cleared.
536   EXPECT_EQ(0u, files.size());
537 }
538
539 TEST_F(FileSelectHelperTest, GetFileTypesFromAcceptType) {
540   content::BrowserTaskEnvironment task_environment;
541   TestingProfile profile;
542   scoped_refptr<FileSelectHelper> file_select_helper =
543       new FileSelectHelper(&profile);
544
545   std::vector<std::u16string> accept_types{
546       // normal file extension
547       u".mp4",
548       // file extension with some chinese
549       u".斤拷锟",
550       // file extension with fire emoji
551       u".🔥",
552       // mime type
553       u"image/png",
554       // non-ascii mime type which should be ignored
555       u"text/斤拷锟"};
556
557   std::unique_ptr<ui::SelectFileDialog::FileTypeInfo> file_type_info =
558       file_select_helper->GetFileTypesFromAcceptType(accept_types);
559
560   std::vector<std::vector<base::FilePath::StringType>> expected_extensions{
561       std::vector<base::FilePath::StringType>{
562 #if BUILDFLAG(IS_WIN)
563           L"mp4", L"斤拷锟", L"🔥", L"png"}};
564 #else
565           "mp4", "斤拷锟", "🔥", "png"}};
566 #endif
567   ASSERT_EQ(expected_extensions, file_type_info->extensions);
568 }
569
570 // This test depends on platform-specific mappings from mime types to file
571 // extensions in PlatformMimeUtil. It would seem that Linux does not offer a way
572 // to get extensions, and our Windows implementation still needs to be updated.
573 #if BUILDFLAG(IS_MAC)
574 TEST_F(FileSelectHelperTest, MultipleFileExtensionsForMime) {
575   content::BrowserTaskEnvironment task_environment;
576   TestingProfile profile;
577   scoped_refptr<FileSelectHelper> file_select_helper =
578       new FileSelectHelper(&profile);
579
580   std::vector<std::u16string> accept_types{u"application/vnd.ms-powerpoint"};
581   std::unique_ptr<ui::SelectFileDialog::FileTypeInfo> file_type_info =
582       file_select_helper->GetFileTypesFromAcceptType(accept_types);
583
584   std::vector<base::FilePath::StringType> expected_extensions {
585 #if BUILDFLAG(IS_WIN)
586     L"ppt", L"pot", L"pps"
587   };
588 #else
589     "ppt", "pot", "pps"
590   };
591 #endif
592   std::sort(expected_extensions.begin(), expected_extensions.end());
593
594   ASSERT_EQ(file_type_info->extensions.size(), 1u);
595   std::vector<base::FilePath::StringType> actual_extensions =
596       file_type_info->extensions[0];
597   std::sort(actual_extensions.begin(), actual_extensions.end());
598
599   EXPECT_EQ(expected_extensions, actual_extensions);
600 }
601 #endif
602
603 #endif  // BUILDFLAG(ENTERPRISE_CLOUD_CONTENT_ANALYSIS)