summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/base.xcodeproj/project.pbxproj2
-rw-r--r--base/base_paths.cc7
-rw-r--r--base/base_paths.h3
-rw-r--r--base/base_paths_mac.h10
-rw-r--r--base/base_paths_mac.mm10
-rw-r--r--base/base_paths_win.cc7
-rw-r--r--base/base_paths_win.h3
-rw-r--r--base/file_util.cc40
-rw-r--r--base/file_util.h38
-rw-r--r--base/file_util_posix.cc219
-rw-r--r--base/file_util_unittest.cc247
11 files changed, 420 insertions, 166 deletions
diff --git a/base/base.xcodeproj/project.pbxproj b/base/base.xcodeproj/project.pbxproj
index d52aee6..a1c1ba1 100644
--- a/base/base.xcodeproj/project.pbxproj
+++ b/base/base.xcodeproj/project.pbxproj
@@ -102,6 +102,7 @@
A5A026550E4A214600498DA9 /* file_util.cc in Sources */ = {isa = PBXBuildFile; fileRef = A5A026540E4A214600498DA9 /* file_util.cc */; };
A5A0268E0E4A2BDC00498DA9 /* file_util_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = A5A0268D0E4A2BDC00498DA9 /* file_util_posix.cc */; };
A5A0270B0E4A630D00498DA9 /* file_util_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = A5A0270A0E4A630D00498DA9 /* file_util_mac.mm */; };
+ A5CE1D2B0E55F4D800AD0606 /* file_util_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = A5A0282D0E4CFA8500498DA9 /* file_util_unittest.cc */; };
ABF4B98F0DC2BA6900A6E319 /* base_paths_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABF4B98E0DC2BA6900A6E319 /* base_paths_mac.mm */; };
ABF4B99E0DC2BB6000A6E319 /* clipboard_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABF4B99D0DC2BB6000A6E319 /* clipboard_mac.mm */; };
ABF4B9AF0DC2BC6200A6E319 /* json_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8254031B0D92D1F40006B936 /* json_reader.cc */; };
@@ -1111,6 +1112,7 @@
files = (
7B78D38E0E54FE0100609465 /* at_exit_unittest.cc in Sources */,
7B78D38F0E54FE0100609465 /* command_line_unittest.cc in Sources */,
+ A5CE1D2B0E55F4D800AD0606 /* file_util_unittest.cc in Sources */,
7B78D3910E54FE0100609465 /* file_version_info_unittest.cc in Sources */,
7B78D3920E54FE0100609465 /* json_reader_unittest.cc in Sources */,
7B78D3930E54FE0100609465 /* json_writer_unittest.cc in Sources */,
diff --git a/base/base_paths.cc b/base/base_paths.cc
index ed0a489..e68a253 100644
--- a/base/base_paths.cc
+++ b/base/base_paths.cc
@@ -51,13 +51,6 @@ bool PathProvider(int key, std::wstring* result) {
if (!file_util::GetTempDir(&cur))
return false;
break;
- case base::DIR_SOURCE_ROOT:
- // By default, unit tests execute two levels deep from the source root.
- // For example: chrome/{Debug|Release}/ui_tests.exe
- PathProvider(base::DIR_EXE, &cur);
- file_util::UpOneDirectory(&cur);
- file_util::UpOneDirectory(&cur);
- break;
default:
return false;
}
diff --git a/base/base_paths.h b/base/base_paths.h
index 31344a2..2fea742 100644
--- a/base/base_paths.h
+++ b/base/base_paths.h
@@ -51,9 +51,6 @@ enum {
DIR_EXE, // directory containing FILE_EXE
DIR_MODULE, // directory containing FILE_MODULE
DIR_TEMP, // temporary directory
- DIR_SOURCE_ROOT, // Returns the root of the source tree. This key is useful
- // for tests that need to locate various resources. It
- // should not be used outside of test code.
PATH_END
};
diff --git a/base/base_paths_mac.h b/base/base_paths_mac.h
index 2097a65..e368dbc 100644
--- a/base/base_paths_mac.h
+++ b/base/base_paths_mac.h
@@ -42,10 +42,12 @@ enum {
FILE_EXE, // path and filename of the current executable
FILE_MODULE, // path and filename of the module containing the code for the
// PathService (which could differ from FILE_EXE if the
- // PathService were compiled into a DLL, for example)
- DIR_APP_DATA, // Application Data directory under the user profile.
- DIR_LOCAL_APP_DATA, // "Local Settings\Application Data" directory under the
- // user profile.
+ // PathService were compiled into a library, for example)
+ DIR_APP_DATA, // ~/Library/Application Support/Google/Chrome
+ DIR_LOCAL_APP_DATA, // same as above (can we remove?)
+ DIR_SOURCE_ROOT, // Returns the root of the source tree. This key is useful
+ // for tests that need to locate various resources. It
+ // should not be used outside of test code.
PATH_MAC_END
};
diff --git a/base/base_paths_mac.mm b/base/base_paths_mac.mm
index c88a433..e5b0c65 100644
--- a/base/base_paths_mac.mm
+++ b/base/base_paths_mac.mm
@@ -31,7 +31,9 @@
#import <Cocoa/Cocoa.h>
+#include "base/file_util.h"
#include "base/logging.h"
+#include "base/path_service.h"
#include "base/string_util.h"
namespace base {
@@ -61,6 +63,14 @@ bool PathProviderMac(int key, std::wstring* result) {
[path cStringUsingEncoding:NSUTF32StringEncoding]);
break;
}
+ case base::DIR_SOURCE_ROOT:
+ // On the mac, unit tests execute three levels deep from the source root.
+ // For example: chrome/build/{Debug|Release}/ui_tests
+ PathService::Get(base::DIR_EXE, &cur);
+ file_util::UpOneDirectory(&cur);
+ file_util::UpOneDirectory(&cur);
+ file_util::UpOneDirectory(&cur);
+ break;
default:
return false;
}
diff --git a/base/base_paths_win.cc b/base/base_paths_win.cc
index 432bc90..0fe0101 100644
--- a/base/base_paths_win.cc
+++ b/base/base_paths_win.cc
@@ -124,6 +124,13 @@ bool PathProviderWin(int key, std::wstring* result) {
return false;
cur = system_buffer;
break;
+ case base::DIR_SOURCE_ROOT:
+ // On Windows, unit tests execute two levels deep from the source root.
+ // For example: chrome/{Debug|Release}/ui_tests.exe
+ PathProvider(base::DIR_EXE, &cur);
+ file_util::UpOneDirectory(&cur);
+ file_util::UpOneDirectory(&cur);
+ break;
default:
return false;
}
diff --git a/base/base_paths_win.h b/base/base_paths_win.h
index 6905ac6..8bb47d1ff 100644
--- a/base/base_paths_win.h
+++ b/base/base_paths_win.h
@@ -56,6 +56,9 @@ enum {
DIR_LOCAL_APP_DATA_LOW, // Local AppData directory for low integrity level.
DIR_LOCAL_APP_DATA, // "Local Settings\Application Data" directory under the
// user profile.
+ DIR_SOURCE_ROOT, // Returns the root of the source tree. This key is useful
+ // for tests that need to locate various resources. It
+ // should not be used outside of test code.
PATH_WIN_END
};
diff --git a/base/file_util.cc b/base/file_util.cc
index 234c466..4594144 100644
--- a/base/file_util.cc
+++ b/base/file_util.cc
@@ -30,7 +30,6 @@
#include "base/file_util.h"
#include <fstream>
-#include <string>
#include "base/logging.h"
#include "base/string_util.h"
@@ -40,12 +39,43 @@ namespace file_util {
const wchar_t kExtensionSeparator = L'.';
+void PathComponents(const std::wstring& path,
+ std::vector<std::wstring>* components) {
+ DCHECK(components != NULL);
+ if (components == NULL)
+ return;
+ std::wstring::size_type start = 0;
+ std::wstring::size_type end = path.find(kPathSeparator, start);
+
+ // Special case the "/" or "\" directory. On Windows with a drive letter,
+ // this code path won't hit, but the right thing should still happen.
+ // "E:\foo" will turn into "E:","foo".
+ if (end == start) {
+ components->push_back(std::wstring(path, 0, 1));
+ start = end + 1;
+ end = path.find(kPathSeparator, start);
+ }
+ while (end != std::wstring::npos) {
+ std::wstring component = std::wstring(path, start, end - start);
+ components->push_back(component);
+ start = end + 1;
+ end = path.find(kPathSeparator, start);
+ }
+ std::wstring component = std::wstring(path, start);
+ components->push_back(component);
+}
+
bool EndsWithSeparator(std::wstring* path) {
- return (!path->empty() && (*path)[path->length() - 1] == kPathSeparator);
+ return EndsWithSeparator(*path);
+}
+
+bool EndsWithSeparator(const std::wstring& path) {
+ bool is_sep = ((path)[path.length() - 1] == kPathSeparator);
+ return is_sep;
}
void TrimTrailingSeparator(std::wstring* dir) {
- while (EndsWithSeparator(dir))
+ while (dir->length() > 1 && EndsWithSeparator(dir))
dir->resize(dir->length() - 1);
}
@@ -77,9 +107,8 @@ void TrimFilename(std::wstring* path) {
}
}
-// TODO(mpcomplete): Make this platform-independent, etc.
std::wstring GetFilenameFromPath(const std::wstring& path) {
- std::wstring::size_type pos = path.find_last_of(L"\\/");
+ std::wstring::size_type pos = path.find_last_of(kPathSeparator);
return std::wstring(path, pos == std::wstring::npos ? 0 : pos+1);
}
@@ -180,6 +209,7 @@ void ReplaceIllegalCharacters(std::wstring* file_name, int replace_char) {
if (illegal_characters.contains(wstr[i])) {
(*file_name)[i] = replace_char;
}
+ ++i;
}
#else
#error wchar_t* should be either UTF-16 or UTF-32
diff --git a/base/file_util.h b/base/file_util.h
index 4aac207..e3895e3 100644
--- a/base/file_util.h
+++ b/base/file_util.h
@@ -37,10 +37,13 @@
#if defined(OS_WIN)
#include <windows.h>
+#elif defined(OS_POSIX)
+#include <fts.h>
#endif
#include <stack>
#include <string>
+#include <vector>
#include "base/basictypes.h"
@@ -55,9 +58,15 @@ extern const wchar_t kPathSeparator;
//-----------------------------------------------------------------------------
// Functions that operate purely on a path string w/o touching the filesystem:
+// Returns a vector of all of the components of the provided path.
+void PathComponents(const std::wstring& path,
+ std::vector<std::wstring>* components);
+
// Returns true if the given path ends with a path separator character.
+// TODO(erikkay): remove this pointer version
bool EndsWithSeparator(std::wstring* path);
-
+bool EndsWithSeparator(const std::wstring& path);
+
// Modifies a string by trimming all trailing separators from the end.
void TrimTrailingSeparator(std::wstring* dir);
@@ -188,6 +197,7 @@ bool ContentsEqual(const std::wstring& filename1,
// Useful for unit tests.
bool ReadFileToString(const std::wstring& path, std::string* contents);
+#if defined(OS_WINDOWS)
// Resolve Windows shortcut (.LNK file)
// Argument path specifies a valid LNK file. On success, return true and put
// the URL into path. If path is a invalid .LNK file, return false.
@@ -218,13 +228,16 @@ bool UpdateShortcutLink(const wchar_t *source, const wchar_t *destination,
const wchar_t *working_dir, const wchar_t *arguments,
const wchar_t *description, const wchar_t *icon,
int icon_index);
+#endif
+
// Get the temporary directory provided by the system.
bool GetTempDir(std::wstring* path);
-// Creates a temporary file name, but does it not create the file. It accesses
-// the disk to do this, however. The full path is placed in 'temp_file', and the
-// function returns true if was successful in creating the file name.
+// Creates a temporary file. The full path is placed in 'temp_file', and the
+// function returns true if was successful in creating the file. The file will
+// be empty and all handles closed after this function returns.
+// TODO(erikkay): rename this function and track down all of the callers.
bool CreateTemporaryFileName(std::wstring* temp_file);
// Create a new directory under TempPath. If prefix is provided, the new
@@ -275,9 +288,18 @@ class FileEnumerator {
// files in one directory will be returned before any files in a
// subdirectory.
//
- // The last parameter is an optional pattern for which files to match. This
- // works like a Windows file pattern. For example, "*.txt" or "Foo???.doc".
+ // |file_type| specifies whether the enumerator should match files,
+ // directories, or both.
+ //
+ // |pattern| is an optional pattern for which files to match. This
+ // works like shell globbing. For example, "*.txt" or "Foo???.doc".
+ // However, be careful in specifying patterns that aren't cross platform
+ // since the underlying code uses OS-specific matching routines. In general,
+ // Windows matching is less featureful than others, so test there first.
// If unspecified, this will match all files.
+ // NOTE: the pattern only matches the contents of root_path, not files in
+ // recursive subdirectories.
+ // TODO(erikkay): Fix the pattern matching to work at all levels.
FileEnumerator(const std::wstring& root_path,
bool recursive,
FileEnumerator::FILE_TYPE file_type);
@@ -307,7 +329,9 @@ class FileEnumerator {
#if defined(OS_WIN)
WIN32_FIND_DATA find_data_;
HANDLE find_handle_;
-#endif // defined(OS_WIN)
+#elif defined(OS_POSIX)
+ FTS* fts_;
+#endif
DISALLOW_EVIL_CONSTRUCTORS(FileEnumerator);
};
diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc
index 4f77e94..4f75c8a 100644
--- a/base/file_util_posix.cc
+++ b/base/file_util_posix.cc
@@ -29,10 +29,13 @@
#include "base/file_util.h"
-#include <sys/stat.h>
-#include <sys/syslimits.h>
#include <fcntl.h>
+#include <fnmatch.h>
+#include <fts.h>
#include <libgen.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <sys/syslimits.h>
#include <time.h>
#include <fstream>
@@ -44,28 +47,79 @@
namespace file_util {
std::wstring GetDirectoryFromPath(const std::wstring& path) {
- char full_path[PATH_MAX];
- base::strlcpy(full_path, WideToUTF8(path).c_str(), arraysize(full_path));
- return UTF8ToWide(dirname(full_path));
+ if (EndsWithSeparator(path)) {
+ std::wstring dir = path;
+ TrimTrailingSeparator(&dir);
+ return dir;
+ } else {
+ char full_path[PATH_MAX];
+ base::strlcpy(full_path, WideToUTF8(path).c_str(), arraysize(full_path));
+ return UTF8ToWide(dirname(full_path));
+ }
}
bool AbsolutePath(std::wstring* path) {
- return ResolveShortcut(path);
+ char full_path[PATH_MAX];
+ if (realpath(WideToUTF8(*path).c_str(), full_path) == NULL)
+ return false;
+ *path = UTF8ToWide(full_path);
+ return true;
}
+// TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*"
+// which works both with and without the recursive flag. I'm not sure we need
+// that functionality. If not, remove from file_util_win.cc, otherwise add it
+// here.
bool Delete(const std::wstring& path, bool recursive) {
- std::string utf8_path = WideToUTF8(path);
+ const char* utf8_path = WideToUTF8(path).c_str();
struct stat64 file_info;
- if (stat64(utf8_path.c_str(), &file_info) != 0);
- return false;
+ int test = stat64(utf8_path, &file_info);
+ if (test != 0) {
+ // The Windows version defines this condition as success.
+ bool ret = (errno == ENOENT || errno == ENOTDIR);
+ return ret;
+ }
if (!S_ISDIR(file_info.st_mode))
- return (unlink(utf8_path.c_str()) == 0);
+ return (unlink(utf8_path) == 0);
if (!recursive)
- return (rmdir(utf8_path.c_str()) == 0);
+ return (rmdir(utf8_path) == 0);
- // TODO(erikkay): delete directories
- DCHECK(recursive);
- return false;
+ bool success = true;
+ int ftsflags = FTS_PHYSICAL | FTS_NOSTAT;
+ char top_dir[PATH_MAX];
+ base::strlcpy(top_dir, utf8_path, sizeof(top_dir));
+ char* dir_list[2] = { top_dir, NULL };
+ FTS* fts = fts_open(dir_list, ftsflags, NULL);
+ if (fts) {
+ FTSENT* fts_ent = fts_read(fts);
+ while (success && fts_ent != NULL) {
+ switch (fts_ent->fts_info) {
+ case FTS_DNR:
+ case FTS_ERR:
+ // log error
+ success = false;
+ continue;
+ break;
+ case FTS_DP:
+ rmdir(fts_ent->fts_accpath);
+ break;
+ case FTS_D:
+ break;
+ case FTS_NSOK:
+ case FTS_F:
+ case FTS_SL:
+ case FTS_SLNONE:
+ unlink(fts_ent->fts_accpath);
+ break;
+ default:
+ DCHECK(false);
+ break;
+ }
+ fts_ent = fts_read(fts);
+ }
+ fts_close(fts);
+ }
+ return success;
}
bool Move(const std::wstring& from_path, const std::wstring& to_path) {
@@ -111,30 +165,18 @@ bool GetFileCreationLocalTime(const std::string& filename,
}
#endif
-bool ResolveShortcut(std::wstring* path) {
- char full_path[PATH_MAX];
- if (!realpath(WideToUTF8(*path).c_str(), full_path))
- return false;
- *path = UTF8ToWide(full_path);
- return true;
-}
-
-bool CreateShortcutLink(const char *source, const char *destination,
- const char *working_dir, const char *arguments,
- const char *description, const char *icon,
- int icon_index) {
- // TODO(erikkay): implement
- return false;
-}
-
bool CreateTemporaryFileName(std::wstring* temp_file) {
std::wstring tmpdir;
if (!GetTempDir(&tmpdir))
return false;
- tmpdir.append(L"/com.google.chrome.XXXXXX");
+ tmpdir.append(L"com.google.chrome.XXXXXX");
// this should be OK since mktemp just replaces characters in place
char* buffer = const_cast<char*>(WideToUTF8(tmpdir).c_str());
*temp_file = UTF8ToWide(mktemp(buffer));
+ int fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0)
+ return false;
+ close(fd);
return true;
}
@@ -154,7 +196,21 @@ bool CreateNewTempDirectory(const std::wstring& prefix,
}
bool CreateDirectory(const std::wstring& full_path) {
- return (mkdir(WideToUTF8(full_path).c_str(), 0777) == 0);
+ std::vector<std::wstring> components;
+ PathComponents(full_path, &components);
+ std::wstring path;
+ std::vector<std::wstring>::iterator i = components.begin();
+ for (; i != components.end(); ++i) {
+ if (path.length() == 0)
+ path = *i;
+ else
+ AppendToPath(&path, *i);
+ if (!PathExists(path)) {
+ if (mkdir(WideToUTF8(path).c_str(), 0777) != 0)
+ return false;
+ }
+ }
+ return true;
}
bool GetFileSize(const std::wstring& file_path, int64* file_size) {
@@ -200,96 +256,97 @@ bool SetCurrentDirectory(const std::wstring& current_directory) {
return (ret == 0);
}
-// TODO(erikkay): implement
-#if 0
-FileEnumerator::FileEnumerator(const std::string& root_path,
+FileEnumerator::FileEnumerator(const std::wstring& root_path,
bool recursive,
FileEnumerator::FILE_TYPE file_type)
: recursive_(recursive),
file_type_(file_type),
is_in_find_op_(false),
- find_handle_(INVALID_HANDLE_VALUE) {
+ fts_(NULL) {
pending_paths_.push(root_path);
}
-FileEnumerator::FileEnumerator(const std::string& root_path,
+FileEnumerator::FileEnumerator(const std::wstring& root_path,
bool recursive,
FileEnumerator::FILE_TYPE file_type,
- const std::string& pattern)
+ const std::wstring& pattern)
: recursive_(recursive),
file_type_(file_type),
+ pattern_(root_path),
is_in_find_op_(false),
- pattern_(pattern),
- find_handle_(INVALID_HANDLE_VALUE) {
+ fts_(NULL) {
+ // The Windows version of this code only matches against items in the top-most
+ // directory, and we're comparing fnmatch against full paths, so this is the
+ // easiest way to get the right pattern.
+ AppendToPath(&pattern_, pattern);
pending_paths_.push(root_path);
}
-
+
FileEnumerator::~FileEnumerator() {
- if (find_handle_ != INVALID_HANDLE_VALUE)
- FindClose(find_handle_);
+ if (fts_)
+ fts_close(fts_);
}
+// As it stands, this method calls itself recursively when the next item of
+// the fts enumeration doesn't match (type, pattern, etc.). In the case of
+// large directories with many files this can be quite deep.
+// TODO(erikkay) - get rid of this recursive pattern
std::wstring FileEnumerator::Next() {
if (!is_in_find_op_) {
if (pending_paths_.empty())
return std::wstring();
// The last find FindFirstFile operation is done, prepare a new one.
- // root_path_ must have the trailing directory character.
root_path_ = pending_paths_.top();
- file_util::AppendToPath(&root_path_, std::wstring());
+ TrimTrailingSeparator(&root_path_);
pending_paths_.pop();
// Start a new find operation.
- std::wstring src(root_path_);
-
- if (pattern_.empty())
- file_util::AppendToPath(&src, "*"); // No pattern = match everything.
- else
- file_util::AppendToPath(&src, pattern_);
-
- find_handle_ = FindFirstFile(src.c_str(), &find_data_);
+ int ftsflags = FTS_LOGICAL;
+ char top_dir[PATH_MAX];
+ base::strlcpy(top_dir, WideToUTF8(root_path_).c_str(), sizeof(top_dir));
+ char* dir_list[2] = { top_dir, NULL };
+ fts_ = fts_open(dir_list, ftsflags, NULL);
+ if (!fts_)
+ return Next();
is_in_find_op_ = true;
-
- } else {
- // Search for the next file/directory.
- if (!FindNextFile(find_handle_, &find_data_)) {
- FindClose(find_handle_);
- find_handle_ = INVALID_HANDLE_VALUE;
- }
}
- if (INVALID_HANDLE_VALUE == find_handle_) {
+ FTSENT* fts_ent = fts_read(fts_);
+ if (fts_ent == NULL) {
+ fts_close(fts_);
+ fts_ = NULL;
is_in_find_op_ = false;
-
- // This is reached when we have finished a directory and are advancing to
- // the next one in the queue. We applied the pattern (if any) to the files
- // in the root search directory, but for those directories which were
- // matched, we want to enumerate all files inside them. This will happen
- // when the handle is empty.
- pattern_.clear();
-
return Next();
}
- std::wstring cur_file(find_data_.cFileName);
- // Skip over . and ..
- if (L"." == cur_file || L".." == cur_file)
+ // Level 0 is the top, which is always skipped.
+ if (fts_ent->fts_level == 0)
return Next();
- // Construct the absolute filename.
- cur_file.insert(0, root_path_);
+ // Patterns are only matched on the items in the top-most directory.
+ // (see Windows implementation)
+ if (fts_ent->fts_level == 1 && pattern_.length() > 0) {
+ const char* utf8_pattern = WideToUTF8(pattern_).c_str();
+ if (fnmatch(utf8_pattern, fts_ent->fts_path, 0) != 0) {
+ if (fts_ent->fts_info == FTS_D)
+ fts_set(fts_, fts_ent, FTS_SKIP);
+ return Next();
+ }
+ }
- if (recursive_ && find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- // If |cur_file| is a directory, and we are doing recursive searching, add
- // it to pending_paths_ so we scan it after we finish scanning this
- // directory.
- pending_paths_.push(cur_file);
+ std::wstring cur_file(UTF8ToWide(fts_ent->fts_path));
+ if (fts_ent->fts_info == FTS_D) {
+ // If not recursive, then prune children.
+ if (!recursive_)
+ fts_set(fts_, fts_ent, FTS_SKIP);
return (file_type_ & FileEnumerator::DIRECTORIES) ? cur_file : Next();
+ } else if (fts_ent->fts_info == FTS_F) {
+ return (file_type_ & FileEnumerator::FILES) ? cur_file : Next();
}
- return (file_type_ & FileEnumerator::FILES) ? cur_file : Next();
+ // TODO(erikkay) - verify that the other fts_info types aren't interesting
+ return Next();
}
-#endif
} // namespace file_util
diff --git a/base/file_util_unittest.cc b/base/file_util_unittest.cc
index f82a894..6ff6ef0 100644
--- a/base/file_util_unittest.cc
+++ b/base/file_util_unittest.cc
@@ -27,13 +27,15 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#if defined(OS_WINDOWS)
#include <windows.h>
-#include <set>
#include <shellapi.h>
#include <shlobj.h>
+#endif
#include <fstream>
#include <iostream>
+#include <set>
#include "base/base_paths.h"
#include "base/file_util.h"
@@ -53,11 +55,11 @@ class FileUtilTest : public testing::Test {
// Create a fresh, empty copy of this directory.
file_util::Delete(test_dir_, true);
- CreateDirectory(test_dir_.c_str(), NULL);
+ file_util::CreateDirectory(test_dir_.c_str());
}
virtual void TearDown() {
// Clean up test directory
- ASSERT_TRUE(file_util::Delete(test_dir_, false));
+ ASSERT_TRUE(file_util::Delete(test_dir_, true));
ASSERT_FALSE(file_util::PathExists(test_dir_));
}
@@ -85,6 +87,10 @@ class FindResultCollector {
bool HasFile(const std::wstring& file) const {
return files_.find(file) != files_.end();
}
+
+ int size() {
+ return files_.size();
+ }
private:
std::set<std::wstring> files_;
@@ -94,7 +100,7 @@ class FindResultCollector {
void CreateTextFile(const std::wstring& filename,
const std::wstring& contents) {
std::ofstream file;
- file.open(filename.c_str());
+ file.open(WideToUTF8(filename).c_str());
ASSERT_TRUE(file.is_open());
file << contents;
file.close();
@@ -102,27 +108,30 @@ void CreateTextFile(const std::wstring& filename,
// Simple function to take out some text from a file.
std::wstring ReadTextFile(const std::wstring& filename) {
- WCHAR contents[64];
+ wchar_t contents[64];
std::wifstream file;
- file.open(filename.c_str());
+ file.open(WideToUTF8(filename).c_str());
EXPECT_TRUE(file.is_open());
file.getline(contents, 64);
file.close();
return std::wstring(contents);
}
+#if defined OS_WINDOWS
uint64 FileTimeAsUint64(const FILETIME& ft) {
ULARGE_INTEGER u;
u.LowPart = ft.dwLowDateTime;
u.HighPart = ft.dwHighDateTime;
return u.QuadPart;
}
+#endif
const struct append_case {
const wchar_t* path;
const wchar_t* ending;
const wchar_t* result;
} append_cases[] = {
+#if defined(OS_WINDOWS)
{L"c:\\colon\\backslash", L"path", L"c:\\colon\\backslash\\path"},
{L"c:\\colon\\backslash\\", L"path", L"c:\\colon\\backslash\\path"},
{L"c:\\colon\\backslash\\\\", L"path", L"c:\\colon\\backslash\\\\path"},
@@ -130,12 +139,21 @@ const struct append_case {
{L"c:\\colon\\backslash", L"", L"c:\\colon\\backslash\\"},
{L"", L"path", L"\\path"},
{L"", L"", L"\\"},
+#elif defined(OS_POSIX)
+ {L"/foo/bar", L"path", L"/foo/bar/path"},
+ {L"/foo/bar/", L"path", L"/foo/bar/path"},
+ {L"/foo/bar//", L"path", L"/foo/bar//path"},
+ {L"/foo/bar/", L"", L"/foo/bar/"},
+ {L"/foo/bar", L"", L"/foo/bar/"},
+ {L"", L"path", L"/path"},
+ {L"", L"", L"/"},
+#endif
};
} // namespace
TEST_F(FileUtilTest, AppendToPath) {
- for (int i = 0; i < arraysize(append_cases); ++i) {
+ for (unsigned int i = 0; i < arraysize(append_cases); ++i) {
const append_case& value = append_cases[i];
std::wstring result = value.path;
file_util::AppendToPath(&result, value.ending);
@@ -168,6 +186,7 @@ static const struct InsertBeforeExtensionCase {
{L"foo", L".", L"foo."},
{L"foo.baz.dll", L"", L"foo.baz.dll"},
{L"foo.baz.dll", L".", L"foo.baz..dll"},
+#if defined(OS_WINDOWS)
{L"\\", L"", L"\\"},
{L"\\", L"txt", L"\\txt"},
{L"\\.", L"txt", L"\\txt."},
@@ -180,10 +199,24 @@ static const struct InsertBeforeExtensionCase {
{L"C:\\bar.baz\\foo.exe", L"", L"C:\\bar.baz\\foo.exe"},
{L"C:\\bar.baz\\foo.dll.exe", L"", L"C:\\bar.baz\\foo.dll.exe"},
{L"C:\\bar\\baz\\foo.exe", L" (1)", L"C:\\bar\\baz\\foo (1).exe"},
+#elif defined(OS_POSIX)
+ {L"/", L"", L"/"},
+ {L"/", L"txt", L"/txt"},
+ {L"/.", L"txt", L"/txt."},
+ {L"/.", L"", L"/."},
+ {L"/bar/foo.dll", L"txt", L"/bar/footxt.dll"},
+ {L"/bar.baz/foodll", L"txt", L"/bar.baz/foodlltxt"},
+ {L"/bar.baz/foo.dll", L"txt", L"/bar.baz/footxt.dll"},
+ {L"/bar.baz/foo.dll.exe", L"txt", L"/bar.baz/foo.dlltxt.exe"},
+ {L"/bar.baz/foo", L"", L"/bar.baz/foo"},
+ {L"/bar.baz/foo.exe", L"", L"/bar.baz/foo.exe"},
+ {L"/bar.baz/foo.dll.exe", L"", L"/bar.baz/foo.dll.exe"},
+ {L"/bar/baz/foo.exe", L" (1)", L"/bar/baz/foo (1).exe"},
+#endif
};
TEST_F(FileUtilTest, InsertBeforeExtensionTest) {
- for (int i = 0; i < arraysize(kInsertBeforeExtension); ++i) {
+ for (unsigned int i = 0; i < arraysize(kInsertBeforeExtension); ++i) {
std::wstring path(kInsertBeforeExtension[i].path);
file_util::InsertBeforeExtension(&path, kInsertBeforeExtension[i].suffix);
EXPECT_EQ(path, kInsertBeforeExtension[i].result);
@@ -194,6 +227,7 @@ static const struct filename_case {
const wchar_t* path;
const wchar_t* filename;
} filename_cases[] = {
+#if defined(OS_WINDOWS)
{L"c:\\colon\\backslash", L"backslash"},
{L"c:\\colon\\backslash\\", L""},
{L"\\\\filename.exe", L"filename.exe"},
@@ -204,10 +238,18 @@ static const struct filename_case {
{L"c:/colon/backslash/", L""},
{L"//////", L""},
{L"///filename.exe", L"filename.exe"},
+#elif defined(OS_POSIX)
+ {L"/foo/bar", L"bar"},
+ {L"/foo/bar/", L""},
+ {L"/filename.exe", L"filename.exe"},
+ {L"filename.exe", L"filename.exe"},
+ {L"", L""},
+ {L"/", L""},
+#endif
};
TEST_F(FileUtilTest, GetFilenameFromPath) {
- for (int i = 0; i < arraysize(filename_cases); ++i) {
+ for (unsigned int i = 0; i < arraysize(filename_cases); ++i) {
const filename_case& value = filename_cases[i];
std::wstring result = file_util::GetFilenameFromPath(value.path);
EXPECT_EQ(value.filename, result);
@@ -219,16 +261,30 @@ static const struct extension_case {
const wchar_t* path;
const wchar_t* extension;
} extension_cases[] = {
+#if defined(OS_WINDOWS)
{L"C:\\colon\\backslash\\filename.extension", L"extension"},
{L"C:\\colon\\backslash\\filename.", L""},
{L"C:\\colon\\backslash\\filename", L""},
{L"C:\\colon\\backslash\\", L""},
{L"C:\\colon\\backslash.\\", L""},
{L"C:\\colon\\backslash\filename.extension.extension2", L"extension2"},
+#elif defined(OS_POSIX)
+ {L"/foo/bar/filename.extension", L"extension"},
+ {L"/foo/bar/filename.", L""},
+ {L"/foo/bar/filename", L""},
+ {L"/foo/bar/", L""},
+ {L"/foo/bar./", L""},
+ {L"/foo/bar/filename.extension.extension2", L"extension2"},
+ {L".", L""},
+ {L"..", L""},
+ {L"./foo", L""},
+ {L"./foo.extension", L"extension"},
+ {L"/foo.extension1/bar.extension2", L"extension2"},
+#endif
};
TEST_F(FileUtilTest, GetFileExtensionFromPath) {
- for (int i = 0; i < arraysize(extension_cases); ++i) {
+ for (unsigned int i = 0; i < arraysize(extension_cases); ++i) {
const extension_case& ext = extension_cases[i];
const std::wstring fext = file_util::GetFileExtensionFromPath(ext.path);
EXPECT_EQ(ext.extension, fext);
@@ -240,6 +296,7 @@ static const struct dir_case {
const wchar_t* full_path;
const wchar_t* directory;
} dir_cases[] = {
+#if defined(OS_WINDOWS)
{L"C:\\WINDOWS\\system32\\gdi32.dll", L"C:\\WINDOWS\\system32"},
{L"C:\\WINDOWS\\system32\\not_exist_thx_1138", L"C:\\WINDOWS\\system32"},
{L"C:\\WINDOWS\\system32\\", L"C:\\WINDOWS\\system32"},
@@ -247,10 +304,21 @@ static const struct dir_case {
{L"C:\\WINDOWS\\system32", L"C:\\WINDOWS"},
{L"C:\\WINDOWS\\system32.\\", L"C:\\WINDOWS\\system32."},
{L"C:\\", L"C:"},
+#elif defined(OS_POSIX)
+ {L"/foo/bar/gdi32.dll", L"/foo/bar"},
+ {L"/foo/bar/not_exist_thx_1138", L"/foo/bar"},
+ {L"/foo/bar/", L"/foo/bar"},
+ {L"/foo/bar//", L"/foo/bar"},
+ {L"/foo/bar", L"/foo"},
+ {L"/foo/bar./", L"/foo/bar."},
+ {L"/", L"/"},
+ {L".", L"."},
+ {L"..", L"."}, // yes, ".." technically lives in "."
+#endif
};
TEST_F(FileUtilTest, GetDirectoryFromPath) {
- for (int i = 0; i < arraysize(dir_cases); ++i) {
+ for (unsigned int i = 0; i < arraysize(dir_cases); ++i) {
const dir_case& dir = dir_cases[i];
const std::wstring parent =
file_util::GetDirectoryFromPath(dir.full_path);
@@ -258,6 +326,8 @@ TEST_F(FileUtilTest, GetDirectoryFromPath) {
}
}
+// TODO(erikkay): implement
+#if defined OS_WINDOWS
TEST_F(FileUtilTest, CountFilesCreatedAfter) {
// Create old file (that we don't want to count)
std::wstring old_file_name = test_dir_;
@@ -284,6 +354,7 @@ TEST_F(FileUtilTest, CountFilesCreatedAfter) {
EXPECT_TRUE(file_util::Delete(new_file_name, false));
EXPECT_EQ(0, file_util::CountFilesCreatedAfter(test_dir_, test_start_time));
}
+#endif
// Tests that the Delete function works as expected, especially
// the recursion flag. Also coincidentally tests PathExists.
@@ -297,29 +368,32 @@ TEST_F(FileUtilTest, Delete) {
std::wstring subdir_path = test_dir_;
file_util::AppendToPath(&subdir_path, L"Subdirectory");
- CreateDirectory(subdir_path.c_str(), NULL);
+ file_util::CreateDirectory(subdir_path.c_str());
ASSERT_TRUE(file_util::PathExists(subdir_path));
std::wstring directory_contents = test_dir_;
+#if defined(OS_WINDOWS)
+ // TODO(erikkay): see if anyone's actually using this feature of the API
file_util::AppendToPath(&directory_contents, L"*");
// Delete non-recursively and check that only the file is deleted
ASSERT_TRUE(file_util::Delete(directory_contents, false));
- ASSERT_FALSE(file_util::PathExists(file_name));
- ASSERT_TRUE(file_util::PathExists(subdir_path));
+ EXPECT_FALSE(file_util::PathExists(file_name));
+ EXPECT_TRUE(file_util::PathExists(subdir_path));
+#endif
// Delete recursively and make sure all contents are deleted
ASSERT_TRUE(file_util::Delete(directory_contents, true));
- ASSERT_FALSE(file_util::PathExists(file_name));
- ASSERT_FALSE(file_util::PathExists(subdir_path));
+ EXPECT_FALSE(file_util::PathExists(file_name));
+ EXPECT_FALSE(file_util::PathExists(subdir_path));
}
TEST_F(FileUtilTest, Move) {
// Create a directory
std::wstring dir_name_from(test_dir_);
file_util::AppendToPath(&dir_name_from, L"Move_From_Subdir");
- CreateDirectory(dir_name_from.c_str(), NULL);
+ file_util::CreateDirectory(dir_name_from.c_str());
ASSERT_TRUE(file_util::PathExists(dir_name_from));
// Create a file under the directory
@@ -345,11 +419,13 @@ TEST_F(FileUtilTest, Move) {
EXPECT_TRUE(file_util::PathExists(file_name_to));
}
+// TODO(erikkay): implement
+#if defined(OS_WINDOWS)
TEST_F(FileUtilTest, CopyDirectoryRecursively) {
// Create a directory.
std::wstring dir_name_from(test_dir_);
file_util::AppendToPath(&dir_name_from, L"Copy_From_Subdir");
- CreateDirectory(dir_name_from.c_str(), NULL);
+ file_util::CreateDirectory(dir_name_from.c_str());
ASSERT_TRUE(file_util::PathExists(dir_name_from));
// Create a file under the directory.
@@ -361,7 +437,7 @@ TEST_F(FileUtilTest, CopyDirectoryRecursively) {
// Create a subdirectory.
std::wstring subdir_name_from(dir_name_from);
file_util::AppendToPath(&subdir_name_from, L"Subdir");
- CreateDirectory(subdir_name_from.c_str(), NULL);
+ file_util::CreateDirectory(subdir_name_from.c_str());
ASSERT_TRUE(file_util::PathExists(subdir_name_from));
// Create a file under the subdirectory.
@@ -399,7 +475,7 @@ TEST_F(FileUtilTest, CopyDirectory) {
// Create a directory.
std::wstring dir_name_from(test_dir_);
file_util::AppendToPath(&dir_name_from, L"Copy_From_Subdir");
- CreateDirectory(dir_name_from.c_str(), NULL);
+ file_util::CreateDirectory(dir_name_from.c_str());
ASSERT_TRUE(file_util::PathExists(dir_name_from));
// Create a file under the directory.
@@ -411,7 +487,7 @@ TEST_F(FileUtilTest, CopyDirectory) {
// Create a subdirectory.
std::wstring subdir_name_from(dir_name_from);
file_util::AppendToPath(&subdir_name_from, L"Subdir");
- CreateDirectory(subdir_name_from.c_str(), NULL);
+ file_util::CreateDirectory(subdir_name_from.c_str());
ASSERT_TRUE(file_util::PathExists(subdir_name_from));
// Create a file under the subdirectory.
@@ -441,12 +517,13 @@ TEST_F(FileUtilTest, CopyDirectory) {
EXPECT_TRUE(file_util::PathExists(file_name_to));
EXPECT_FALSE(file_util::PathExists(subdir_name_to));
}
+#endif
TEST_F(FileUtilTest, CopyFile) {
// Create a directory
std::wstring dir_name_from(test_dir_);
file_util::AppendToPath(&dir_name_from, L"Copy_From_Subdir");
- CreateDirectory(dir_name_from.c_str(), NULL);
+ file_util::CreateDirectory(dir_name_from.c_str());
ASSERT_TRUE(file_util::PathExists(dir_name_from));
// Create a file under the directory
@@ -460,14 +537,27 @@ TEST_F(FileUtilTest, CopyFile) {
std::wstring dest_file(dir_name_from);
file_util::AppendToPath(&dest_file, L"DestFile.txt");
ASSERT_TRUE(file_util::CopyFile(file_name_from, dest_file));
+
+ // Copy the file to another location using '..' in the path.
+ std::wstring dest_file2(dir_name_from);
+ file_util::AppendToPath(&dest_file2, L"..");
+ file_util::AppendToPath(&dest_file2, L"DestFile.txt");
+ ASSERT_TRUE(file_util::CopyFile(file_name_from, dest_file2));
+ std::wstring dest_file2_test(dir_name_from);
+ file_util::UpOneDirectory(&dest_file2_test);
+ file_util::AppendToPath(&dest_file2_test, L"DestFile.txt");
// Check everything has been copied.
EXPECT_TRUE(file_util::PathExists(file_name_from));
EXPECT_TRUE(file_util::PathExists(dest_file));
const std::wstring read_contents = ReadTextFile(dest_file);
EXPECT_EQ(file_contents, read_contents);
+ EXPECT_TRUE(file_util::PathExists(dest_file2_test));
+ EXPECT_TRUE(file_util::PathExists(dest_file2));
}
+// TODO(erikkay): implement
+#if defined(OS_WINDOWS)
TEST_F(FileUtilTest, GetFileCreationLocalTime) {
std::wstring file_name = test_dir_;
file_util::AppendToPath(&file_name, L"Test File.txt");
@@ -500,6 +590,7 @@ TEST_F(FileUtilTest, GetFileCreationLocalTime) {
ASSERT_TRUE(DeleteFile(file_name.c_str()));
}
+#endif
typedef testing::Test ReadOnlyFileUtilTest;
@@ -550,6 +641,8 @@ TEST(ReadOnlyFileUtilTest, ContentsEqual) {
EXPECT_FALSE(file_util::ContentsEqual(binary_file, binary_file_diff));
}
+// We don't need equivalent functionality outside of Windows.
+#if defined(OS_WINDOWS)
TEST_F(FileUtilTest, ResolveShortcutTest) {
std::wstring target_file = test_dir_;
file_util::AppendToPath(&target_file, L"Target.txt");
@@ -617,25 +710,32 @@ TEST_F(FileUtilTest, CreateShortcutTest) {
DeleteFile(link_file.c_str());
CoUninitialize();
}
+#endif
TEST_F(FileUtilTest, CreateTemporaryFileNameTest) {
std::wstring temp_file;
file_util::CreateTemporaryFileName(&temp_file);
EXPECT_EQ(file_util::PathExists(temp_file), true);
+ EXPECT_EQ(file_util::Delete(temp_file, false), true);
}
TEST_F(FileUtilTest, CreateNewTempDirectoryTest) {
std::wstring temp_dir;
file_util::CreateNewTempDirectory(std::wstring(), &temp_dir);
EXPECT_EQ(file_util::PathExists(temp_dir), true);
+ EXPECT_EQ(file_util::Delete(temp_dir, false), true);
}
TEST_F(FileUtilTest, CreateDirectoryTest) {
std::wstring test_root = test_dir_;
file_util::AppendToPath(&test_root, L"create_directory_test");
std::wstring test_path(test_root);
+#if defined(OS_WINDOWS)
file_util::AppendToPath(&test_path, L"dir\\tree\\likely\\doesnt\\exist\\");
-
+#elif defined(OS_POSIX)
+ file_util::AppendToPath(&test_path, L"dir/tree/likely/doesnt/exist/");
+#endif
+
EXPECT_EQ(file_util::PathExists(test_path), false);
EXPECT_EQ(file_util::CreateDirectory(test_path), true);
EXPECT_EQ(file_util::PathExists(test_path), true);
@@ -644,18 +744,24 @@ TEST_F(FileUtilTest, CreateDirectoryTest) {
EXPECT_EQ(file_util::PathExists(test_path), false);
}
-static const struct {
+static const struct goodbad_pair {
std::wstring bad_name;
std::wstring good_name;
} kIllegalCharacterCases[] = {
{L"bad*file:name?.jpg", L"bad-file-name-.jpg"},
{L"**********::::.txt", L"--------------.txt"},
- {L"bad*file\\name.jpg", L"bad-file-name.jpg"},
// We can't use UCNs (universal character names) for C0/C1 characters and
// U+007F, but \x escape is interpreted by MSVC and gcc as we intend.
{L"bad\x0003\x0091 file\u200E\u200Fname.png", L"bad-- file--name.png"},
+#if defined(OS_WINDOWS)
+ {L"bad*file\\name.jpg", L"bad-file-name.jpg"},
{L"\t bad*file\\name/.jpg ", L"bad-file-name-.jpg"},
{L"bad\uFFFFfile\U0010FFFEname.jpg ", L"bad-file-name.jpg"},
+#elif defined(OS_POSIX)
+ {L"bad*file?name.jpg", L"bad-file-name.jpg"},
+ {L"\t bad*file?name/.jpg ", L"bad-file-name-.jpg"},
+ {L"bad\uFFFFfile-name.jpg ", L"bad-file-name.jpg"},
+#endif
{L"this_file_name is okay!.mp3", L"this_file_name is okay!.mp3"},
{L"\u4E00\uAC00.mp3", L"\u4E00\uAC00.mp3"},
{L"\u0635\u200C\u0644.mp3", L"\u0635\u200C\u0644.mp3"},
@@ -665,7 +771,7 @@ static const struct {
};
TEST_F(FileUtilTest, ReplaceIllegalCharactersTest) {
- for (int i = 0; i < arraysize(kIllegalCharacterCases); ++i) {
+ for (unsigned int i = 0; i < arraysize(kIllegalCharacterCases); ++i) {
std::wstring bad_name(kIllegalCharacterCases[i].bad_name);
file_util::ReplaceIllegalCharacters(&bad_name, L'-');
EXPECT_EQ(kIllegalCharacterCases[i].good_name, bad_name);
@@ -696,7 +802,7 @@ static const struct ReplaceExtensionCase {
};
TEST_F(FileUtilTest, ReplaceExtensionTest) {
- for (int i = 0; i < arraysize(kReplaceExtension); ++i) {
+ for (unsigned int i = 0; i < arraysize(kReplaceExtension); ++i) {
std::wstring file_name(kReplaceExtension[i].file_name);
file_util::ReplaceExtension(&file_name, kReplaceExtension[i].extension);
EXPECT_EQ(file_name, kReplaceExtension[i].result);
@@ -710,63 +816,86 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
EXPECT_EQ(f0.Next(), L"");
EXPECT_EQ(f0.Next(), L"");
- // Populate the test dir.
- file_util::CreateDirectory(test_dir_ + L"\\dir1");
- file_util::CreateDirectory(test_dir_ + L"\\dir2");
- CreateTextFile(test_dir_ + L"\\dir2\\dir2file.txt", L"");
- file_util::CreateDirectory(test_dir_ + L"\\dir2\\inner");
- CreateTextFile(test_dir_ + L"\\dir2\\inner\\innerfile.txt", L"");
- CreateTextFile(test_dir_ + L"\\file1.txt", L"");
- CreateTextFile(test_dir_ + L"\\file2.txt", L"");
+ // create the directories
+ std::wstring dir1 = test_dir_;
+ file_util::AppendToPath(&dir1, L"dir1");
+ EXPECT_TRUE(file_util::CreateDirectory(dir1));
+ std::wstring dir2 = test_dir_;
+ file_util::AppendToPath(&dir2, L"dir2");
+ EXPECT_TRUE(file_util::CreateDirectory(dir2));
+ std::wstring dir2inner = dir2;
+ file_util::AppendToPath(&dir2inner, L"inner");
+ EXPECT_TRUE(file_util::CreateDirectory(dir2inner));
+
+ // create the files
+ std::wstring dir2file = dir2;
+ file_util::AppendToPath(&dir2file, L"dir2file.txt");
+ CreateTextFile(dir2file, L"");
+ std::wstring dir2innerfile = dir2inner;
+ file_util::AppendToPath(&dir2innerfile, L"innerfile.txt");
+ CreateTextFile(dir2innerfile, L"");
+ std::wstring file1 = test_dir_;
+ file_util::AppendToPath(&file1, L"file1.txt");
+ CreateTextFile(file1, L"");
+ std::wstring file2_rel = dir2;
+ file_util::AppendToPath(&file2_rel, L"..");
+ file_util::AppendToPath(&file2_rel, L"file2.txt");
+ CreateTextFile(file2_rel, L"");
+ std::wstring file2_abs = test_dir_;
+ file_util::AppendToPath(&file2_abs, L"file2.txt");
// Only enumerate files.
file_util::FileEnumerator f1(test_dir_, true,
file_util::FileEnumerator::FILES);
FindResultCollector c1(f1);
- EXPECT_TRUE(c1.HasFile(test_dir_ + L"\\file1.txt"));
- EXPECT_TRUE(c1.HasFile(test_dir_ + L"\\file2.txt"));
- EXPECT_TRUE(c1.HasFile(test_dir_ + L"\\dir2\\dir2file.txt"));
- EXPECT_TRUE(c1.HasFile(test_dir_ + L"\\dir2\\inner\\innerfile.txt"));
+ EXPECT_TRUE(c1.HasFile(file1));
+ EXPECT_TRUE(c1.HasFile(file2_abs));
+ EXPECT_TRUE(c1.HasFile(dir2file));
+ EXPECT_TRUE(c1.HasFile(dir2innerfile));
+ EXPECT_EQ(c1.size(), 4);
// Only enumerate directories.
file_util::FileEnumerator f2(test_dir_, true,
file_util::FileEnumerator::DIRECTORIES);
FindResultCollector c2(f2);
- EXPECT_TRUE(c2.HasFile(test_dir_ + L"\\dir1"));
- EXPECT_TRUE(c2.HasFile(test_dir_ + L"\\dir2"));
- EXPECT_TRUE(c2.HasFile(test_dir_ + L"\\dir2\\inner"));
+ EXPECT_TRUE(c2.HasFile(dir1));
+ EXPECT_TRUE(c2.HasFile(dir2));
+ EXPECT_TRUE(c2.HasFile(dir2inner));
+ EXPECT_EQ(c2.size(), 3);
// Enumerate files and directories.
file_util::FileEnumerator f3(test_dir_, true,
file_util::FileEnumerator::FILES_AND_DIRECTORIES);
FindResultCollector c3(f3);
- EXPECT_TRUE(c3.HasFile(test_dir_ + L"\\dir1"));
- EXPECT_TRUE(c3.HasFile(test_dir_ + L"\\dir2"));
- EXPECT_TRUE(c3.HasFile(test_dir_ + L"\\file1.txt"));
- EXPECT_TRUE(c3.HasFile(test_dir_ + L"\\file2.txt"));
- EXPECT_TRUE(c3.HasFile(test_dir_ + L"\\dir2\\dir2file.txt"));
- EXPECT_TRUE(c3.HasFile(test_dir_ + L"\\dir2\\dir2file.txt"));
- EXPECT_TRUE(c3.HasFile(test_dir_ + L"\\dir2\\inner"));
- EXPECT_TRUE(c3.HasFile(test_dir_ + L"\\dir2\\inner\\innerfile.txt"));
+ EXPECT_TRUE(c3.HasFile(dir1));
+ EXPECT_TRUE(c3.HasFile(dir2));
+ EXPECT_TRUE(c3.HasFile(file1));
+ EXPECT_TRUE(c3.HasFile(file2_abs));
+ EXPECT_TRUE(c3.HasFile(dir2file));
+ EXPECT_TRUE(c3.HasFile(dir2inner));
+ EXPECT_TRUE(c3.HasFile(dir2innerfile));
+ EXPECT_EQ(c3.size(), 7);
// Non-recursive operation.
file_util::FileEnumerator f4(test_dir_, false,
file_util::FileEnumerator::FILES_AND_DIRECTORIES);
FindResultCollector c4(f4);
- EXPECT_TRUE(c4.HasFile(test_dir_ + L"\\dir1"));
- EXPECT_TRUE(c4.HasFile(test_dir_ + L"\\dir2"));
- EXPECT_TRUE(c4.HasFile(test_dir_ + L"\\file1.txt"));
- EXPECT_TRUE(c4.HasFile(test_dir_ + L"\\file2.txt"));
+ EXPECT_TRUE(c4.HasFile(dir2));
+ EXPECT_TRUE(c4.HasFile(dir2));
+ EXPECT_TRUE(c4.HasFile(file1));
+ EXPECT_TRUE(c4.HasFile(file2_abs));
+ EXPECT_EQ(c4.size(), 4);
// Enumerate with a pattern.
file_util::FileEnumerator f5(test_dir_, true,
file_util::FileEnumerator::FILES_AND_DIRECTORIES, L"dir*");
FindResultCollector c5(f5);
- EXPECT_TRUE(c5.HasFile(test_dir_ + L"\\dir1"));
- EXPECT_TRUE(c5.HasFile(test_dir_ + L"\\dir2"));
- EXPECT_TRUE(c5.HasFile(test_dir_ + L"\\dir2\\dir2file.txt"));
- EXPECT_TRUE(c5.HasFile(test_dir_ + L"\\dir2\\inner"));
- EXPECT_TRUE(c5.HasFile(test_dir_ + L"\\dir2\\inner\\innerfile.txt"));
+ EXPECT_TRUE(c5.HasFile(dir1));
+ EXPECT_TRUE(c5.HasFile(dir2));
+ EXPECT_TRUE(c5.HasFile(dir2file));
+ EXPECT_TRUE(c5.HasFile(dir2inner));
+ EXPECT_TRUE(c5.HasFile(dir2innerfile));
+ EXPECT_EQ(c5.size(), 5);
// Make sure the destructor closes the find handle while in the middle of a
// query to allow TearDown to delete the directory.