Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / tests / nacl_io_test / html5_fs_test.cc
1 // Copyright 2013 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 <errno.h>
6 #include <fcntl.h>
7
8 #include <set>
9 #include <string>
10
11 #include <gmock/gmock.h>
12 #include <ppapi/c/ppb_file_io.h>
13 #include <ppapi/c/pp_directory_entry.h>
14 #include <ppapi/c/pp_errors.h>
15 #include <ppapi/c/pp_instance.h>
16 #if defined(WIN32)
17 #include <windows.h>  // For Sleep()
18 #endif
19
20 #include "fake_ppapi/fake_pepper_interface_html5_fs.h"
21 #include "nacl_io/kernel_handle.h"
22 #include "nacl_io/html5fs/html5_fs.h"
23 #include "nacl_io/osdirent.h"
24 #include "nacl_io/osunistd.h"
25 #include "nacl_io/pepper_interface_delegate.h"
26 #include "sdk_util/scoped_ref.h"
27 #include "mock_util.h"
28 #include "pepper_interface_mock.h"
29
30 using namespace nacl_io;
31 using namespace sdk_util;
32
33 using ::testing::_;
34 using ::testing::DoAll;
35 using ::testing::Invoke;
36 using ::testing::Mock;
37 using ::testing::Return;
38
39 namespace {
40
41 class Html5FsForTesting : public Html5Fs {
42  public:
43   Html5FsForTesting(StringMap_t& string_map, PepperInterface* ppapi,
44                     int expected_error = 0) {
45     FsInitArgs args;
46     args.string_map = string_map;
47     args.ppapi = ppapi;
48     Error error = Init(args);
49     EXPECT_EQ(expected_error, error);
50   }
51
52   bool Exists(const char* filename) {
53     ScopedNode node;
54     if (Open(Path(filename), O_RDONLY, &node))
55       return false;
56
57     struct stat buf;
58     return node->GetStat(&buf) == 0;
59   }
60 };
61
62 class Html5FsTest : public ::testing::Test {
63  public:
64   Html5FsTest();
65
66  protected:
67   FakePepperInterfaceHtml5Fs ppapi_html5_;
68   PepperInterfaceMock ppapi_mock_;
69   PepperInterfaceDelegate ppapi_;
70 };
71
72 Html5FsTest::Html5FsTest()
73     : ppapi_mock_(ppapi_html5_.GetInstance()),
74       ppapi_(ppapi_html5_.GetInstance()) {
75   // Default delegation to the html5 pepper interface.
76   ppapi_.SetCoreInterfaceDelegate(ppapi_html5_.GetCoreInterface());
77   ppapi_.SetFileSystemInterfaceDelegate(ppapi_html5_.GetFileSystemInterface());
78   ppapi_.SetFileRefInterfaceDelegate(ppapi_html5_.GetFileRefInterface());
79   ppapi_.SetFileIoInterfaceDelegate(ppapi_html5_.GetFileIoInterface());
80   ppapi_.SetVarInterfaceDelegate(ppapi_html5_.GetVarInterface());
81 }
82
83 }  // namespace
84
85 TEST_F(Html5FsTest, FilesystemType) {
86   const char* filesystem_type_strings[] = {"", "PERSISTENT", "TEMPORARY", NULL};
87   PP_FileSystemType filesystem_type_values[] = {
88       PP_FILESYSTEMTYPE_LOCALPERSISTENT,  // Default to persistent.
89       PP_FILESYSTEMTYPE_LOCALPERSISTENT, PP_FILESYSTEMTYPE_LOCALTEMPORARY};
90
91   const char* expected_size_strings[] = {"100", "12345", NULL};
92   const int expected_size_values[] = {100, 12345};
93
94   FileSystemInterfaceMock* filesystem_mock =
95       ppapi_mock_.GetFileSystemInterface();
96
97   FakeFileSystemInterface* filesystem_fake =
98       static_cast<FakeFileSystemInterface*>(
99           ppapi_html5_.GetFileSystemInterface());
100
101   for (int i = 0; filesystem_type_strings[i] != NULL; ++i) {
102     const char* filesystem_type_string = filesystem_type_strings[i];
103     PP_FileSystemType expected_filesystem_type = filesystem_type_values[i];
104
105     for (int j = 0; expected_size_strings[j] != NULL; ++j) {
106       const char* expected_size_string = expected_size_strings[j];
107       int64_t expected_expected_size = expected_size_values[j];
108
109       ppapi_.SetFileSystemInterfaceDelegate(filesystem_mock);
110
111       ON_CALL(*filesystem_mock, Create(_, _)).WillByDefault(
112           Invoke(filesystem_fake, &FakeFileSystemInterface::Create));
113
114       EXPECT_CALL(*filesystem_mock,
115                   Create(ppapi_.GetInstance(), expected_filesystem_type));
116
117       EXPECT_CALL(*filesystem_mock, Open(_, expected_expected_size, _))
118           .WillOnce(DoAll(CallCallback<2>(int32_t(PP_OK)),
119                           Return(int32_t(PP_OK_COMPLETIONPENDING))));
120
121       StringMap_t map;
122       map["type"] = filesystem_type_string;
123       map["expected_size"] = expected_size_string;
124       ScopedRef<Html5FsForTesting> fs(new Html5FsForTesting(map, &ppapi_));
125
126       Mock::VerifyAndClearExpectations(&filesystem_mock);
127     }
128   }
129 }
130
131 TEST_F(Html5FsTest, PassFilesystemResource) {
132   // Fail if given a bad resource.
133   {
134     StringMap_t map;
135     map["filesystem_resource"] = "0";
136     ScopedRef<Html5FsForTesting> fs(
137         new Html5FsForTesting(map, &ppapi_, EINVAL));
138   }
139
140   {
141     EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddEmptyFile("/foo", NULL));
142     PP_Resource filesystem = ppapi_html5_.GetFileSystemInterface()->Create(
143         ppapi_html5_.GetInstance(), PP_FILESYSTEMTYPE_LOCALPERSISTENT);
144
145     ASSERT_EQ(int32_t(PP_OK), ppapi_html5_.GetFileSystemInterface()->Open(
146               filesystem, 0, PP_BlockUntilComplete()));
147
148     StringMap_t map;
149     char buffer[30];
150     snprintf(buffer, 30, "%d", filesystem);
151     map["filesystem_resource"] = buffer;
152     ScopedRef<Html5FsForTesting> fs(
153         new Html5FsForTesting(map, &ppapi_));
154
155     ASSERT_TRUE(fs->Exists("/foo"));
156
157     ppapi_html5_.GetCoreInterface()->ReleaseResource(filesystem);
158   }
159 }
160
161 TEST_F(Html5FsTest, MountSubtree) {
162   EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddEmptyFile("/foo/bar",
163                                                                NULL));
164   StringMap_t map;
165   map["SOURCE"] = "/foo";
166   ScopedRef<Html5FsForTesting> fs(new Html5FsForTesting(map, &ppapi_));
167
168   ASSERT_TRUE(fs->Exists("/bar"));
169   ASSERT_FALSE(fs->Exists("/foo/bar"));
170 }
171
172 TEST_F(Html5FsTest, Mkdir) {
173   StringMap_t map;
174   ScopedRef<Html5FsForTesting> fs(new Html5FsForTesting(map, &ppapi_));
175
176   // mkdir at the root should return EEXIST, not EACCES.
177   EXPECT_EQ(EEXIST, fs->Mkdir(Path("/"), 0644));
178
179   Path path("/foo");
180   ASSERT_FALSE(fs->Exists("/foo"));
181   ASSERT_EQ(0, fs->Mkdir(path, 0644));
182
183   struct stat stat;
184   ScopedNode node;
185   ASSERT_EQ(0, fs->Open(path, O_RDONLY, &node));
186   EXPECT_EQ(0, node->GetStat(&stat));
187   EXPECT_TRUE(S_ISDIR(stat.st_mode));
188 }
189
190 TEST_F(Html5FsTest, Remove) {
191   const char* kPath = "/foo";
192   EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddEmptyFile(kPath, NULL));
193
194   StringMap_t map;
195   ScopedRef<Html5FsForTesting> fs(new Html5FsForTesting(map, &ppapi_));
196
197   Path path(kPath);
198   ASSERT_TRUE(fs->Exists(kPath));
199   ASSERT_EQ(0, fs->Remove(path));
200   EXPECT_FALSE(fs->Exists(kPath));
201 }
202
203 TEST_F(Html5FsTest, Unlink) {
204   EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddEmptyFile("/file", NULL));
205   EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddDirectory("/dir", NULL));
206
207   StringMap_t map;
208   ScopedRef<Html5FsForTesting> fs(new Html5FsForTesting(map, &ppapi_));
209
210   ASSERT_TRUE(fs->Exists("/dir"));
211   ASSERT_TRUE(fs->Exists("/file"));
212   ASSERT_EQ(0, fs->Unlink(Path("/file")));
213   ASSERT_EQ(EISDIR, fs->Unlink(Path("/dir")));
214   EXPECT_FALSE(fs->Exists("/file"));
215   EXPECT_TRUE(fs->Exists("/dir"));
216 }
217
218 TEST_F(Html5FsTest, Rmdir) {
219   EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddEmptyFile("/file", NULL));
220   EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddDirectory("/dir", NULL));
221
222   StringMap_t map;
223   ScopedRef<Html5FsForTesting> fs(new Html5FsForTesting(map, &ppapi_));
224
225   ASSERT_EQ(ENOTDIR, fs->Rmdir(Path("/file")));
226   EXPECT_EQ(0, fs->Rmdir(Path("/dir")));
227   EXPECT_FALSE(fs->Exists("/dir"));
228   EXPECT_TRUE(fs->Exists("/file"));
229 }
230
231 TEST_F(Html5FsTest, Rename) {
232   EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddEmptyFile("/foo", NULL));
233
234   StringMap_t map;
235   ScopedRef<Html5FsForTesting> fs(new Html5FsForTesting(map, &ppapi_));
236
237   ASSERT_TRUE(fs->Exists("/foo"));
238   ASSERT_EQ(0, fs->Rename(Path("/foo"), Path("/bar")));
239   EXPECT_FALSE(fs->Exists("/foo"));
240   EXPECT_TRUE(fs->Exists("/bar"));
241 }
242
243 TEST_F(Html5FsTest, OpenForCreate) {
244   StringMap_t map;
245   ScopedRef<Html5FsForTesting> fs(new Html5FsForTesting(map, &ppapi_));
246
247   EXPECT_FALSE(fs->Exists("/foo"));
248
249   Path path("/foo");
250   ScopedNode node;
251   ASSERT_EQ(0, fs->Open(path, O_CREAT | O_RDWR, &node));
252
253   // Write some data.
254   char contents[] = "contents";
255   int bytes_written = 0;
256   EXPECT_EQ(0, node->Write(HandleAttr(), &contents[0], strlen(contents),
257                            &bytes_written));
258   EXPECT_EQ(strlen(contents), bytes_written);
259
260   // Create again.
261   ASSERT_EQ(0, fs->Open(path, O_CREAT, &node));
262
263   // Check that the file still has data.
264   off_t size;
265   EXPECT_EQ(0, node->GetSize(&size));
266   EXPECT_EQ(strlen(contents), size);
267
268   // Open exclusively.
269   EXPECT_EQ(EEXIST, fs->Open(path, O_CREAT | O_EXCL, &node));
270
271   // Try to truncate without write access.
272   EXPECT_EQ(EINVAL, fs->Open(path, O_CREAT | O_TRUNC, &node));
273
274   // Open and truncate.
275   ASSERT_EQ(0, fs->Open(path, O_CREAT | O_TRUNC | O_WRONLY, &node));
276
277   // File should be empty.
278   EXPECT_EQ(0, node->GetSize(&size));
279   EXPECT_EQ(0, size);
280 }
281
282 TEST_F(Html5FsTest, Read) {
283   const char contents[] = "contents";
284   ASSERT_TRUE(
285       ppapi_html5_.filesystem_template()->AddFile("/file", contents, NULL));
286   ASSERT_TRUE(ppapi_html5_.filesystem_template()->AddDirectory("/dir", NULL));
287   StringMap_t map;
288   ScopedRef<Html5FsForTesting> fs(new Html5FsForTesting(map, &ppapi_));
289
290   ScopedNode node;
291   ASSERT_EQ(0, fs->Open(Path("/file"), O_RDONLY, &node));
292
293   char buffer[10] = {0};
294   int bytes_read = 0;
295   HandleAttr attr;
296   ASSERT_EQ(0, node->Read(attr, &buffer[0], sizeof(buffer), &bytes_read));
297   ASSERT_EQ(strlen(contents), bytes_read);
298   ASSERT_STREQ(contents, buffer);
299
300   // Read nothing past the end of the file.
301   attr.offs = 100;
302   ASSERT_EQ(0, node->Read(attr, &buffer[0], sizeof(buffer), &bytes_read));
303   ASSERT_EQ(0, bytes_read);
304
305   // Read part of the data.
306   attr.offs = 4;
307   ASSERT_EQ(0, node->Read(attr, &buffer[0], sizeof(buffer), &bytes_read));
308   ASSERT_EQ(strlen(contents) - 4, bytes_read);
309   buffer[bytes_read] = 0;
310   ASSERT_STREQ("ents", buffer);
311
312   // Writing should fail.
313   int bytes_written = 1;  // Set to a non-zero value.
314   attr.offs = 0;
315   ASSERT_EQ(EACCES,
316             node->Write(attr, &buffer[0], sizeof(buffer), &bytes_written));
317   ASSERT_EQ(0, bytes_written);
318
319   // Reading from a directory should fail.
320   ASSERT_EQ(0, fs->Open(Path("/dir"), O_RDONLY, &node));
321   ASSERT_EQ(EISDIR, node->Read(attr, &buffer[0], sizeof(buffer), &bytes_read));
322 }
323
324 TEST_F(Html5FsTest, Write) {
325   const char contents[] = "contents";
326   EXPECT_TRUE(
327       ppapi_html5_.filesystem_template()->AddFile("/file", contents, NULL));
328   EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddDirectory("/dir", NULL));
329
330   StringMap_t map;
331   ScopedRef<Html5FsForTesting> fs(new Html5FsForTesting(map, &ppapi_));
332
333   ScopedNode node;
334   ASSERT_EQ(0, fs->Open(Path("/file"), O_WRONLY, &node));
335
336   // Reading should fail.
337   char buffer[10];
338   int bytes_read = 1;  // Set to a non-zero value.
339   HandleAttr attr;
340   EXPECT_EQ(EACCES, node->Read(attr, &buffer[0], sizeof(buffer), &bytes_read));
341   EXPECT_EQ(0, bytes_read);
342
343   // Reopen as read-write.
344   ASSERT_EQ(0, fs->Open(Path("/file"), O_RDWR, &node));
345
346   int bytes_written = 1;  // Set to a non-zero value.
347   attr.offs = 3;
348   EXPECT_EQ(0, node->Write(attr, "struct", 6, &bytes_written));
349   EXPECT_EQ(6, bytes_written);
350
351   attr.offs = 0;
352   EXPECT_EQ(0, node->Read(attr, &buffer[0], sizeof(buffer), &bytes_read));
353   EXPECT_EQ(9, bytes_read);
354   buffer[bytes_read] = 0;
355   EXPECT_STREQ("construct", buffer);
356
357   // Writing to a directory should fail.
358   EXPECT_EQ(0, fs->Open(Path("/dir"), O_RDWR, &node));
359   EXPECT_EQ(EISDIR, node->Write(attr, &buffer[0], sizeof(buffer), &bytes_read));
360 }
361
362 TEST_F(Html5FsTest, GetStat) {
363   const int creation_time = 1000;
364   const int access_time = 2000;
365   const int modified_time = 3000;
366   const char contents[] = "contents";
367
368   // Create fake file.
369   FakeHtml5FsNode* fake_node;
370   EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddFile(
371       "/file", contents, &fake_node));
372   fake_node->set_creation_time(creation_time);
373   fake_node->set_last_access_time(access_time);
374   fake_node->set_last_modified_time(modified_time);
375
376   // Create fake directory.
377   EXPECT_TRUE(
378       ppapi_html5_.filesystem_template()->AddDirectory("/dir", &fake_node));
379   fake_node->set_creation_time(creation_time);
380   fake_node->set_last_access_time(access_time);
381   fake_node->set_last_modified_time(modified_time);
382
383   StringMap_t map;
384   ScopedRef<Html5FsForTesting> fs(new Html5FsForTesting(map, &ppapi_));
385
386   ScopedNode node;
387   ASSERT_EQ(0, fs->Open(Path("/file"), O_RDONLY, &node));
388
389   struct stat statbuf;
390   EXPECT_EQ(0, node->GetStat(&statbuf));
391   EXPECT_TRUE(S_ISREG(statbuf.st_mode));
392   EXPECT_EQ(S_IRALL | S_IWALL | S_IXALL, statbuf.st_mode & S_MODEBITS);
393   EXPECT_EQ(strlen(contents), statbuf.st_size);
394   EXPECT_EQ(access_time, statbuf.st_atime);
395   EXPECT_EQ(creation_time, statbuf.st_ctime);
396   EXPECT_EQ(modified_time, statbuf.st_mtime);
397
398   // Test Get* and Isa* methods.
399   off_t size;
400   EXPECT_EQ(0, node->GetSize(&size));
401   EXPECT_EQ(strlen(contents), size);
402   EXPECT_FALSE(node->IsaDir());
403   EXPECT_TRUE(node->IsaFile());
404   EXPECT_EQ(ENOTTY, node->Isatty());
405
406   // GetStat on a directory...
407   EXPECT_EQ(0, fs->Open(Path("/dir"), O_RDONLY, &node));
408   EXPECT_EQ(0, node->GetStat(&statbuf));
409   EXPECT_TRUE(S_ISDIR(statbuf.st_mode));
410   EXPECT_EQ(S_IRALL | S_IWALL | S_IXALL, statbuf.st_mode & S_MODEBITS);
411   EXPECT_EQ(0, statbuf.st_size);
412   EXPECT_EQ(access_time, statbuf.st_atime);
413   EXPECT_EQ(creation_time, statbuf.st_ctime);
414   EXPECT_EQ(modified_time, statbuf.st_mtime);
415
416   // Test Get* and Isa* methods.
417   EXPECT_EQ(0, node->GetSize(&size));
418   EXPECT_EQ(0, size);
419   EXPECT_TRUE(node->IsaDir());
420   EXPECT_FALSE(node->IsaFile());
421   EXPECT_EQ(ENOTTY, node->Isatty());
422 }
423
424 TEST_F(Html5FsTest, FTruncate) {
425   const char contents[] = "contents";
426   EXPECT_TRUE(
427       ppapi_html5_.filesystem_template()->AddFile("/file", contents, NULL));
428   EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddDirectory("/dir", NULL));
429
430   StringMap_t map;
431   ScopedRef<Html5FsForTesting> fs(new Html5FsForTesting(map, &ppapi_));
432
433   ScopedNode node;
434   ASSERT_EQ(0, fs->Open(Path("/file"), O_RDWR, &node));
435
436   HandleAttr attr;
437   char buffer[10] = {0};
438   int bytes_read = 0;
439
440   // First make the file shorter...
441   EXPECT_EQ(0, node->FTruncate(4));
442   EXPECT_EQ(0, node->Read(attr, &buffer[0], sizeof(buffer), &bytes_read));
443   EXPECT_EQ(4, bytes_read);
444   buffer[bytes_read] = 0;
445   EXPECT_STREQ("cont", buffer);
446
447   // Now make the file longer...
448   EXPECT_EQ(0, node->FTruncate(8));
449   EXPECT_EQ(0, node->Read(attr, &buffer[0], sizeof(buffer), &bytes_read));
450   EXPECT_EQ(8, bytes_read);
451   buffer[bytes_read] = 0;
452   EXPECT_STREQ("cont\0\0\0\0", buffer);
453
454   // Ftruncate should fail for a directory.
455   EXPECT_EQ(0, fs->Open(Path("/dir"), O_RDONLY, &node));
456   EXPECT_EQ(EISDIR, node->FTruncate(4));
457 }
458
459 TEST_F(Html5FsTest, Chmod) {
460   StringMap_t map;
461   ScopedRef<Html5FsForTesting> fs(new Html5FsForTesting(map, &ppapi_));
462   ScopedNode node;
463   ASSERT_EQ(0, fs->Open(Path("/"), O_RDONLY, &node));
464   ASSERT_EQ(0, node->Fchmod(0777));
465 }
466
467 TEST_F(Html5FsTest, GetDents) {
468   const char contents[] = "contents";
469   EXPECT_TRUE(
470       ppapi_html5_.filesystem_template()->AddFile("/file", contents, NULL));
471
472   StringMap_t map;
473   ScopedRef<Html5FsForTesting> fs(new Html5FsForTesting(map, &ppapi_));
474
475   ScopedNode root;
476   ASSERT_EQ(0, fs->Open(Path("/"), O_RDONLY, &root));
477
478   ScopedNode node;
479   ASSERT_EQ(0, fs->Open(Path("/file"), O_RDWR, &node));
480
481   struct stat stat;
482   ASSERT_EQ(0, node->GetStat(&stat));
483   ino_t file1_ino = stat.st_ino;
484
485   // Should fail for regular files.
486   const size_t kMaxDirents = 5;
487   dirent dirents[kMaxDirents];
488   int bytes_read = 1;  // Set to a non-zero value.
489
490   memset(&dirents[0], 0, sizeof(dirents));
491   EXPECT_EQ(ENOTDIR,
492             node->GetDents(0, &dirents[0], sizeof(dirents), &bytes_read));
493   EXPECT_EQ(0, bytes_read);
494
495   // Should work with root directory.
496   // +2 to test a size that is not a multiple of sizeof(dirent).
497   // Expect it to round down.
498   memset(&dirents[0], 0, sizeof(dirents));
499   EXPECT_EQ(
500       0, root->GetDents(0, &dirents[0], sizeof(dirent) * 3 + 2, &bytes_read));
501
502   {
503     size_t num_dirents = bytes_read / sizeof(dirent);
504     EXPECT_EQ(3, num_dirents);
505     EXPECT_EQ(sizeof(dirent) * num_dirents, bytes_read);
506
507     std::multiset<std::string> dirnames;
508     for (size_t i = 0; i < num_dirents; ++i) {
509       EXPECT_EQ(sizeof(dirent), dirents[i].d_off);
510       EXPECT_EQ(sizeof(dirent), dirents[i].d_reclen);
511       dirnames.insert(dirents[i].d_name);
512     }
513
514     EXPECT_EQ(1, dirnames.count("file"));
515     EXPECT_EQ(1, dirnames.count("."));
516     EXPECT_EQ(1, dirnames.count(".."));
517   }
518
519   // Add another file...
520   ASSERT_EQ(0, fs->Open(Path("/file2"), O_CREAT, &node));
521   ASSERT_EQ(0, node->GetStat(&stat));
522   ino_t file2_ino = stat.st_ino;
523
524   // These files SHOULD not hash to the same value but COULD.
525   EXPECT_NE(file1_ino, file2_ino);
526
527   // Read the root directory again.
528   memset(&dirents[0], 0, sizeof(dirents));
529   EXPECT_EQ(0, root->GetDents(0, &dirents[0], sizeof(dirents), &bytes_read));
530
531   {
532     size_t num_dirents = bytes_read / sizeof(dirent);
533     EXPECT_EQ(4, num_dirents);
534     EXPECT_EQ(sizeof(dirent) * num_dirents, bytes_read);
535
536     std::multiset<std::string> dirnames;
537     for (size_t i = 0; i < num_dirents; ++i) {
538       EXPECT_EQ(sizeof(dirent), dirents[i].d_off);
539       EXPECT_EQ(sizeof(dirent), dirents[i].d_reclen);
540       dirnames.insert(dirents[i].d_name);
541
542       if (!strcmp(dirents[i].d_name, "file")) {
543         EXPECT_EQ(dirents[i].d_ino, file1_ino);
544       }
545       if (!strcmp(dirents[i].d_name, "file2")) {
546         EXPECT_EQ(dirents[i].d_ino, file2_ino);
547       }
548     }
549
550     EXPECT_EQ(1, dirnames.count("file"));
551     EXPECT_EQ(1, dirnames.count("file2"));
552     EXPECT_EQ(1, dirnames.count("."));
553     EXPECT_EQ(1, dirnames.count(".."));
554   }
555 }