1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "base/file_util.h"
31
32 #ifdef OS_WIN
33 #include <Windows.h>
34 #endif // OS_WIN
35
36 #include <fstream>
37 #include <string>
38
39 #include "base/file_stream.h"
40 #include "base/logging.h"
41 #include "base/util.h"
42 #include "testing/base/public/gunit.h"
43
44 // Ad-hoc workadound against macro problem on Windows.
45 // On Windows, following macros, defined when you include <Windows.h>,
46 // should be removed here because they affects the method name definition of
47 // Util class.
48 // TODO(yukawa): Use different method name if applicable.
49 #ifdef CreateDirectory
50 #undef CreateDirectory
51 #endif // CreateDirectory
52 #ifdef RemoveDirectory
53 #undef RemoveDirectory
54 #endif // RemoveDirectory
55 #ifdef CopyFile
56 #undef CopyFile
57 #endif // CopyFile
58
59 DECLARE_string(test_srcdir);
60 DECLARE_string(test_tmpdir);
61
62 namespace mozc {
63
64 class FileUtilTest : public testing::Test {
65 };
66
67 namespace {
CreateTestFile(const string & filename,const string & data)68 void CreateTestFile(const string &filename, const string &data) {
69 OutputFileStream ofs(filename.c_str(), std::ios::binary | std::ios::trunc);
70 ofs << data;
71 EXPECT_TRUE(ofs.good());
72 }
73 } // namespace
74
TEST_F(FileUtilTest,CreateDirectory)75 TEST_F(FileUtilTest, CreateDirectory) {
76 EXPECT_TRUE(FileUtil::DirectoryExists(FLAGS_test_tmpdir));
77 // dirpath = FLAGS_test_tmpdir/testdir
78 const string dirpath = FileUtil::JoinPath(FLAGS_test_tmpdir, "testdir");
79
80 // Delete dirpath, if it exists.
81 if (FileUtil::FileExists(dirpath)) {
82 FileUtil::RemoveDirectory(dirpath);
83 }
84 ASSERT_FALSE(FileUtil::FileExists(dirpath));
85
86 // Create the directory.
87 EXPECT_TRUE(FileUtil::CreateDirectory(dirpath));
88 EXPECT_TRUE(FileUtil::DirectoryExists(dirpath));
89
90 // Delete the directory.
91 ASSERT_TRUE(FileUtil::RemoveDirectory(dirpath));
92 ASSERT_FALSE(FileUtil::FileExists(dirpath));
93 }
94
TEST_F(FileUtilTest,DirectoryExists)95 TEST_F(FileUtilTest, DirectoryExists) {
96 EXPECT_TRUE(FileUtil::DirectoryExists(FLAGS_test_tmpdir));
97 const string filepath = FileUtil::JoinPath(FLAGS_test_tmpdir, "testfile");
98
99 // Delete filepath, if it exists.
100 if (FileUtil::FileExists(filepath)) {
101 FileUtil::Unlink(filepath);
102 }
103 ASSERT_FALSE(FileUtil::FileExists(filepath));
104
105 // Create a file.
106 CreateTestFile(filepath, "test data");
107 EXPECT_TRUE(FileUtil::FileExists(filepath));
108 EXPECT_FALSE(FileUtil::DirectoryExists(filepath));
109
110 // Delete the file.
111 FileUtil::Unlink(filepath);
112 ASSERT_FALSE(FileUtil::FileExists(filepath));
113 }
114
TEST_F(FileUtilTest,Unlink)115 TEST_F(FileUtilTest, Unlink) {
116 const string filepath = FileUtil::JoinPath(FLAGS_test_tmpdir, "testfile");
117 FileUtil::Unlink(filepath);
118 EXPECT_FALSE(FileUtil::FileExists(filepath));
119
120 CreateTestFile(filepath, "simple test");
121 EXPECT_TRUE(FileUtil::FileExists(filepath));
122 EXPECT_TRUE(FileUtil::Unlink(filepath));
123 EXPECT_FALSE(FileUtil::FileExists(filepath));
124
125 #ifdef OS_WIN
126 const DWORD kTestAttributeList[] = {
127 FILE_ATTRIBUTE_ARCHIVE,
128 FILE_ATTRIBUTE_HIDDEN,
129 FILE_ATTRIBUTE_NORMAL,
130 FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
131 FILE_ATTRIBUTE_OFFLINE,
132 FILE_ATTRIBUTE_READONLY,
133 FILE_ATTRIBUTE_SYSTEM,
134 FILE_ATTRIBUTE_TEMPORARY,
135 };
136
137 std::wstring wfilepath;
138 Util::UTF8ToWide(filepath, &wfilepath);
139 for (size_t i = 0; i < arraysize(kTestAttributeList); ++i) {
140 SCOPED_TRACE(Util::StringPrintf("AttributeTest %zd", i));
141 CreateTestFile(filepath, "attribute_test");
142 EXPECT_NE(FALSE,
143 ::SetFileAttributesW(wfilepath.c_str(), kTestAttributeList[i]));
144 EXPECT_TRUE(FileUtil::FileExists(filepath));
145 EXPECT_TRUE(FileUtil::Unlink(filepath));
146 EXPECT_FALSE(FileUtil::FileExists(filepath));
147 }
148 #endif // OS_WIN
149
150 FileUtil::Unlink(filepath);
151 }
152
153 #ifdef OS_WIN
TEST_F(FileUtilTest,HideFile)154 TEST_F(FileUtilTest, HideFile) {
155 const string filename = FileUtil::JoinPath(FLAGS_test_tmpdir, "testfile");
156 FileUtil::Unlink(filename);
157
158 EXPECT_FALSE(FileUtil::HideFile(filename));
159
160 std::wstring wfilename;
161 Util::UTF8ToWide(filename.c_str(), &wfilename);
162
163 CreateTestFile(filename, "test data");
164 EXPECT_TRUE(FileUtil::FileExists(filename));
165
166 EXPECT_NE(FALSE,
167 ::SetFileAttributesW(wfilename.c_str(), FILE_ATTRIBUTE_NORMAL));
168 EXPECT_TRUE(FileUtil::HideFile(filename));
169 EXPECT_EQ(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM |
170 FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
171 ::GetFileAttributesW(wfilename.c_str()));
172
173 EXPECT_NE(FALSE,
174 ::SetFileAttributesW(wfilename.c_str(), FILE_ATTRIBUTE_ARCHIVE));
175 EXPECT_TRUE(FileUtil::HideFile(filename));
176 EXPECT_EQ(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM |
177 FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_ARCHIVE,
178 ::GetFileAttributesW(wfilename.c_str()));
179
180 EXPECT_NE(FALSE,
181 ::SetFileAttributesW(wfilename.c_str(), FILE_ATTRIBUTE_NORMAL));
182 EXPECT_TRUE(FileUtil::HideFileWithExtraAttributes(filename,
183 FILE_ATTRIBUTE_TEMPORARY));
184 EXPECT_EQ(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM |
185 FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY,
186 ::GetFileAttributesW(wfilename.c_str()));
187
188 EXPECT_NE(FALSE,
189 ::SetFileAttributesW(wfilename.c_str(), FILE_ATTRIBUTE_ARCHIVE));
190 EXPECT_TRUE(FileUtil::HideFileWithExtraAttributes(filename,
191 FILE_ATTRIBUTE_TEMPORARY));
192 EXPECT_EQ(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM |
193 FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_ARCHIVE |
194 FILE_ATTRIBUTE_TEMPORARY,
195 ::GetFileAttributesW(wfilename.c_str()));
196
197 FileUtil::Unlink(filename);
198 }
199 #endif // OS_WIN
200
TEST_F(FileUtilTest,IsEqualFile)201 TEST_F(FileUtilTest, IsEqualFile) {
202 const string filename1 = FileUtil::JoinPath(FLAGS_test_tmpdir, "test1");
203 const string filename2 = FileUtil::JoinPath(FLAGS_test_tmpdir, "test2");
204 FileUtil::Unlink(filename1);
205 FileUtil::Unlink(filename2);
206 EXPECT_FALSE(FileUtil::IsEqualFile(filename1, filename2));
207
208 CreateTestFile(filename1, "test data1");
209 EXPECT_FALSE(FileUtil::IsEqualFile(filename1, filename2));
210
211 CreateTestFile(filename2, "test data1");
212 EXPECT_TRUE(FileUtil::IsEqualFile(filename1, filename2));
213
214 CreateTestFile(filename2, "test data1 test data1");
215 EXPECT_FALSE(FileUtil::IsEqualFile(filename1, filename2));
216
217 CreateTestFile(filename2, "test data2");
218 EXPECT_FALSE(FileUtil::IsEqualFile(filename1, filename2));
219
220 FileUtil::Unlink(filename1);
221 FileUtil::Unlink(filename2);
222 }
223
TEST_F(FileUtilTest,CopyFile)224 TEST_F(FileUtilTest, CopyFile) {
225 // just test rename operation works as intended
226 const string from = FileUtil::JoinPath(FLAGS_test_tmpdir, "copy_from");
227 const string to = FileUtil::JoinPath(FLAGS_test_tmpdir, "copy_to");
228 FileUtil::Unlink(from);
229 FileUtil::Unlink(to);
230
231 CreateTestFile(from, "simple test");
232 EXPECT_TRUE(FileUtil::CopyFile(from, to));
233 EXPECT_TRUE(FileUtil::IsEqualFile(from, to));
234
235 CreateTestFile(from, "overwrite test");
236 EXPECT_TRUE(FileUtil::CopyFile(from, to));
237 EXPECT_TRUE(FileUtil::IsEqualFile(from, to));
238
239 #ifdef OS_WIN
240 struct TestData {
241 TestData(DWORD from, DWORD to)
242 : from_attributes(from), to_attributes(to) {}
243 const DWORD from_attributes;
244 const DWORD to_attributes;
245 };
246 const TestData kTestDataList[] = {
247 TestData(FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_ARCHIVE),
248 TestData(FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_HIDDEN),
249 TestData(FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NORMAL),
250 TestData(FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED),
251 TestData(FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_OFFLINE),
252 TestData(FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_READONLY),
253 TestData(FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_SYSTEM),
254 TestData(FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_TEMPORARY),
255
256 TestData(FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_NORMAL),
257 TestData(FILE_ATTRIBUTE_NORMAL,
258 FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY),
259 TestData(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,
260 FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM),
261 };
262
263 for (size_t i = 0; i < arraysize(kTestDataList); ++i) {
264 const string test_label =
265 "overwrite test with attributes " + std::to_string(i);
266 SCOPED_TRACE(test_label);
267 CreateTestFile(from, test_label);
268
269 const TestData &kData = kTestDataList[i];
270 std::wstring wfrom, wto;
271 Util::UTF8ToWide(from.c_str(), &wfrom);
272 Util::UTF8ToWide(to.c_str(), &wto);
273 EXPECT_NE(FALSE,
274 ::SetFileAttributesW(wfrom.c_str(), kData.from_attributes));
275 EXPECT_NE(FALSE, ::SetFileAttributesW(wto.c_str(), kData.to_attributes));
276
277 EXPECT_TRUE(FileUtil::CopyFile(from, to));
278 EXPECT_TRUE(FileUtil::IsEqualFile(from, to));
279 EXPECT_EQ(kData.from_attributes, ::GetFileAttributesW(wfrom.c_str()));
280 EXPECT_EQ(kData.from_attributes, ::GetFileAttributesW(wto.c_str()));
281
282 EXPECT_NE(FALSE,
283 ::SetFileAttributesW(wfrom.c_str(), FILE_ATTRIBUTE_NORMAL));
284 EXPECT_NE(FALSE, ::SetFileAttributesW(wto.c_str(), FILE_ATTRIBUTE_NORMAL));
285 }
286 #endif // OS_WIN
287
288 FileUtil::Unlink(from);
289 FileUtil::Unlink(to);
290 }
291
TEST_F(FileUtilTest,AtomicRename)292 TEST_F(FileUtilTest, AtomicRename) {
293 // just test rename operation works as intended
294 const string from = FileUtil::JoinPath(FLAGS_test_tmpdir,
295 "atomic_rename_test_from");
296 const string to = FileUtil::JoinPath(FLAGS_test_tmpdir,
297 "atomic_rename_test_to");
298 FileUtil::Unlink(from);
299 FileUtil::Unlink(to);
300
301 // |from| is not found
302 EXPECT_FALSE(FileUtil::AtomicRename(from, to));
303 CreateTestFile(from, "test");
304 EXPECT_TRUE(FileUtil::AtomicRename(from, to));
305
306 // from is deleted
307 EXPECT_FALSE(FileUtil::FileExists(from));
308 EXPECT_TRUE(FileUtil::FileExists(to));
309
310 {
311 InputFileStream ifs(to.c_str());
312 EXPECT_TRUE(ifs.good());
313 string line;
314 getline(ifs, line);
315 EXPECT_EQ("test", line);
316 }
317
318 EXPECT_FALSE(FileUtil::AtomicRename(from, to));
319
320 FileUtil::Unlink(from);
321 FileUtil::Unlink(to);
322
323 // overwrite the file
324 CreateTestFile(from, "test");
325 CreateTestFile(to, "test");
326 EXPECT_TRUE(FileUtil::AtomicRename(from, to));
327
328 #ifdef OS_WIN
329 struct TestData {
330 TestData(DWORD from, DWORD to)
331 : from_attributes(from), to_attributes(to) {}
332 const DWORD from_attributes;
333 const DWORD to_attributes;
334 };
335 const TestData kTestDataList[] = {
336 TestData(FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_ARCHIVE),
337 TestData(FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_HIDDEN),
338 TestData(FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NORMAL),
339 TestData(FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED),
340 TestData(FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_OFFLINE),
341 TestData(FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_READONLY),
342 TestData(FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_SYSTEM),
343 TestData(FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_TEMPORARY),
344
345 TestData(FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_NORMAL),
346 TestData(FILE_ATTRIBUTE_NORMAL,
347 FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY),
348 TestData(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,
349 FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM),
350 };
351
352 for (size_t i = 0; i < arraysize(kTestDataList); ++i) {
353 const string test_label =
354 "overwrite file with attributes " + std::to_string(i);
355 SCOPED_TRACE(test_label);
356 CreateTestFile(from, test_label);
357
358 const TestData &kData = kTestDataList[i];
359 std::wstring wfrom, wto;
360 Util::UTF8ToWide(from.c_str(), &wfrom);
361 Util::UTF8ToWide(to.c_str(), &wto);
362 EXPECT_NE(FALSE,
363 ::SetFileAttributesW(wfrom.c_str(), kData.from_attributes));
364 EXPECT_NE(FALSE, ::SetFileAttributesW(wto.c_str(), kData.to_attributes));
365
366 EXPECT_TRUE(FileUtil::AtomicRename(from, to));
367 EXPECT_EQ(kData.from_attributes, ::GetFileAttributesW(wto.c_str()));
368 EXPECT_FALSE(FileUtil::FileExists(from));
369 EXPECT_TRUE(FileUtil::FileExists(to));
370
371 ::SetFileAttributesW(wfrom.c_str(), FILE_ATTRIBUTE_NORMAL);
372 ::SetFileAttributesW(wto.c_str(), FILE_ATTRIBUTE_NORMAL);
373 }
374 #endif // OS_WIN
375
376 FileUtil::Unlink(from);
377 FileUtil::Unlink(to);
378 }
379
380 #ifdef OS_WIN
381 #define SP "\\"
382 #else
383 #define SP "/"
384 #endif // OS_WIN
385
TEST_F(FileUtilTest,JoinPath)386 TEST_F(FileUtilTest, JoinPath) {
387 EXPECT_TRUE(FileUtil::JoinPath({}).empty());
388 EXPECT_EQ("foo", FileUtil::JoinPath({"foo"}));
389 EXPECT_EQ("foo" SP "bar", FileUtil::JoinPath({"foo", "bar"}));
390 EXPECT_EQ("foo" SP "bar" SP "baz", FileUtil::JoinPath({"foo", "bar", "baz"}));
391
392 // Some path components end with delimiter.
393 EXPECT_EQ("foo" SP "bar" SP "baz",
394 FileUtil::JoinPath({"foo" SP, "bar", "baz"}));
395 EXPECT_EQ("foo" SP "bar" SP "baz",
396 FileUtil::JoinPath({"foo", "bar" SP, "baz"}));
397 EXPECT_EQ("foo" SP "bar" SP "baz" SP,
398 FileUtil::JoinPath({"foo", "bar", "baz" SP}));
399
400 // Containing empty strings.
401 EXPECT_TRUE(FileUtil::JoinPath({"", "", ""}).empty());
402 EXPECT_EQ("foo" SP "bar", FileUtil::JoinPath({"", "foo", "bar"}));
403 EXPECT_EQ("foo" SP "bar", FileUtil::JoinPath({"foo", "", "bar"}));
404 EXPECT_EQ("foo" SP "bar", FileUtil::JoinPath({"foo", "bar", ""}));
405 }
406
TEST_F(FileUtilTest,Dirname)407 TEST_F(FileUtilTest, Dirname) {
408 EXPECT_EQ(SP "foo", FileUtil::Dirname(SP "foo" SP "bar"));
409 EXPECT_EQ(SP "foo" SP "bar",
410 FileUtil::Dirname(SP "foo" SP "bar" SP "foo.txt"));
411 EXPECT_EQ("", FileUtil::Dirname("foo.txt"));
412 EXPECT_EQ("", FileUtil::Dirname(SP));
413 }
414
TEST_F(FileUtilTest,Basename)415 TEST_F(FileUtilTest, Basename) {
416 EXPECT_EQ("bar", FileUtil::Basename(SP "foo" SP "bar"));
417 EXPECT_EQ("foo.txt", FileUtil::Basename(SP "foo" SP "bar" SP "foo.txt"));
418 EXPECT_EQ("foo.txt", FileUtil::Basename("foo.txt"));
419 EXPECT_EQ("foo.txt", FileUtil::Basename("." SP "foo.txt"));
420 EXPECT_EQ(".foo.txt", FileUtil::Basename("." SP ".foo.txt"));
421 EXPECT_EQ("", FileUtil::Basename(SP));
422 EXPECT_EQ("", FileUtil::Basename("foo" SP "bar" SP "buz" SP));
423 }
424
425 #undef SP
426
TEST_F(FileUtilTest,NormalizeDirectorySeparator)427 TEST_F(FileUtilTest, NormalizeDirectorySeparator) {
428 #ifdef OS_WIN
429 EXPECT_EQ("\\foo\\bar", FileUtil::NormalizeDirectorySeparator("\\foo\\bar"));
430 EXPECT_EQ("\\foo\\bar", FileUtil::NormalizeDirectorySeparator("/foo\\bar"));
431 EXPECT_EQ("\\foo\\bar", FileUtil::NormalizeDirectorySeparator("\\foo/bar"));
432 EXPECT_EQ("\\foo\\bar", FileUtil::NormalizeDirectorySeparator("/foo/bar"));
433 EXPECT_EQ("\\foo\\bar\\",
434 FileUtil::NormalizeDirectorySeparator("\\foo\\bar\\"));
435 EXPECT_EQ("\\foo\\bar\\", FileUtil::NormalizeDirectorySeparator("/foo/bar/"));
436 EXPECT_EQ("", FileUtil::NormalizeDirectorySeparator(""));
437 EXPECT_EQ("\\", FileUtil::NormalizeDirectorySeparator("/"));
438 EXPECT_EQ("\\", FileUtil::NormalizeDirectorySeparator("\\"));
439 #else
440 EXPECT_EQ("\\foo\\bar", FileUtil::NormalizeDirectorySeparator("\\foo\\bar"));
441 EXPECT_EQ("/foo\\bar", FileUtil::NormalizeDirectorySeparator("/foo\\bar"));
442 EXPECT_EQ("\\foo/bar", FileUtil::NormalizeDirectorySeparator("\\foo/bar"));
443 EXPECT_EQ("/foo/bar", FileUtil::NormalizeDirectorySeparator("/foo/bar"));
444 EXPECT_EQ("\\foo\\bar\\",
445 FileUtil::NormalizeDirectorySeparator("\\foo\\bar\\"));
446 EXPECT_EQ("/foo/bar/", FileUtil::NormalizeDirectorySeparator("/foo/bar/"));
447 EXPECT_EQ("", FileUtil::NormalizeDirectorySeparator(""));
448 EXPECT_EQ("/", FileUtil::NormalizeDirectorySeparator("/"));
449 EXPECT_EQ("\\", FileUtil::NormalizeDirectorySeparator("\\"));
450 #endif // OS_WIN
451 }
452
TEST_F(FileUtilTest,GetModificationTime)453 TEST_F(FileUtilTest, GetModificationTime) {
454 FileTimeStamp time_stamp = 0;
455 EXPECT_FALSE(FileUtil::GetModificationTime("not_existent_file", &time_stamp));
456
457 const string &path = FileUtil::JoinPath(FLAGS_test_tmpdir, "testfile");
458 CreateTestFile(path, "content");
459 EXPECT_TRUE(FileUtil::GetModificationTime(path, &time_stamp));
460 EXPECT_NE(0, time_stamp);
461
462 FileTimeStamp time_stamp2 = 0;
463 EXPECT_TRUE(FileUtil::GetModificationTime(path, &time_stamp2));
464 EXPECT_EQ(time_stamp, time_stamp2);
465
466 // Cleanup
467 FileUtil::Unlink(path);
468 }
469
470 } // namespace mozc
471