1// Copyright (c) 2012 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 "base/path_service.h"
6
7#include "base/basictypes.h"
8#include "base/files/file_path.h"
9#include "base/files/file_util.h"
10#include "base/files/scoped_temp_dir.h"
11#include "base/strings/string_util.h"
12#include "build/build_config.h"
13#include "testing/gtest/include/gtest/gtest-spi.h"
14#include "testing/gtest/include/gtest/gtest.h"
15#include "testing/platform_test.h"
16
17#if defined(OS_WIN)
18#include "base/win/windows_version.h"
19#endif
20
21namespace {
22
23// Returns true if PathService::Get returns true and sets the path parameter
24// to non-empty for the given PathService::DirType enumeration value.
25bool ReturnsValidPath(int dir_type) {
26  base::FilePath path;
27  bool result = PathService::Get(dir_type, &path);
28
29  // Some paths might not exist on some platforms in which case confirming
30  // |result| is true and !path.empty() is the best we can do.
31  bool check_path_exists = true;
32#if defined(OS_POSIX)
33  // If chromium has never been started on this account, the cache path may not
34  // exist.
35  if (dir_type == base::DIR_CACHE)
36    check_path_exists = false;
37#endif
38#if defined(OS_LINUX)
39  // On the linux try-bots: a path is returned (e.g. /home/chrome-bot/Desktop),
40  // but it doesn't exist.
41  if (dir_type == base::DIR_USER_DESKTOP)
42    check_path_exists = false;
43#endif
44#if defined(OS_WIN)
45  if (dir_type == base::DIR_TASKBAR_PINS) {
46    // There is no pinned-to-taskbar shortcuts prior to Win7.
47    if (base::win::GetVersion() < base::win::VERSION_WIN7)
48      check_path_exists = false;
49  }
50#endif
51#if defined(OS_MACOSX)
52  if (dir_type != base::DIR_EXE && dir_type != base::DIR_MODULE &&
53      dir_type != base::FILE_EXE && dir_type != base::FILE_MODULE) {
54    if (path.ReferencesParent())
55      return false;
56  }
57#else
58  if (path.ReferencesParent())
59    return false;
60#endif
61  return result && !path.empty() && (!check_path_exists ||
62                                     base::PathExists(path));
63}
64
65#if defined(OS_WIN)
66// Function to test any directory keys that are not supported on some versions
67// of Windows. Checks that the function fails and that the returned path is
68// empty.
69bool ReturnsInvalidPath(int dir_type) {
70  base::FilePath path;
71  bool result = PathService::Get(dir_type, &path);
72  return !result && path.empty();
73}
74#endif
75
76}  // namespace
77
78// On the Mac this winds up using some autoreleased objects, so we need to
79// be a PlatformTest.
80typedef PlatformTest PathServiceTest;
81
82// Test that all PathService::Get calls return a value and a true result
83// in the development environment.  (This test was created because a few
84// later changes to Get broke the semantics of the function and yielded the
85// correct value while returning false.)
86TEST_F(PathServiceTest, Get) {
87  for (int key = base::PATH_START + 1; key < base::PATH_END; ++key) {
88#if defined(OS_ANDROID)
89    if (key == base::FILE_MODULE || key == base::DIR_USER_DESKTOP ||
90        key == base::DIR_HOME)
91      continue;  // Android doesn't implement these.
92#elif defined(OS_IOS)
93    if (key == base::DIR_USER_DESKTOP)
94      continue;  // iOS doesn't implement DIR_USER_DESKTOP;
95#endif
96    EXPECT_PRED1(ReturnsValidPath, key);
97  }
98#if defined(OS_WIN)
99  for (int key = base::PATH_WIN_START + 1; key < base::PATH_WIN_END; ++key) {
100    bool valid = true;
101    switch(key) {
102      case base::DIR_LOCAL_APP_DATA_LOW:
103        // DIR_LOCAL_APP_DATA_LOW is not supported prior Vista and is expected
104        // to fail.
105        valid = base::win::GetVersion() >= base::win::VERSION_VISTA;
106        break;
107      case base::DIR_APP_SHORTCUTS:
108        // DIR_APP_SHORTCUTS is not supported prior Windows 8 and is expected to
109        // fail.
110        valid = base::win::GetVersion() >= base::win::VERSION_WIN8;
111        break;
112    }
113
114    if (valid)
115      EXPECT_TRUE(ReturnsValidPath(key)) << key;
116    else
117      EXPECT_TRUE(ReturnsInvalidPath(key)) << key;
118  }
119#elif defined(OS_MACOSX)
120  for (int key = base::PATH_MAC_START + 1; key < base::PATH_MAC_END; ++key) {
121    EXPECT_PRED1(ReturnsValidPath, key);
122  }
123#elif defined(OS_ANDROID)
124  for (int key = base::PATH_ANDROID_START + 1; key < base::PATH_ANDROID_END;
125       ++key) {
126    EXPECT_PRED1(ReturnsValidPath, key);
127  }
128#elif defined(OS_POSIX)
129  for (int key = base::PATH_POSIX_START + 1; key < base::PATH_POSIX_END;
130       ++key) {
131    EXPECT_PRED1(ReturnsValidPath, key);
132  }
133#endif
134}
135
136// Test that all versions of the Override function of PathService do what they
137// are supposed to do.
138TEST_F(PathServiceTest, Override) {
139  int my_special_key = 666;
140  base::ScopedTempDir temp_dir;
141  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
142  base::FilePath fake_cache_dir(temp_dir.path().AppendASCII("cache"));
143  // PathService::Override should always create the path provided if it doesn't
144  // exist.
145  EXPECT_TRUE(PathService::Override(my_special_key, fake_cache_dir));
146  EXPECT_TRUE(base::PathExists(fake_cache_dir));
147
148  base::FilePath fake_cache_dir2(temp_dir.path().AppendASCII("cache2"));
149  // PathService::OverrideAndCreateIfNeeded should obey the |create| parameter.
150  PathService::OverrideAndCreateIfNeeded(my_special_key,
151                                         fake_cache_dir2,
152                                         false,
153                                         false);
154  EXPECT_FALSE(base::PathExists(fake_cache_dir2));
155  EXPECT_TRUE(PathService::OverrideAndCreateIfNeeded(my_special_key,
156                                                     fake_cache_dir2,
157                                                     false,
158                                                     true));
159  EXPECT_TRUE(base::PathExists(fake_cache_dir2));
160
161#if defined(OS_POSIX)
162  base::FilePath non_existent(
163      base::MakeAbsoluteFilePath(temp_dir.path()).AppendASCII("non_existent"));
164  EXPECT_TRUE(non_existent.IsAbsolute());
165  EXPECT_FALSE(base::PathExists(non_existent));
166#if !defined(OS_ANDROID)
167  // This fails because MakeAbsoluteFilePath fails for non-existent files.
168  // Earlier versions of Bionic libc don't fail for non-existent files, so
169  // skip this check on Android.
170  EXPECT_FALSE(PathService::OverrideAndCreateIfNeeded(my_special_key,
171                                                      non_existent,
172                                                      false,
173                                                      false));
174#endif
175  // This works because indicating that |non_existent| is absolute skips the
176  // internal MakeAbsoluteFilePath call.
177  EXPECT_TRUE(PathService::OverrideAndCreateIfNeeded(my_special_key,
178                                                     non_existent,
179                                                     true,
180                                                     false));
181  // Check that the path has been overridden and no directory was created.
182  EXPECT_FALSE(base::PathExists(non_existent));
183  base::FilePath path;
184  EXPECT_TRUE(PathService::Get(my_special_key, &path));
185  EXPECT_EQ(non_existent, path);
186#endif
187}
188
189// Check if multiple overrides can co-exist.
190TEST_F(PathServiceTest, OverrideMultiple) {
191  int my_special_key = 666;
192  base::ScopedTempDir temp_dir;
193  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
194  base::FilePath fake_cache_dir1(temp_dir.path().AppendASCII("1"));
195  EXPECT_TRUE(PathService::Override(my_special_key, fake_cache_dir1));
196  EXPECT_TRUE(base::PathExists(fake_cache_dir1));
197  ASSERT_EQ(1, base::WriteFile(fake_cache_dir1.AppendASCII("t1"), ".", 1));
198
199  base::FilePath fake_cache_dir2(temp_dir.path().AppendASCII("2"));
200  EXPECT_TRUE(PathService::Override(my_special_key + 1, fake_cache_dir2));
201  EXPECT_TRUE(base::PathExists(fake_cache_dir2));
202  ASSERT_EQ(1, base::WriteFile(fake_cache_dir2.AppendASCII("t2"), ".", 1));
203
204  base::FilePath result;
205  EXPECT_TRUE(PathService::Get(my_special_key, &result));
206  // Override might have changed the path representation but our test file
207  // should be still there.
208  EXPECT_TRUE(base::PathExists(result.AppendASCII("t1")));
209  EXPECT_TRUE(PathService::Get(my_special_key + 1, &result));
210  EXPECT_TRUE(base::PathExists(result.AppendASCII("t2")));
211}
212
213TEST_F(PathServiceTest, RemoveOverride) {
214  // Before we start the test we have to call RemoveOverride at least once to
215  // clear any overrides that might have been left from other tests.
216  PathService::RemoveOverride(base::DIR_TEMP);
217
218  base::FilePath original_user_data_dir;
219  EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &original_user_data_dir));
220  EXPECT_FALSE(PathService::RemoveOverride(base::DIR_TEMP));
221
222  base::ScopedTempDir temp_dir;
223  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
224  EXPECT_TRUE(PathService::Override(base::DIR_TEMP, temp_dir.path()));
225  base::FilePath new_user_data_dir;
226  EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &new_user_data_dir));
227  EXPECT_NE(original_user_data_dir, new_user_data_dir);
228
229  EXPECT_TRUE(PathService::RemoveOverride(base::DIR_TEMP));
230  EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &new_user_data_dir));
231  EXPECT_EQ(original_user_data_dir, new_user_data_dir);
232}
233