1 // Copyright 2020 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/ash/holding_space/holding_space_client_impl.h"
6 
7 #include <string>
8 
9 #include "ash/public/cpp/ash_features.h"
10 #include "ash/public/cpp/holding_space/holding_space_controller.h"
11 #include "ash/public/cpp/holding_space/holding_space_image.h"
12 #include "ash/public/cpp/holding_space/holding_space_item.h"
13 #include "ash/public/cpp/holding_space/holding_space_model.h"
14 #include "base/callback_helpers.h"
15 #include "base/files/file_path.h"
16 #include "base/files/file_util.h"
17 #include "base/path_service.h"
18 #include "base/run_loop.h"
19 #include "base/test/bind.h"
20 #include "base/unguessable_token.h"
21 #include "chrome/browser/chromeos/file_manager/path_util.h"
22 #include "chrome/browser/extensions/component_loader.h"
23 #include "chrome/browser/profiles/profile_manager.h"
24 #include "chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.h"
25 #include "chrome/browser/ui/browser.h"
26 #include "chrome/test/base/in_process_browser_test.h"
27 #include "content/public/test/browser_test.h"
28 #include "storage/browser/file_system/external_mount_points.h"
29 #include "ui/gfx/image/image_skia.h"
30 
31 namespace ash {
32 
33 namespace {
34 
35 // File paths for test data.
36 constexpr char kTestDataDir[] = "chrome/test/data/chromeos/file_manager/";
37 constexpr char kImageFilePath[] = "image.png";
38 constexpr char kTextFilePath[] = "text.txt";
39 
40 // Helpers ---------------------------------------------------------------------
41 
42 // Copies the file for the `relative_path` in the test data directory to
43 // downloads directory, and returns the path to the copy.
TestFile(Profile * profile,const std::string & relative_path)44 base::FilePath TestFile(Profile* profile, const std::string& relative_path) {
45   base::FilePath source_root;
46   EXPECT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &source_root));
47   const base::FilePath source_file =
48       source_root.AppendASCII(kTestDataDir).AppendASCII(relative_path);
49 
50   base::FilePath target_dir;
51   if (!storage::ExternalMountPoints::GetSystemInstance()->GetRegisteredPath(
52           file_manager::util::GetDownloadsMountPointName(profile),
53           &target_dir)) {
54     ADD_FAILURE() << "Failed to get downloads mount point";
55     return base::FilePath();
56   }
57 
58   const base::FilePath target_path = target_dir.Append(source_file.BaseName());
59   base::ScopedAllowBlockingForTesting allow_blocking;
60   if (!base::CopyFile(source_file, target_path)) {
61     ADD_FAILURE() << "Failed to create file.";
62     return base::FilePath();
63   }
64 
65   return target_path;
66 }
67 
68 }  // namespace
69 
70 // Tests -----------------------------------------------------------------------
71 
72 using HoldingSpaceClientImplTest = HoldingSpaceBrowserTestBase;
73 
74 // Verifies that `HoldingSpaceClient::CopyImageToClipboard()` works as intended
75 // when attempting to copy both image backed and non-image backed holding space
76 // items.
IN_PROC_BROWSER_TEST_F(HoldingSpaceClientImplTest,CopyImageToClipboard)77 IN_PROC_BROWSER_TEST_F(HoldingSpaceClientImplTest, CopyImageToClipboard) {
78   ASSERT_TRUE(HoldingSpaceController::Get());
79 
80   auto* holding_space_client = HoldingSpaceController::Get()->client();
81   ASSERT_TRUE(holding_space_client);
82 
83   {
84     // Create a holding space item backed by a non-image file.
85     auto* holding_space_item =
86         AddItem(GetProfile(), HoldingSpaceItem::Type::kDownload,
87                 TestFile(GetProfile(), kTextFilePath));
88 
89     // We expect `HoldingSpaceClient::CopyImageToClipboard()` to fail when the
90     // backing file for `holding_space_item` is not an image file.
91     base::RunLoop run_loop;
92     holding_space_client->CopyImageToClipboard(
93         *holding_space_item,
94         base::BindLambdaForTesting([&run_loop](bool success) {
95           EXPECT_FALSE(success);
96           run_loop.Quit();
97         }));
98     run_loop.Run();
99   }
100 
101   {
102     // Create a holding space item backed by an image file.
103     auto* holding_space_item =
104         AddItem(GetProfile(), HoldingSpaceItem::Type::kDownload,
105                 TestFile(GetProfile(), kImageFilePath));
106 
107     // We expect `HoldingSpaceClient::CopyImageToClipboard()` to succeed when
108     // the backing file for `holding_space_item` is an image file.
109     base::RunLoop run_loop;
110     holding_space_client->CopyImageToClipboard(
111         *holding_space_item,
112         base::BindLambdaForTesting([&run_loop](bool success) {
113           EXPECT_TRUE(success);
114           run_loop.Quit();
115         }));
116     run_loop.Run();
117   }
118 }
119 
120 // Verifies that `HoldingSpaceClient::OpenDownloads()` works as intended.
121 // TODO(crbug.com/1139299): Flaky.
IN_PROC_BROWSER_TEST_F(HoldingSpaceClientImplTest,DISABLED_OpenDownloads)122 IN_PROC_BROWSER_TEST_F(HoldingSpaceClientImplTest, DISABLED_OpenDownloads) {
123   ASSERT_TRUE(HoldingSpaceController::Get());
124 
125   auto* holding_space_client = HoldingSpaceController::Get()->client();
126   ASSERT_TRUE(holding_space_client);
127 
128   // We expect `HoldingSpaceClient::OpenDownloads()` to succeed.
129   base::RunLoop run_loop;
130   holding_space_client->OpenDownloads(
131       base::BindLambdaForTesting([&run_loop](bool success) {
132         EXPECT_TRUE(success);
133         run_loop.Quit();
134       }));
135   run_loop.Run();
136 }
137 
138 // Verifies that `HoldingSpaceClient::OpenItems()` works as intended when
139 // attempting to open holding space items backed by both non-existing and
140 // existing files.
IN_PROC_BROWSER_TEST_F(HoldingSpaceClientImplTest,OpenItems)141 IN_PROC_BROWSER_TEST_F(HoldingSpaceClientImplTest, OpenItems) {
142   ASSERT_TRUE(HoldingSpaceController::Get());
143 
144   auto* holding_space_client = HoldingSpaceController::Get()->client();
145   ASSERT_TRUE(holding_space_client);
146 
147   {
148     // Create a holding space item backed by a non-existing file.
149     auto holding_space_item = HoldingSpaceItem::CreateFileBackedItem(
150         HoldingSpaceItem::Type::kDownload, base::FilePath("foo"),
151         GURL("filesystem:fake"),
152         std::make_unique<HoldingSpaceImage>(
153             /*placeholder=*/gfx::ImageSkia(),
154             /*async_bitmap_resolver=*/base::DoNothing()));
155 
156     // We expect `HoldingSpaceClient::OpenItems()` to fail when the backing file
157     // for `holding_space_item` does not exist.
158     base::RunLoop run_loop;
159     holding_space_client->OpenItems(
160         {holding_space_item.get()},
161         base::BindLambdaForTesting([&run_loop](bool success) {
162           EXPECT_FALSE(success);
163           run_loop.Quit();
164         }));
165     run_loop.Run();
166   }
167 
168   {
169     // Create a holding space item backed by a newly created txt file.
170     HoldingSpaceItem* holding_space_item = AddPinnedFile();
171 
172     // We expect `HoldingSpaceClient::OpenItems()` to succeed when the backing
173     // file for `holding_space_item` exists.
174     base::RunLoop run_loop;
175     holding_space_client->OpenItems(
176         {holding_space_item},
177         base::BindLambdaForTesting([&run_loop](bool success) {
178           EXPECT_TRUE(success);
179           run_loop.Quit();
180         }));
181     run_loop.Run();
182   }
183 }
184 
185 // Verifies that `HoldingSpaceClient::ShowItemInFolder()` works as intended when
186 // attempting to open holding space items backed by both non-existing and
187 // existing files.
188 // Flaky on linux-chromeos-dbg (https://crbug.com/1130958)
189 #ifdef NDEBUG
190 #define MAYBE_ShowItemInFolder ShowItemInFolder
191 #else
192 #define MAYBE_ShowItemInFolder DISABLED_ShowItemInFolder
193 #endif
IN_PROC_BROWSER_TEST_F(HoldingSpaceClientImplTest,MAYBE_ShowItemInFolder)194 IN_PROC_BROWSER_TEST_F(HoldingSpaceClientImplTest, MAYBE_ShowItemInFolder) {
195   ASSERT_TRUE(HoldingSpaceController::Get());
196 
197   auto* holding_space_client = HoldingSpaceController::Get()->client();
198   ASSERT_TRUE(holding_space_client);
199 
200   {
201     // Create a holding space item backed by a non-existing file.
202     auto holding_space_item = HoldingSpaceItem::CreateFileBackedItem(
203         HoldingSpaceItem::Type::kDownload, base::FilePath("foo"),
204         GURL("filesystem:fake"),
205         std::make_unique<HoldingSpaceImage>(
206             /*placeholder=*/gfx::ImageSkia(),
207             /*async_bitmap_resolver=*/base::DoNothing()));
208 
209     // We expect `HoldingSpaceClient::ShowItemInFolder()` to fail when the
210     // backing file for `holding_space_item` does not exist.
211     base::RunLoop run_loop;
212     holding_space_client->ShowItemInFolder(
213         *holding_space_item,
214         base::BindLambdaForTesting([&run_loop](bool success) {
215           EXPECT_FALSE(success);
216           run_loop.Quit();
217         }));
218     run_loop.Run();
219   }
220 
221   {
222     // Create a holding space item backed by a newly created txt file.
223     HoldingSpaceItem* holding_space_item = AddPinnedFile();
224 
225     // We expect `HoldingSpaceClient::ShowItemInFolder()` to succeed when the
226     // backing file for `holding_space_item` exists.
227     base::RunLoop run_loop;
228     holding_space_client->ShowItemInFolder(
229         *holding_space_item,
230         base::BindLambdaForTesting([&run_loop](bool success) {
231           EXPECT_TRUE(success);
232           run_loop.Quit();
233         }));
234     run_loop.Run();
235   }
236 }
237 
238 // Verifies that `HoldingSpaceClient::PinItems()` works as intended.
IN_PROC_BROWSER_TEST_F(HoldingSpaceClientImplTest,PinItems)239 IN_PROC_BROWSER_TEST_F(HoldingSpaceClientImplTest, PinItems) {
240   ASSERT_TRUE(HoldingSpaceController::Get());
241 
242   auto* holding_space_client = HoldingSpaceController::Get()->client();
243   auto* holding_space_model = HoldingSpaceController::Get()->model();
244   ASSERT_TRUE(holding_space_client && holding_space_model);
245 
246   // Create a download holding space item.
247   HoldingSpaceItem* download_item = AddDownloadFile();
248   ASSERT_EQ(1u, holding_space_model->items().size());
249 
250   // Attempt to pin the download holding space item.
251   holding_space_client->PinItems({download_item});
252   ASSERT_EQ(2u, holding_space_model->items().size());
253 
254   // The pinned holding space item should have type `kPinnedFile` but share the
255   // same text and file path as the original download holding space item.
256   HoldingSpaceItem* pinned_file_item = holding_space_model->items()[1].get();
257   EXPECT_EQ(pinned_file_item->type(), HoldingSpaceItem::Type::kPinnedFile);
258   EXPECT_EQ(download_item->text(), pinned_file_item->text());
259   EXPECT_EQ(download_item->file_path(), pinned_file_item->file_path());
260 }
261 
262 // Verifies that `HoldingSpaceClient::UnpinItems()` works as intended.
IN_PROC_BROWSER_TEST_F(HoldingSpaceClientImplTest,UnpinItems)263 IN_PROC_BROWSER_TEST_F(HoldingSpaceClientImplTest, UnpinItems) {
264   ASSERT_TRUE(HoldingSpaceController::Get());
265 
266   auto* holding_space_client = HoldingSpaceController::Get()->client();
267   auto* holding_space_model = HoldingSpaceController::Get()->model();
268   ASSERT_TRUE(holding_space_client && holding_space_model);
269 
270   // Create a pinned file holding space item.
271   HoldingSpaceItem* pinned_file_item = AddPinnedFile();
272   ASSERT_EQ(1u, holding_space_model->items().size());
273 
274   // Attempt to unpin the pinned file holding space item.
275   holding_space_client->UnpinItems({pinned_file_item});
276   ASSERT_EQ(0u, holding_space_model->items().size());
277 }
278 
279 }  // namespace ash
280