1 // Copyright 2015 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.
5 #include "chrome/browser/platform_util.h"
8 #include "base/callback.h"
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/run_loop.h"
13 #include "chrome/browser/platform_util_internal.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 #if defined(OS_CHROMEOS)
17 #include "base/json/json_string_value_serializer.h"
18 #include "base/values.h"
19 #include "chrome/browser/chrome_content_browser_client.h"
20 #include "chrome/browser/chromeos/file_manager/app_id.h"
21 #include "chrome/browser/chromeos/fileapi/file_system_backend.h"
22 #include "chrome/browser/extensions/extension_special_storage_policy.h"
23 #include "chrome/test/base/browser_with_test_window_test.h"
24 #include "content/public/browser/browser_context.h"
25 #include "content/public/common/content_client.h"
26 #include "content/public/test/mock_special_storage_policy.h"
27 #include "extensions/browser/extension_registry.h"
28 #include "extensions/common/extension.h"
29 #include "storage/browser/fileapi/external_mount_points.h"
30 #include "storage/common/fileapi/file_system_types.h"
32 #include "content/public/test/test_browser_thread_bundle.h"
35 namespace platform_util
{
39 #if defined(OS_CHROMEOS)
41 // ChromeContentBrowserClient subclass that sets up a custom file system backend
42 // that allows the test to grant file access to the file manager extension ID
43 // without having to install the extension.
44 class PlatformUtilTestContentBrowserClient
45 : public chrome::ChromeContentBrowserClient
{
47 void GetAdditionalFileSystemBackends(
48 content::BrowserContext
* browser_context
,
49 const base::FilePath
& storage_partition_path
,
50 ScopedVector
<storage::FileSystemBackend
>* additional_backends
) override
{
51 storage::ExternalMountPoints
* external_mount_points
=
52 content::BrowserContext::GetMountPoints(browser_context
);
53 scoped_refptr
<content::MockSpecialStoragePolicy
> special_storage_policy
=
54 new content::MockSpecialStoragePolicy();
56 // New FileSystemBackend that uses our MockSpecialStoragePolicy.
57 chromeos::FileSystemBackend
* backend
= new chromeos::FileSystemBackend(
58 nullptr, nullptr, nullptr, special_storage_policy
,
59 external_mount_points
,
60 storage::ExternalMountPoints::GetSystemInstance());
61 additional_backends
->push_back(backend
);
63 // The only change we need to make is to add kFileManagerAppId as a file
65 special_storage_policy
->AddFileHandler(file_manager::kFileManagerAppId
);
69 // Base test fixture class to be used on Chrome OS.
70 class PlatformUtilTestBase
: public BrowserWithTestWindowTest
{
72 void SetUpPlatformFixture(const base::FilePath
& test_directory
) {
73 content_browser_client_
.reset(new PlatformUtilTestContentBrowserClient());
74 old_content_browser_client_
=
75 content::SetBrowserClientForTesting(content_browser_client_
.get());
77 // The test_directory needs to be mounted for it to be accessible.
78 content::BrowserContext::GetMountPoints(GetProfile())
79 ->RegisterFileSystem("test", storage::kFileSystemTypeNativeLocal
,
80 storage::FileSystemMountOption(), test_directory
);
82 // To test opening a file, we are going to register a mock extension that
83 // handles .txt files. The extension doesn't actually need to exist due to
84 // the DisableShellOperationsForTesting() call which prevents the extension
85 // from being invoked.
89 std::string json_manifest
=
91 " \"manifest_version\": 2,"
92 " \"name\": \"Test extension\","
93 " \"version\": \"0\","
94 " \"app\": { \"background\": { \"scripts\": [\"main.js\"] }},"
95 " \"file_handlers\": {"
97 " \"extensions\": [ \"txt\" ],"
98 " \"title\": \"Text\""
102 JSONStringValueDeserializer
json_string_deserializer(json_manifest
);
103 scoped_ptr
<base::Value
> manifest(
104 json_string_deserializer
.Deserialize(&error_code
, &error
));
105 base::DictionaryValue
* manifest_dictionary
;
107 manifest
->GetAsDictionary(&manifest_dictionary
);
108 ASSERT_TRUE(manifest_dictionary
);
110 scoped_refptr
<extensions::Extension
> extension
=
111 extensions::Extension::Create(
112 test_directory
.AppendASCII("invalid-extension"),
113 extensions::Manifest::INVALID_LOCATION
, *manifest_dictionary
,
114 extensions::Extension::NO_FLAGS
, &error
);
115 ASSERT_TRUE(error
.empty()) << error
;
116 extensions::ExtensionRegistry::Get(GetProfile())->AddEnabled(extension
);
119 void TearDown() override
{
120 content::ContentBrowserClient
* content_browser_client
=
121 content::SetBrowserClientForTesting(old_content_browser_client_
);
122 old_content_browser_client_
= nullptr;
123 DCHECK_EQ(static_cast<content::ContentBrowserClient
*>(
124 content_browser_client_
.get()),
125 content_browser_client
)
126 << "ContentBrowserClient changed during test.";
127 BrowserWithTestWindowTest::TearDown();
131 scoped_ptr
<content::ContentBrowserClient
> content_browser_client_
;
132 content::ContentBrowserClient
* old_content_browser_client_
= nullptr;
137 // Test fixture used by all desktop platforms other than Chrome OS.
138 class PlatformUtilTestBase
: public testing::Test
{
140 Profile
* GetProfile() { return nullptr; }
141 void SetUpPlatformFixture(const base::FilePath
&) {}
144 content::TestBrowserThreadBundle thread_bundle_
;
149 class PlatformUtilTest
: public PlatformUtilTestBase
{
151 void SetUp() override
{
152 ASSERT_NO_FATAL_FAILURE(PlatformUtilTestBase::SetUp());
154 static const char kTestFileData
[] = "Cow says moo!";
155 const int kTestFileDataLength
= arraysize(kTestFileData
) - 1;
157 // This prevents platfrom_util from invoking any shell or external APIs
158 // during tests. Doing so may result in external applications being launched
159 // and intefering with tests.
160 internal::DisableShellOperationsForTesting();
162 ASSERT_TRUE(directory_
.CreateUniqueTempDir());
165 existing_file_
= directory_
.path().AppendASCII("test_file.txt");
168 base::WriteFile(existing_file_
, kTestFileData
, kTestFileDataLength
));
171 existing_folder_
= directory_
.path().AppendASCII("test_folder");
172 ASSERT_TRUE(base::CreateDirectory(existing_folder_
));
174 // A non-existent path.
175 nowhere_
= directory_
.path().AppendASCII("nowhere");
177 SetUpPlatformFixture(directory_
.path());
180 OpenOperationResult
CallOpenItem(const base::FilePath
& path
,
181 OpenItemType item_type
) {
182 base::RunLoop run_loop
;
183 OpenOperationResult result
= OPEN_SUCCEEDED
;
184 OpenOperationCallback callback
=
185 base::Bind(&OnOpenOperationDone
, run_loop
.QuitClosure(), &result
);
186 OpenItem(GetProfile(), path
, item_type
, callback
);
191 base::FilePath existing_file_
;
192 base::FilePath existing_folder_
;
193 base::FilePath nowhere_
;
196 base::ScopedTempDir directory_
;
199 scoped_ptr
<base::RunLoop
> run_loop_
;
201 static void OnOpenOperationDone(const base::Closure
& closure
,
202 OpenOperationResult
* store_result
,
203 OpenOperationResult result
) {
204 *store_result
= result
;
211 TEST_F(PlatformUtilTest
, OpenFile
) {
212 EXPECT_EQ(OPEN_SUCCEEDED
, CallOpenItem(existing_file_
, OPEN_FILE
));
213 EXPECT_EQ(OPEN_FAILED_INVALID_TYPE
,
214 CallOpenItem(existing_folder_
, OPEN_FILE
));
215 EXPECT_EQ(OPEN_FAILED_PATH_NOT_FOUND
, CallOpenItem(nowhere_
, OPEN_FILE
));
218 TEST_F(PlatformUtilTest
, OpenFolder
) {
219 EXPECT_EQ(OPEN_SUCCEEDED
, CallOpenItem(existing_folder_
, OPEN_FOLDER
));
220 EXPECT_EQ(OPEN_FAILED_INVALID_TYPE
,
221 CallOpenItem(existing_file_
, OPEN_FOLDER
));
222 EXPECT_EQ(OPEN_FAILED_PATH_NOT_FOUND
, CallOpenItem(nowhere_
, OPEN_FOLDER
));
225 #if defined(OS_POSIX)
226 // Symbolic links are currently only supported on Posix. Windows technically
227 // supports it as well, but not on Windows XP.
228 class PlatformUtilPosixTest
: public PlatformUtilTest
{
230 void SetUp() override
{
231 ASSERT_NO_FATAL_FAILURE(PlatformUtilTest::SetUp());
233 symlink_to_file_
= directory_
.path().AppendASCII("l_file.txt");
234 ASSERT_TRUE(base::CreateSymbolicLink(existing_file_
, symlink_to_file_
));
235 symlink_to_folder_
= directory_
.path().AppendASCII("l_folder");
236 ASSERT_TRUE(base::CreateSymbolicLink(existing_folder_
, symlink_to_folder_
));
237 symlink_to_nowhere_
= directory_
.path().AppendASCII("l_nowhere");
238 ASSERT_TRUE(base::CreateSymbolicLink(nowhere_
, symlink_to_nowhere_
));
242 base::FilePath symlink_to_file_
;
243 base::FilePath symlink_to_folder_
;
244 base::FilePath symlink_to_nowhere_
;
248 #if defined(OS_CHROMEOS)
249 // ChromeOS doesn't follow symbolic links in sandboxed filesystems. So all the
250 // symbolic link tests should return PATH_NOT_FOUND.
252 TEST_F(PlatformUtilPosixTest
, OpenFileWithPosixSymlinksChromeOS
) {
253 EXPECT_EQ(OPEN_FAILED_PATH_NOT_FOUND
,
254 CallOpenItem(symlink_to_file_
, OPEN_FILE
));
255 EXPECT_EQ(OPEN_FAILED_PATH_NOT_FOUND
,
256 CallOpenItem(symlink_to_folder_
, OPEN_FILE
));
257 EXPECT_EQ(OPEN_FAILED_PATH_NOT_FOUND
,
258 CallOpenItem(symlink_to_nowhere_
, OPEN_FILE
));
261 TEST_F(PlatformUtilPosixTest
, OpenFolderWithPosixSymlinksChromeOS
) {
262 EXPECT_EQ(OPEN_FAILED_PATH_NOT_FOUND
,
263 CallOpenItem(symlink_to_folder_
, OPEN_FOLDER
));
264 EXPECT_EQ(OPEN_FAILED_PATH_NOT_FOUND
,
265 CallOpenItem(symlink_to_file_
, OPEN_FOLDER
));
266 EXPECT_EQ(OPEN_FAILED_PATH_NOT_FOUND
,
267 CallOpenItem(symlink_to_nowhere_
, OPEN_FOLDER
));
270 TEST_F(PlatformUtilTest
, OpenFileWithUnhandledFileType
) {
271 base::FilePath unhandled_file
=
272 directory_
.path().AppendASCII("myfile.filetype");
273 ASSERT_EQ(3, base::WriteFile(unhandled_file
, "cat", 3));
274 EXPECT_EQ(OPEN_FAILED_NO_HANLDER_FOR_FILE_TYPE
,
275 CallOpenItem(unhandled_file
, OPEN_FILE
));
277 #endif // OS_CHROMEOS
279 #if defined(OS_POSIX) && !defined(OS_CHROMEOS)
280 // On all other Posix platforms, the symbolic link tests should work as
283 TEST_F(PlatformUtilPosixTest
, OpenFileWithPosixSymlinks
) {
284 EXPECT_EQ(OPEN_SUCCEEDED
, CallOpenItem(symlink_to_file_
, OPEN_FILE
));
285 EXPECT_EQ(OPEN_FAILED_INVALID_TYPE
,
286 CallOpenItem(symlink_to_folder_
, OPEN_FILE
));
287 EXPECT_EQ(OPEN_FAILED_PATH_NOT_FOUND
,
288 CallOpenItem(symlink_to_nowhere_
, OPEN_FILE
));
291 TEST_F(PlatformUtilPosixTest
, OpenFolderWithPosixSymlinks
) {
292 EXPECT_EQ(OPEN_SUCCEEDED
, CallOpenItem(symlink_to_folder_
, OPEN_FOLDER
));
293 EXPECT_EQ(OPEN_FAILED_INVALID_TYPE
,
294 CallOpenItem(symlink_to_file_
, OPEN_FOLDER
));
295 EXPECT_EQ(OPEN_FAILED_PATH_NOT_FOUND
,
296 CallOpenItem(symlink_to_nowhere_
, OPEN_FOLDER
));
298 #endif // OS_POSIX && !OS_CHROMEOS
300 } // namespace platform_util