xref: /aosp_15_r20/external/cronet/base/path_service_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 "base/path_service.h"
6 
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/scoped_environment_variable_override.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/test/gtest_util.h"
17 #include "build/build_config.h"
18 #include "testing/gtest/include/gtest/gtest-spi.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "testing/platform_test.h"
21 
22 #if BUILDFLAG(IS_WIN)
23 #include "base/win/windows_version.h"
24 #endif
25 
26 #if BUILDFLAG(IS_APPLE)
27 #include "base/apple/bundle_locations.h"
28 #endif
29 
30 namespace base {
31 
32 namespace {
33 
34 #if BUILDFLAG(IS_ANDROID)
35 // Defined in
36 // //base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java.
37 constexpr char kExpectedChromiumTestsRoot[] =
38     "/storage/emulated/0/chromium_tests_root";
39 #endif
40 
41 // Returns true if PathService::Get returns true and sets the path parameter
42 // to non-empty for the given PathService key enumeration value.
ReturnsValidPath(int key)43 bool ReturnsValidPath(int key) {
44   FilePath path;
45   bool result = PathService::Get(key, &path);
46 
47   // Some paths might not exist on some platforms in which case confirming
48   // |result| is true and !path.empty() is the best we can do.
49   bool check_path_exists = true;
50 
51 #if BUILDFLAG(IS_POSIX)
52   // If chromium has never been started on this account, the cache path may not
53   // exist.
54   if (key == DIR_CACHE)
55     check_path_exists = false;
56 #endif
57 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
58   // On the linux try-bots: a path is returned (e.g. /home/chrome-bot/Desktop),
59   // but it doesn't exist.
60   if (key == DIR_USER_DESKTOP)
61     check_path_exists = false;
62 #endif
63 #if BUILDFLAG(IS_WIN)
64   if (key == DIR_TASKBAR_PINS)
65     check_path_exists = false;
66 #endif
67 #if BUILDFLAG(IS_MAC)
68   if (key != DIR_EXE && key != DIR_MODULE && key != FILE_EXE &&
69       key != FILE_MODULE) {
70     if (path.ReferencesParent()) {
71       LOG(INFO) << "Path (" << path << ") references parent.";
72       return false;
73     }
74   }
75 #else
76   if (path.ReferencesParent()) {
77     LOG(INFO) << "Path (" << path << ") references parent.";
78     return false;
79   }
80 #endif  // BUILDFLAG(IS_MAC)
81   if (!result) {
82     LOG(INFO) << "PathService::Get() returned false.";
83     return false;
84   }
85   if (path.empty()) {
86     LOG(INFO) << "PathService::Get() returned an empty path.";
87     return false;
88   }
89   if (check_path_exists && !PathExists(path)) {
90     LOG(INFO) << "Path (" << path << ") does not exist.";
91     return false;
92   }
93   return true;
94 }
95 
96 // Returns true if PathService::Get returns false and path parameter is empty
97 // for the given PathService key enumeration value. Used to test path keys that
98 // are not supported on the platform or on some versions of Windows.
ReturnsInvalidPath(int key)99 bool ReturnsInvalidPath(int key) {
100   FilePath path;
101   bool result = PathService::Get(key, &path);
102   return !result && path.empty();
103 }
104 
105 }  // namespace
106 
107 // On the Mac this winds up using some autoreleased objects, so we need to
108 // be a PlatformTest.
109 typedef PlatformTest PathServiceTest;
110 
111 // Test that all PathService::Get calls return a value and a true result
112 // in the development environment.  (This test was created because a few
113 // later changes to Get broke the semantics of the function and yielded the
114 // correct value while returning false.)
115 // If this test fails for specific value(s) on a specific platform, consider not
116 // defining the enum value on that platform rather than skipping or expecting
117 // failure for the value(s) on that platform in this test.
TEST_F(PathServiceTest,Get)118 TEST_F(PathServiceTest, Get) {
119   // Contains keys that are defined but not supported on the platform.
120 #if BUILDFLAG(IS_ANDROID)
121   // The following keys are not intended to be implemented on Android (see
122   // crbug.com/1257402). Current implementation is described before each key.
123   // TODO(crbug.com/1257402): Remove the definition of these keys on Android
124   // or at least fix the behavior of DIR_HOME.
125   constexpr std::array kUnsupportedKeys = {
126       // Though DIR_HOME is not intended to be supported, PathProviderPosix
127       // handles it and returns true. Thus, it is NOT included in the array.
128       /* DIR_HOME, */
129       // PathProviderAndroid and PathProviderPosix both return false.
130       FILE_MODULE,
131       // PathProviderPosix handles it but fails at some point.
132       DIR_USER_DESKTOP};
133 #elif BUILDFLAG(IS_FUCHSIA)
134   constexpr std::array kUnsupportedKeys = {
135       // TODO(crbug.com/1231928): Implement DIR_USER_DESKTOP.
136       DIR_USER_DESKTOP};
137 #else
138   constexpr std::array<BasePathKey, 0> kUnsupportedKeys = {};
139 #endif  // BUILDFLAG(IS_ANDROID)
140   for (int key = PATH_START + 1; key < PATH_END; ++key) {
141     EXPECT_PRED1(Contains(kUnsupportedKeys, key) ? &ReturnsInvalidPath
142                                                  : &ReturnsValidPath,
143                  key);
144   }
145 #if BUILDFLAG(IS_WIN)
146   for (int key = PATH_WIN_START + 1; key < PATH_WIN_END; ++key) {
147     EXPECT_PRED1(ReturnsValidPath, key);
148   }
149 #elif BUILDFLAG(IS_MAC)
150   for (int key = PATH_MAC_START + 1; key < PATH_MAC_END; ++key) {
151     EXPECT_PRED1(ReturnsValidPath, key);
152   }
153 #elif BUILDFLAG(IS_IOS)
154   for (int key = PATH_IOS_START + 1; key < PATH_IOS_END; ++key) {
155     EXPECT_PRED1(ReturnsValidPath, key);
156   }
157 #elif BUILDFLAG(IS_ANDROID)
158   for (int key = PATH_ANDROID_START + 1; key < PATH_ANDROID_END;
159        ++key) {
160     EXPECT_PRED1(ReturnsValidPath, key);
161   }
162 #elif BUILDFLAG(IS_POSIX)
163   for (int key = PATH_POSIX_START + 1; key < PATH_POSIX_END;
164        ++key) {
165     EXPECT_PRED1(ReturnsValidPath, key);
166   }
167 #endif  // BUILDFLAG(IS_WIN)
168 }
169 
170 // Tests that CheckedGet returns the same path as Get.
TEST_F(PathServiceTest,CheckedGet)171 TEST_F(PathServiceTest, CheckedGet) {
172   constexpr int kKey = DIR_CURRENT;
173   FilePath path;
174   ASSERT_TRUE(PathService::Get(kKey, &path));
175   EXPECT_EQ(path, PathService::CheckedGet(kKey));
176 }
177 
178 #if defined(GTEST_HAS_DEATH_TEST)
179 
180 // Tests that CheckedGet CHECKs on failure.
TEST_F(PathServiceTest,CheckedGetFailure)181 TEST_F(PathServiceTest, CheckedGetFailure) {
182   constexpr int kBadKey = PATH_END;
183   FilePath path;
184   EXPECT_FALSE(PathService::Get(kBadKey, &path));
185   EXPECT_DEATH(PathService::CheckedGet(kBadKey), "Failed to get the path");
186 }
187 
188 #endif  // defined(GTEST_HAS_DEATH_TEST)
189 
190 // Test that all versions of the Override function of PathService do what they
191 // are supposed to do.
TEST_F(PathServiceTest,Override)192 TEST_F(PathServiceTest, Override) {
193   int my_special_key = 666;
194   ScopedTempDir temp_dir;
195   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
196   FilePath fake_cache_dir(temp_dir.GetPath().AppendASCII("cache"));
197   // PathService::Override should always create the path provided if it doesn't
198   // exist.
199   EXPECT_TRUE(PathService::Override(my_special_key, fake_cache_dir));
200   EXPECT_TRUE(PathExists(fake_cache_dir));
201 
202   FilePath fake_cache_dir2(temp_dir.GetPath().AppendASCII("cache2"));
203   // PathService::OverrideAndCreateIfNeeded should obey the |create| parameter.
204   PathService::OverrideAndCreateIfNeeded(my_special_key,
205                                          fake_cache_dir2,
206                                          false,
207                                          false);
208   EXPECT_FALSE(PathExists(fake_cache_dir2));
209   EXPECT_TRUE(PathService::OverrideAndCreateIfNeeded(my_special_key,
210                                                      fake_cache_dir2,
211                                                      false,
212                                                      true));
213   EXPECT_TRUE(PathExists(fake_cache_dir2));
214 
215 #if BUILDFLAG(IS_POSIX)
216   FilePath non_existent(
217       MakeAbsoluteFilePath(temp_dir.GetPath()).AppendASCII("non_existent"));
218   EXPECT_TRUE(non_existent.IsAbsolute());
219   EXPECT_FALSE(PathExists(non_existent));
220 #if !BUILDFLAG(IS_ANDROID)
221   // This fails because MakeAbsoluteFilePath fails for non-existent files.
222   // Earlier versions of Bionic libc don't fail for non-existent files, so
223   // skip this check on Android.
224   EXPECT_FALSE(PathService::OverrideAndCreateIfNeeded(my_special_key,
225                                                       non_existent,
226                                                       false,
227                                                       false));
228 #endif  // !BUILDFLAG(IS_ANDROID)
229   // This works because indicating that |non_existent| is absolute skips the
230   // internal MakeAbsoluteFilePath call.
231   EXPECT_TRUE(PathService::OverrideAndCreateIfNeeded(my_special_key,
232                                                      non_existent,
233                                                      true,
234                                                      false));
235   // Check that the path has been overridden and no directory was created.
236   EXPECT_FALSE(PathExists(non_existent));
237   FilePath path;
238   EXPECT_TRUE(PathService::Get(my_special_key, &path));
239   EXPECT_EQ(non_existent, path);
240 #endif  // BUILDFLAG(IS_POSIX)
241 }
242 
243 // Check if multiple overrides can co-exist.
TEST_F(PathServiceTest,OverrideMultiple)244 TEST_F(PathServiceTest, OverrideMultiple) {
245   int my_special_key = 666;
246   ScopedTempDir temp_dir;
247   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
248   FilePath fake_cache_dir1(temp_dir.GetPath().AppendASCII("1"));
249   EXPECT_TRUE(PathService::Override(my_special_key, fake_cache_dir1));
250   EXPECT_TRUE(PathExists(fake_cache_dir1));
251   ASSERT_TRUE(WriteFile(fake_cache_dir1.AppendASCII("t1"), "."));
252 
253   FilePath fake_cache_dir2(temp_dir.GetPath().AppendASCII("2"));
254   EXPECT_TRUE(PathService::Override(my_special_key + 1, fake_cache_dir2));
255   EXPECT_TRUE(PathExists(fake_cache_dir2));
256   ASSERT_TRUE(WriteFile(fake_cache_dir2.AppendASCII("t2"), "."));
257 
258   FilePath result;
259   EXPECT_TRUE(PathService::Get(my_special_key, &result));
260   // Override might have changed the path representation but our test file
261   // should be still there.
262   EXPECT_TRUE(PathExists(result.AppendASCII("t1")));
263   EXPECT_TRUE(PathService::Get(my_special_key + 1, &result));
264   EXPECT_TRUE(PathExists(result.AppendASCII("t2")));
265 }
266 
TEST_F(PathServiceTest,RemoveOverride)267 TEST_F(PathServiceTest, RemoveOverride) {
268   // Before we start the test we have to call RemoveOverride at least once to
269   // clear any overrides that might have been left from other tests.
270   PathService::RemoveOverrideForTests(DIR_TEMP);
271 
272   FilePath original_user_data_dir;
273   EXPECT_TRUE(PathService::Get(DIR_TEMP, &original_user_data_dir));
274   EXPECT_FALSE(PathService::RemoveOverrideForTests(DIR_TEMP));
275 
276   ScopedTempDir temp_dir;
277   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
278   EXPECT_TRUE(PathService::Override(DIR_TEMP, temp_dir.GetPath()));
279   FilePath new_user_data_dir;
280   EXPECT_TRUE(PathService::Get(DIR_TEMP, &new_user_data_dir));
281   EXPECT_NE(original_user_data_dir, new_user_data_dir);
282 
283   EXPECT_TRUE(PathService::RemoveOverrideForTests(DIR_TEMP));
284   EXPECT_TRUE(PathService::Get(DIR_TEMP, &new_user_data_dir));
285   EXPECT_EQ(original_user_data_dir, new_user_data_dir);
286 }
287 
288 #if BUILDFLAG(IS_WIN)
TEST_F(PathServiceTest,GetProgramFiles)289 TEST_F(PathServiceTest, GetProgramFiles) {
290   FilePath programfiles_dir;
291 #if defined(_WIN64)
292   // 64-bit on 64-bit.
293   EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES,
294       &programfiles_dir));
295   EXPECT_EQ(programfiles_dir.value(),
296       FILE_PATH_LITERAL("C:\\Program Files"));
297   EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILESX86,
298       &programfiles_dir));
299   EXPECT_EQ(programfiles_dir.value(),
300       FILE_PATH_LITERAL("C:\\Program Files (x86)"));
301   EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES6432,
302       &programfiles_dir));
303   EXPECT_EQ(programfiles_dir.value(),
304       FILE_PATH_LITERAL("C:\\Program Files"));
305 #else
306   if (base::win::OSInfo::GetInstance()->IsWowX86OnAMD64() ||
307       base::win::OSInfo::GetInstance()->IsWowX86OnARM64()) {
308     // 32-bit on 64-bit.
309     EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES,
310         &programfiles_dir));
311     EXPECT_EQ(programfiles_dir.value(),
312         FILE_PATH_LITERAL("C:\\Program Files (x86)"));
313     EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILESX86,
314         &programfiles_dir));
315     EXPECT_EQ(programfiles_dir.value(),
316         FILE_PATH_LITERAL("C:\\Program Files (x86)"));
317     EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES6432,
318         &programfiles_dir));
319     EXPECT_EQ(programfiles_dir.value(),
320         FILE_PATH_LITERAL("C:\\Program Files"));
321   } else {
322     // 32-bit on 32-bit.
323     EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES,
324         &programfiles_dir));
325     EXPECT_EQ(programfiles_dir.value(),
326         FILE_PATH_LITERAL("C:\\Program Files"));
327     EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILESX86,
328         &programfiles_dir));
329     EXPECT_EQ(programfiles_dir.value(),
330         FILE_PATH_LITERAL("C:\\Program Files"));
331     EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES6432,
332         &programfiles_dir));
333     EXPECT_EQ(programfiles_dir.value(),
334         FILE_PATH_LITERAL("C:\\Program Files"));
335   }
336 #endif  // defined(_WIN64)
337 }
338 #endif  // BUILDFLAG(IS_WIN)
339 
340 // Tests that DIR_ASSETS is
341 // - the package root on Fuchsia,
342 // - overridden in tests by test_support_android.cc,
343 // - equals to base::apple::FrameworkBundlePath() on iOS,
344 // - a sub-directory of base::apple::FrameworkBundlePath() on iOS catalyst,
345 // - equals to DIR_MODULE otherwise.
TEST_F(PathServiceTest,DIR_ASSETS)346 TEST_F(PathServiceTest, DIR_ASSETS) {
347   FilePath path;
348   ASSERT_TRUE(PathService::Get(DIR_ASSETS, &path));
349 #if BUILDFLAG(IS_FUCHSIA)
350   EXPECT_EQ(path.value(), "/pkg");
351 #elif BUILDFLAG(IS_ANDROID)
352   // This key is overridden in //base/test/test_support_android.cc.
353   EXPECT_EQ(path.value(), kExpectedChromiumTestsRoot);
354 #elif BUILDFLAG(IS_IOS_MACCATALYST)
355   EXPECT_TRUE(base::apple::FrameworkBundlePath().IsParent(path));
356 #elif BUILDFLAG(IS_IOS)
357   EXPECT_EQ(path, base::apple::FrameworkBundlePath());
358 #else
359   EXPECT_EQ(path, PathService::CheckedGet(DIR_MODULE));
360 #endif
361 }
362 
363 // DIR_OUT_TEST_DATA_ROOT is DIR_MODULE except on Fuchsia where it is the
364 // package root, on ios where it is the resources directory and on Android
365 // where it is overridden in tests by test_support_android.cc.
TEST_F(PathServiceTest,DIR_OUT_TEST_DATA_ROOT)366 TEST_F(PathServiceTest, DIR_OUT_TEST_DATA_ROOT) {
367   FilePath path;
368   ASSERT_TRUE(PathService::Get(DIR_OUT_TEST_DATA_ROOT, &path));
369 #if BUILDFLAG(IS_FUCHSIA)
370   EXPECT_EQ(path.value(), "/pkg");
371 #elif BUILDFLAG(IS_ANDROID)
372   // This key is overridden in //base/test/test_support_android.cc.
373   EXPECT_EQ(path.value(), kExpectedChromiumTestsRoot);
374 #elif BUILDFLAG(IS_IOS)
375   // On iOS, build output files are moved to the resources directory.
376   EXPECT_EQ(path, base::apple::FrameworkBundlePath());
377 #else
378   // On other platforms all build output is in the same directory,
379   // so DIR_OUT_TEST_DATA_ROOT should match DIR_MODULE.
380   EXPECT_EQ(path, PathService::CheckedGet(DIR_MODULE));
381 #endif
382 }
383 
384 // Test that DIR_GEN_TEST_DATA_ROOT contains dummy_generated.txt which is
385 // generated for this test.
TEST_F(PathServiceTest,DIR_GEN_TEST_DATA_ROOT)386 TEST_F(PathServiceTest, DIR_GEN_TEST_DATA_ROOT) {
387   FilePath path;
388   ASSERT_TRUE(PathService::Get(DIR_GEN_TEST_DATA_ROOT, &path));
389   EXPECT_TRUE(base::PathExists(
390       path.Append(FILE_PATH_LITERAL("base/generated_file_for_test.txt"))));
391 }
392 
393 #if ((BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE) && \
394       !BUILDFLAG(IS_ANDROID)) ||                     \
395      BUILDFLAG(IS_WIN))
396 
397 // Test that CR_SOURCE_ROOT is being used when set.
398 // By default on those platforms, this directory is set to two directories up
399 // the current executable directory ("../../").
TEST_F(PathServiceTest,SetTestDataRootAsAbsolutePath)400 TEST_F(PathServiceTest, SetTestDataRootAsAbsolutePath) {
401   // This is needed because on some platform `DIR_SRC_TEST_DATA_ROOT` can be
402   // cached before reaching this function.
403   PathService::DisableCache();
404   base::ScopedTempDir tempdir;
405   ASSERT_TRUE(tempdir.CreateUniqueTempDir());
406 
407 #if BUILDFLAG(IS_WIN)
408   auto scoped_env = base::ScopedEnvironmentVariableOverride(
409       "CR_SOURCE_ROOT", base::WideToUTF8(tempdir.GetPath().value()));
410 #else
411   auto scoped_env = base::ScopedEnvironmentVariableOverride(
412       "CR_SOURCE_ROOT", tempdir.GetPath().value());
413 #endif
414 
415   base::FilePath test_data_root;
416   ASSERT_TRUE(PathService::Get(DIR_SRC_TEST_DATA_ROOT, &test_data_root));
417 
418   ASSERT_EQ(test_data_root, tempdir.GetPath());
419 }
420 
421 // Test that CR_SOURCE_ROOT is being used when set.
TEST_F(PathServiceTest,SetTestDataRootAsRelativePath)422 TEST_F(PathServiceTest, SetTestDataRootAsRelativePath) {
423   // This is needed because on some platform `DIR_SRC_TEST_DATA_ROOT` can be
424   // cached before reaching this function.
425   PathService::DisableCache();
426 #if BUILDFLAG(IS_WIN)
427   auto scoped_env = base::ScopedEnvironmentVariableOverride(
428       "CR_SOURCE_ROOT", base::WideToUTF8(base::FilePath::kParentDirectory));
429 #else
430   auto scoped_env = base::ScopedEnvironmentVariableOverride(
431       "CR_SOURCE_ROOT", base::FilePath::kParentDirectory);
432 #endif
433   base::FilePath path;
434   ASSERT_TRUE(PathService::Get(DIR_EXE, &path));
435 
436   base::FilePath test_data_root;
437   ASSERT_TRUE(PathService::Get(DIR_SRC_TEST_DATA_ROOT, &test_data_root));
438 
439   path = MakeAbsoluteFilePath(path.Append(base::FilePath::kParentDirectory));
440   ASSERT_EQ(test_data_root, path);
441 }
442 
443 #endif
444 
445 #if BUILDFLAG(IS_FUCHSIA)
446 // On Fuchsia, some keys have fixed paths that are easy to test.
447 
TEST_F(PathServiceTest,DIR_SRC_TEST_DATA_ROOT)448 TEST_F(PathServiceTest, DIR_SRC_TEST_DATA_ROOT) {
449   FilePath test_binary_path;
450   EXPECT_EQ(PathService::CheckedGet(DIR_SRC_TEST_DATA_ROOT).value(), "/pkg");
451 }
452 
453 #elif BUILDFLAG(IS_ANDROID)
454 
455 // These keys are overridden in //base/test/test_support_android.cc.
TEST_F(PathServiceTest,AndroidTestOverrides)456 TEST_F(PathServiceTest, AndroidTestOverrides) {
457   EXPECT_EQ(PathService::CheckedGet(DIR_ANDROID_APP_DATA).value(),
458             kExpectedChromiumTestsRoot);
459   EXPECT_EQ(PathService::CheckedGet(DIR_ASSETS).value(),
460             kExpectedChromiumTestsRoot);
461   EXPECT_EQ(PathService::CheckedGet(DIR_SRC_TEST_DATA_ROOT).value(),
462             kExpectedChromiumTestsRoot);
463   EXPECT_EQ(PathService::CheckedGet(DIR_OUT_TEST_DATA_ROOT).value(),
464             kExpectedChromiumTestsRoot);
465 }
466 
467 #endif  // BUILDFLAG(IS_FUCHSIA)
468 
469 }  // namespace base
470