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.
5 #include "base/path_service.h"
7 #include "base/base_paths.h"
8 #include "base/containers/contains.h"
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/logging.h"
13 #include "base/strings/string_util.h"
14 #include "base/test/gtest_util.h"
15 #include "build/build_config.h"
16 #include "testing/gtest/include/gtest/gtest-spi.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "testing/platform_test.h"
21 #include "base/win/windows_version.h"
24 #if BUILDFLAG(IS_APPLE)
25 #include "base/apple/bundle_locations.h"
32 #if BUILDFLAG(IS_ANDROID)
34 // //base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java.
35 constexpr char kExpectedChromiumTestsRoot[] =
36 "/storage/emulated/0/chromium_tests_root";
39 // Returns true if PathService::Get returns true and sets the path parameter
40 // to non-empty for the given PathService key enumeration value.
41 bool ReturnsValidPath(int key) {
43 bool result = PathService::Get(key, &path);
45 // Some paths might not exist on some platforms in which case confirming
46 // |result| is true and !path.empty() is the best we can do.
47 bool check_path_exists = true;
49 #if BUILDFLAG(IS_POSIX)
50 // If chromium has never been started on this account, the cache path may not
53 check_path_exists = false;
55 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
56 // On the linux try-bots: a path is returned (e.g. /home/chrome-bot/Desktop),
57 // but it doesn't exist.
58 if (key == DIR_USER_DESKTOP)
59 check_path_exists = false;
62 if (key == DIR_TASKBAR_PINS)
63 check_path_exists = false;
66 if (key != DIR_EXE && key != DIR_MODULE && key != FILE_EXE &&
68 if (path.ReferencesParent()) {
69 LOG(INFO) << "Path (" << path << ") references parent.";
74 if (path.ReferencesParent()) {
75 LOG(INFO) << "Path (" << path << ") references parent.";
78 #endif // BUILDFLAG(IS_MAC)
80 LOG(INFO) << "PathService::Get() returned false.";
84 LOG(INFO) << "PathService::Get() returned an empty path.";
87 if (check_path_exists && !PathExists(path)) {
88 LOG(INFO) << "Path (" << path << ") does not exist.";
94 // Returns true if PathService::Get returns false and path parameter is empty
95 // for the given PathService key enumeration value. Used to test path keys that
96 // are not supported on the platform or on some versions of Windows.
97 bool ReturnsInvalidPath(int key) {
99 bool result = PathService::Get(key, &path);
100 return !result && path.empty();
105 // On the Mac this winds up using some autoreleased objects, so we need to
106 // be a PlatformTest.
107 typedef PlatformTest PathServiceTest;
109 // Test that all PathService::Get calls return a value and a true result
110 // in the development environment. (This test was created because a few
111 // later changes to Get broke the semantics of the function and yielded the
112 // correct value while returning false.)
113 // If this test fails for specific value(s) on a specific platform, consider not
114 // defining the enum value on that platform rather than skipping or expecting
115 // failure for the value(s) on that platform in this test.
116 TEST_F(PathServiceTest, Get) {
117 // Contains keys that are defined but not supported on the platform.
118 #if BUILDFLAG(IS_ANDROID)
119 // The following keys are not intended to be implemented on Android (see
120 // crbug.com/1257402). Current implementation is described before each key.
121 // TODO(crbug.com/1257402): Remove the definition of these keys on Android
122 // or at least fix the behavior of DIR_HOME.
123 constexpr std::array kUnsupportedKeys = {
124 // Though DIR_HOME is not intended to be supported, PathProviderPosix
125 // handles it and returns true. Thus, it is NOT included in the array.
127 // PathProviderAndroid and PathProviderPosix both return false.
129 // PathProviderPosix handles it but fails at some point.
131 #elif BUILDFLAG(IS_FUCHSIA)
132 constexpr std::array kUnsupportedKeys = {
133 // TODO(crbug.com/1231928): Implement DIR_USER_DESKTOP.
136 constexpr std::array<BasePathKey, 0> kUnsupportedKeys = {};
137 #endif // BUILDFLAG(IS_ANDROID)
138 for (int key = PATH_START + 1; key < PATH_END; ++key) {
139 EXPECT_PRED1(Contains(kUnsupportedKeys, key) ? &ReturnsInvalidPath
143 #if BUILDFLAG(IS_WIN)
144 for (int key = PATH_WIN_START + 1; key < PATH_WIN_END; ++key) {
145 EXPECT_PRED1(ReturnsValidPath, key);
147 #elif BUILDFLAG(IS_MAC)
148 for (int key = PATH_MAC_START + 1; key < PATH_MAC_END; ++key) {
149 EXPECT_PRED1(ReturnsValidPath, key);
151 #elif BUILDFLAG(IS_IOS)
152 for (int key = PATH_IOS_START + 1; key < PATH_IOS_END; ++key) {
153 EXPECT_PRED1(ReturnsValidPath, key);
155 #elif BUILDFLAG(IS_ANDROID)
156 for (int key = PATH_ANDROID_START + 1; key < PATH_ANDROID_END;
158 EXPECT_PRED1(ReturnsValidPath, key);
160 #elif BUILDFLAG(IS_POSIX)
161 for (int key = PATH_POSIX_START + 1; key < PATH_POSIX_END;
163 EXPECT_PRED1(ReturnsValidPath, key);
165 #endif // BUILDFLAG(IS_WIN)
168 // Tests that CheckedGet returns the same path as Get.
169 TEST_F(PathServiceTest, CheckedGet) {
170 constexpr int kKey = DIR_CURRENT;
172 ASSERT_TRUE(PathService::Get(kKey, &path));
173 EXPECT_EQ(path, PathService::CheckedGet(kKey));
176 #if defined(GTEST_HAS_DEATH_TEST)
178 // Tests that CheckedGet CHECKs on failure.
179 TEST_F(PathServiceTest, CheckedGetFailure) {
180 constexpr int kBadKey = PATH_END;
182 EXPECT_FALSE(PathService::Get(kBadKey, &path));
183 EXPECT_DEATH(PathService::CheckedGet(kBadKey), "Failed to get the path");
186 #endif // defined(GTEST_HAS_DEATH_TEST)
188 // Test that all versions of the Override function of PathService do what they
189 // are supposed to do.
190 TEST_F(PathServiceTest, Override) {
191 int my_special_key = 666;
192 ScopedTempDir temp_dir;
193 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
194 FilePath fake_cache_dir(temp_dir.GetPath().AppendASCII("cache"));
195 // PathService::Override should always create the path provided if it doesn't
197 EXPECT_TRUE(PathService::Override(my_special_key, fake_cache_dir));
198 EXPECT_TRUE(PathExists(fake_cache_dir));
200 FilePath fake_cache_dir2(temp_dir.GetPath().AppendASCII("cache2"));
201 // PathService::OverrideAndCreateIfNeeded should obey the |create| parameter.
202 PathService::OverrideAndCreateIfNeeded(my_special_key,
206 EXPECT_FALSE(PathExists(fake_cache_dir2));
207 EXPECT_TRUE(PathService::OverrideAndCreateIfNeeded(my_special_key,
211 EXPECT_TRUE(PathExists(fake_cache_dir2));
213 #if BUILDFLAG(IS_POSIX)
214 FilePath non_existent(
215 MakeAbsoluteFilePath(temp_dir.GetPath()).AppendASCII("non_existent"));
216 EXPECT_TRUE(non_existent.IsAbsolute());
217 EXPECT_FALSE(PathExists(non_existent));
218 #if !BUILDFLAG(IS_ANDROID)
219 // This fails because MakeAbsoluteFilePath fails for non-existent files.
220 // Earlier versions of Bionic libc don't fail for non-existent files, so
221 // skip this check on Android.
222 EXPECT_FALSE(PathService::OverrideAndCreateIfNeeded(my_special_key,
226 #endif // !BUILDFLAG(IS_ANDROID)
227 // This works because indicating that |non_existent| is absolute skips the
228 // internal MakeAbsoluteFilePath call.
229 EXPECT_TRUE(PathService::OverrideAndCreateIfNeeded(my_special_key,
233 // Check that the path has been overridden and no directory was created.
234 EXPECT_FALSE(PathExists(non_existent));
236 EXPECT_TRUE(PathService::Get(my_special_key, &path));
237 EXPECT_EQ(non_existent, path);
238 #endif // BUILDFLAG(IS_POSIX)
241 // Check if multiple overrides can co-exist.
242 TEST_F(PathServiceTest, OverrideMultiple) {
243 int my_special_key = 666;
244 ScopedTempDir temp_dir;
245 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
246 FilePath fake_cache_dir1(temp_dir.GetPath().AppendASCII("1"));
247 EXPECT_TRUE(PathService::Override(my_special_key, fake_cache_dir1));
248 EXPECT_TRUE(PathExists(fake_cache_dir1));
249 ASSERT_TRUE(WriteFile(fake_cache_dir1.AppendASCII("t1"), "."));
251 FilePath fake_cache_dir2(temp_dir.GetPath().AppendASCII("2"));
252 EXPECT_TRUE(PathService::Override(my_special_key + 1, fake_cache_dir2));
253 EXPECT_TRUE(PathExists(fake_cache_dir2));
254 ASSERT_TRUE(WriteFile(fake_cache_dir2.AppendASCII("t2"), "."));
257 EXPECT_TRUE(PathService::Get(my_special_key, &result));
258 // Override might have changed the path representation but our test file
259 // should be still there.
260 EXPECT_TRUE(PathExists(result.AppendASCII("t1")));
261 EXPECT_TRUE(PathService::Get(my_special_key + 1, &result));
262 EXPECT_TRUE(PathExists(result.AppendASCII("t2")));
265 TEST_F(PathServiceTest, RemoveOverride) {
266 // Before we start the test we have to call RemoveOverride at least once to
267 // clear any overrides that might have been left from other tests.
268 PathService::RemoveOverrideForTests(DIR_TEMP);
270 FilePath original_user_data_dir;
271 EXPECT_TRUE(PathService::Get(DIR_TEMP, &original_user_data_dir));
272 EXPECT_FALSE(PathService::RemoveOverrideForTests(DIR_TEMP));
274 ScopedTempDir temp_dir;
275 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
276 EXPECT_TRUE(PathService::Override(DIR_TEMP, temp_dir.GetPath()));
277 FilePath new_user_data_dir;
278 EXPECT_TRUE(PathService::Get(DIR_TEMP, &new_user_data_dir));
279 EXPECT_NE(original_user_data_dir, new_user_data_dir);
281 EXPECT_TRUE(PathService::RemoveOverrideForTests(DIR_TEMP));
282 EXPECT_TRUE(PathService::Get(DIR_TEMP, &new_user_data_dir));
283 EXPECT_EQ(original_user_data_dir, new_user_data_dir);
286 #if BUILDFLAG(IS_WIN)
287 TEST_F(PathServiceTest, GetProgramFiles) {
288 FilePath programfiles_dir;
291 EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES,
293 EXPECT_EQ(programfiles_dir.value(),
294 FILE_PATH_LITERAL("C:\\Program Files"));
295 EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILESX86,
297 EXPECT_EQ(programfiles_dir.value(),
298 FILE_PATH_LITERAL("C:\\Program Files (x86)"));
299 EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES6432,
301 EXPECT_EQ(programfiles_dir.value(),
302 FILE_PATH_LITERAL("C:\\Program Files"));
304 if (base::win::OSInfo::GetInstance()->IsWowX86OnAMD64()) {
306 EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES,
308 EXPECT_EQ(programfiles_dir.value(),
309 FILE_PATH_LITERAL("C:\\Program Files (x86)"));
310 EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILESX86,
312 EXPECT_EQ(programfiles_dir.value(),
313 FILE_PATH_LITERAL("C:\\Program Files (x86)"));
314 EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES6432,
316 EXPECT_EQ(programfiles_dir.value(),
317 FILE_PATH_LITERAL("C:\\Program Files"));
320 EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES,
322 EXPECT_EQ(programfiles_dir.value(),
323 FILE_PATH_LITERAL("C:\\Program Files"));
324 EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILESX86,
326 EXPECT_EQ(programfiles_dir.value(),
327 FILE_PATH_LITERAL("C:\\Program Files"));
328 EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES6432,
330 EXPECT_EQ(programfiles_dir.value(),
331 FILE_PATH_LITERAL("C:\\Program Files"));
333 #endif // defined(_WIN64)
335 #endif // BUILDFLAG(IS_WIN)
337 // Tests that DIR_ASSETS is
338 // - the package root on Fuchsia,
339 // - overridden in tests by test_support_android.cc,
340 // - equals to base::apple::FrameworkBundlePath() on iOS,
341 // - a sub-directory of base::apple::FrameworkBundlePath() on iOS catalyst,
342 // - equals to DIR_MODULE otherwise.
343 TEST_F(PathServiceTest, DIR_ASSETS) {
345 ASSERT_TRUE(PathService::Get(DIR_ASSETS, &path));
346 #if BUILDFLAG(IS_FUCHSIA)
347 EXPECT_EQ(path.value(), "/pkg");
348 #elif BUILDFLAG(IS_ANDROID)
349 // This key is overridden in //base/test/test_support_android.cc.
350 EXPECT_EQ(path.value(), kExpectedChromiumTestsRoot);
351 #elif BUILDFLAG(IS_IOS_MACCATALYST)
352 EXPECT_TRUE(base::apple::FrameworkBundlePath().IsParent(path));
353 #elif BUILDFLAG(IS_IOS)
354 EXPECT_EQ(path, base::apple::FrameworkBundlePath());
356 EXPECT_EQ(path, PathService::CheckedGet(DIR_MODULE));
360 // DIR_OUT_TEST_DATA_ROOT is DIR_MODULE except on Fuchsia where it is the
361 // package root, on ios where it is the resources directory and on Android
362 // where it is overridden in tests by test_support_android.cc.
363 TEST_F(PathServiceTest, DIR_OUT_TEST_DATA_ROOT) {
365 ASSERT_TRUE(PathService::Get(DIR_OUT_TEST_DATA_ROOT, &path));
366 #if BUILDFLAG(IS_FUCHSIA)
367 EXPECT_EQ(path.value(), "/pkg");
368 #elif BUILDFLAG(IS_ANDROID)
369 // This key is overridden in //base/test/test_support_android.cc.
370 EXPECT_EQ(path.value(), kExpectedChromiumTestsRoot);
371 #elif BUILDFLAG(IS_IOS)
372 // On iOS, build output files are moved to the resources directory.
373 EXPECT_EQ(path, base::apple::FrameworkBundlePath());
375 // On other platforms all build output is in the same directory,
376 // so DIR_OUT_TEST_DATA_ROOT should match DIR_MODULE.
377 EXPECT_EQ(path, PathService::CheckedGet(DIR_MODULE));
381 // Test that DIR_GEN_TEST_DATA_ROOT contains dummy_generated.txt which is
382 // generated for this test.
383 TEST_F(PathServiceTest, DIR_GEN_TEST_DATA_ROOT) {
385 ASSERT_TRUE(PathService::Get(DIR_GEN_TEST_DATA_ROOT, &path));
386 EXPECT_TRUE(base::PathExists(
387 path.Append(FILE_PATH_LITERAL("base/generated_file_for_test.txt"))));
390 #if BUILDFLAG(IS_FUCHSIA)
391 // On Fuchsia, some keys have fixed paths that are easy to test.
393 TEST_F(PathServiceTest, DIR_SRC_TEST_DATA_ROOT) {
394 FilePath test_binary_path;
395 EXPECT_EQ(PathService::CheckedGet(DIR_SRC_TEST_DATA_ROOT).value(), "/pkg");
398 #elif BUILDFLAG(IS_ANDROID)
400 // These keys are overridden in //base/test/test_support_android.cc.
401 TEST_F(PathServiceTest, AndroidTestOverrides) {
402 EXPECT_EQ(PathService::CheckedGet(DIR_ANDROID_APP_DATA).value(),
403 kExpectedChromiumTestsRoot);
404 EXPECT_EQ(PathService::CheckedGet(DIR_ASSETS).value(),
405 kExpectedChromiumTestsRoot);
406 EXPECT_EQ(PathService::CheckedGet(DIR_SRC_TEST_DATA_ROOT).value(),
407 kExpectedChromiumTestsRoot);
408 EXPECT_EQ(PathService::CheckedGet(DIR_OUT_TEST_DATA_ROOT).value(),
409 kExpectedChromiumTestsRoot);
412 #endif // BUILDFLAG(IS_FUCHSIA)