| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 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 "files/public/c/lib/file_fd_impl.h" | |
| 6 | |
| 7 #include <errno.h> | |
| 8 | |
| 9 #include <string> | |
| 10 | |
| 11 #include "files/public/c/mojio_sys_stat.h" | |
| 12 #include "files/public/c/mojio_unistd.h" | |
| 13 #include "files/public/c/tests/mock_errno_impl.h" | |
| 14 #include "files/public/c/tests/mojio_impl_test_base.h" | |
| 15 #include "files/public/c/tests/test_utils.h" | |
| 16 #include "files/public/interfaces/files.mojom.h" | |
| 17 #include "files/public/interfaces/types.mojom.h" | |
| 18 | |
| 19 namespace mojio { | |
| 20 namespace { | |
| 21 | |
| 22 using FileFDImplTest = mojio::test::MojioImplTestBase; | |
| 23 | |
| 24 const int kLastErrorSentinel = -12345; | |
| 25 | |
| 26 TEST_F(FileFDImplTest, ConstructClose) { | |
| 27 test::MockErrnoImpl errno_impl(kLastErrorSentinel); | |
| 28 FileFDImpl ffdi(&errno_impl, | |
| 29 test::OpenFileAt(&directory(), "my_file", | |
| 30 mojo::files::kOpenFlagWrite | | |
| 31 mojo::files::kOpenFlagCreate)); | |
| 32 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 33 | |
| 34 errno_impl.Reset(kLastErrorSentinel); | |
| 35 EXPECT_TRUE(ffdi.Close()); | |
| 36 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 37 } | |
| 38 | |
| 39 TEST_F(FileFDImplTest, Dup) { | |
| 40 test::CreateTestFileAt(&directory(), "my_file", 1000); | |
| 41 | |
| 42 test::MockErrnoImpl errno_impl(kLastErrorSentinel); | |
| 43 FileFDImpl ffdi(&errno_impl, test::OpenFileAt(&directory(), "my_file", | |
| 44 mojo::files::kOpenFlagRead)); | |
| 45 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 46 | |
| 47 errno_impl.Reset(kLastErrorSentinel); | |
| 48 std::unique_ptr<FDImpl> duped_ffdi = ffdi.Dup(); | |
| 49 EXPECT_TRUE(duped_ffdi); | |
| 50 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 51 | |
| 52 // Seeking in one should change the position in the other. | |
| 53 errno_impl.Reset(kLastErrorSentinel); | |
| 54 EXPECT_EQ(123, ffdi.Lseek(123, MOJIO_SEEK_SET)); | |
| 55 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 56 errno_impl.Reset(kLastErrorSentinel); | |
| 57 EXPECT_EQ(123, duped_ffdi->Lseek(0, MOJIO_SEEK_CUR)); | |
| 58 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 59 | |
| 60 // And vice versa. | |
| 61 errno_impl.Reset(kLastErrorSentinel); | |
| 62 EXPECT_EQ(123 + 456, duped_ffdi->Lseek(456, MOJIO_SEEK_CUR)); | |
| 63 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 64 errno_impl.Reset(kLastErrorSentinel); | |
| 65 EXPECT_EQ(123 + 456, ffdi.Lseek(0, MOJIO_SEEK_CUR)); | |
| 66 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 67 } | |
| 68 | |
| 69 TEST_F(FileFDImplTest, Ftruncate) { | |
| 70 test::CreateTestFileAt(&directory(), "my_file", 1000); | |
| 71 | |
| 72 test::MockErrnoImpl errno_impl(kLastErrorSentinel); | |
| 73 FileFDImpl ffdi(&errno_impl, test::OpenFileAt(&directory(), "my_file", | |
| 74 mojo::files::kOpenFlagWrite)); | |
| 75 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 76 | |
| 77 // Truncate. | |
| 78 errno_impl.Reset(kLastErrorSentinel); | |
| 79 EXPECT_TRUE(ffdi.Ftruncate(123)); | |
| 80 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 81 EXPECT_EQ(123, test::GetFileSize(&directory(), "my_file")); | |
| 82 | |
| 83 // Can also extend. | |
| 84 errno_impl.Reset(kLastErrorSentinel); | |
| 85 EXPECT_TRUE(ffdi.Ftruncate(456)); | |
| 86 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 87 EXPECT_EQ(456, test::GetFileSize(&directory(), "my_file")); | |
| 88 | |
| 89 // TODO(vtl): Check file position after |Ftruncate()|. | |
| 90 | |
| 91 // Invalid size. | |
| 92 errno_impl.Reset(kLastErrorSentinel); | |
| 93 EXPECT_FALSE(ffdi.Ftruncate(-1)); | |
| 94 EXPECT_EQ(EINVAL, errno_impl.Get()); | |
| 95 } | |
| 96 | |
| 97 TEST_F(FileFDImplTest, Lseek) { | |
| 98 test::CreateTestFileAt(&directory(), "my_file", 123); | |
| 99 | |
| 100 test::MockErrnoImpl errno_impl(kLastErrorSentinel); | |
| 101 FileFDImpl ffdi(&errno_impl, test::OpenFileAt(&directory(), "my_file", | |
| 102 mojo::files::kOpenFlagWrite)); | |
| 103 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 104 | |
| 105 // Seek and write in various places. | |
| 106 | |
| 107 // 5 from beginning. | |
| 108 errno_impl.Reset(kLastErrorSentinel); | |
| 109 EXPECT_EQ(5, ffdi.Lseek(5, MOJIO_SEEK_SET)); | |
| 110 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 111 | |
| 112 // Write a byte. | |
| 113 errno_impl.Reset(kLastErrorSentinel); | |
| 114 char c = 42; | |
| 115 EXPECT_EQ(1, ffdi.Write(&c, 1)); | |
| 116 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 117 | |
| 118 // 42 from current. | |
| 119 errno_impl.Reset(kLastErrorSentinel); | |
| 120 EXPECT_EQ(5 + 1 + 42, ffdi.Lseek(42, MOJIO_SEEK_CUR)); | |
| 121 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 122 | |
| 123 // Write a byte. | |
| 124 errno_impl.Reset(kLastErrorSentinel); | |
| 125 c = 5; | |
| 126 EXPECT_EQ(1, ffdi.Write(&c, 1)); | |
| 127 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 128 | |
| 129 // 5 before end. | |
| 130 errno_impl.Reset(kLastErrorSentinel); | |
| 131 EXPECT_EQ(123 - 5, ffdi.Lseek(-5, MOJIO_SEEK_END)); | |
| 132 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 133 | |
| 134 // Write a byte. | |
| 135 errno_impl.Reset(kLastErrorSentinel); | |
| 136 c = 0; | |
| 137 EXPECT_EQ(1, ffdi.Write(&c, 1)); | |
| 138 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 139 | |
| 140 // Now read everything and check. | |
| 141 std::string expected_contents(123, '\0'); | |
| 142 for (size_t i = 0; i < 123; i++) { | |
| 143 unsigned char c = static_cast<unsigned char>(i); | |
| 144 expected_contents[i] = *reinterpret_cast<char*>(&c); | |
| 145 } | |
| 146 expected_contents[5] = 42; | |
| 147 expected_contents[5 + 1 + 42] = 5; | |
| 148 expected_contents[123 - 5] = 0; | |
| 149 EXPECT_EQ(expected_contents, test::GetFileContents(&directory(), "my_file")); | |
| 150 } | |
| 151 | |
| 152 TEST_F(FileFDImplTest, Read) { | |
| 153 test::CreateTestFileAt(&directory(), "my_file", 123); | |
| 154 | |
| 155 test::MockErrnoImpl errno_impl(kLastErrorSentinel); | |
| 156 FileFDImpl ffdi(&errno_impl, test::OpenFileAt(&directory(), "my_file", | |
| 157 mojo::files::kOpenFlagRead)); | |
| 158 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 159 | |
| 160 // Read a bit. | |
| 161 errno_impl.Reset(kLastErrorSentinel); | |
| 162 unsigned char buffer[1000] = {}; | |
| 163 EXPECT_EQ(23, ffdi.Read(buffer, 23)); | |
| 164 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 165 for (size_t i = 0; i < 23; i++) | |
| 166 EXPECT_EQ(static_cast<unsigned char>(i), buffer[i]) << i; | |
| 167 | |
| 168 // Read too much. | |
| 169 errno_impl.Reset(kLastErrorSentinel); | |
| 170 EXPECT_EQ(100, ffdi.Read(buffer, sizeof(buffer))); | |
| 171 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 172 for (size_t i = 0; i < 100; i++) | |
| 173 EXPECT_EQ(static_cast<unsigned char>(23 + i), buffer[i]) << i; | |
| 174 | |
| 175 // Invalid |count| (must fit within |ssize_t|). | |
| 176 errno_impl.Reset(kLastErrorSentinel); | |
| 177 EXPECT_EQ(-1, ffdi.Read(buffer, static_cast<size_t>(-1))); | |
| 178 EXPECT_EQ(EINVAL, errno_impl.Get()); | |
| 179 } | |
| 180 | |
| 181 TEST_F(FileFDImplTest, Write) { | |
| 182 test::MockErrnoImpl errno_impl(kLastErrorSentinel); | |
| 183 FileFDImpl ffdi(&errno_impl, | |
| 184 test::OpenFileAt(&directory(), "my_file", | |
| 185 mojo::files::kOpenFlagWrite | | |
| 186 mojo::files::kOpenFlagCreate | | |
| 187 mojo::files::kOpenFlagExclusive)); | |
| 188 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 189 | |
| 190 // Write something. | |
| 191 errno_impl.Reset(kLastErrorSentinel); | |
| 192 const char kHello[] = {'h', 'e', 'l', 'l', 'o', ' '}; | |
| 193 EXPECT_EQ(static_cast<mojio_off_t>(sizeof(kHello)), | |
| 194 ffdi.Write(kHello, sizeof(kHello))); | |
| 195 | |
| 196 // Write something else. | |
| 197 const char kMojio[] = {'m', 'o', 'j', 'i', 'o'}; | |
| 198 EXPECT_EQ(static_cast<mojio_off_t>(sizeof(kMojio)), | |
| 199 ffdi.Write(kMojio, sizeof(kMojio))); | |
| 200 | |
| 201 EXPECT_EQ(std::string("hello mojio"), | |
| 202 test::GetFileContents(&directory(), "my_file")); | |
| 203 | |
| 204 // Invalid |count| (must fit within |ssize_t|). | |
| 205 errno_impl.Reset(kLastErrorSentinel); | |
| 206 EXPECT_EQ(-1, ffdi.Write(kHello, static_cast<size_t>(-1))); | |
| 207 EXPECT_EQ(EINVAL, errno_impl.Get()); | |
| 208 } | |
| 209 | |
| 210 TEST_F(FileFDImplTest, Fstat) { | |
| 211 test::CreateTestFileAt(&directory(), "my_file_0", 0); | |
| 212 test::CreateTestFileAt(&directory(), "my_file_1", 512); | |
| 213 test::CreateTestFileAt(&directory(), "my_file_2", 513); | |
| 214 | |
| 215 test::MockErrnoImpl errno_impl(kLastErrorSentinel); | |
| 216 FileFDImpl ffdi0(&errno_impl, test::OpenFileAt(&directory(), "my_file_0", | |
| 217 mojo::files::kOpenFlagRead)); | |
| 218 FileFDImpl ffdi1(&errno_impl, test::OpenFileAt(&directory(), "my_file_1", | |
| 219 mojo::files::kOpenFlagRead)); | |
| 220 FileFDImpl ffdi2(&errno_impl, test::OpenFileAt(&directory(), "my_file_2", | |
| 221 mojo::files::kOpenFlagRead)); | |
| 222 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 223 | |
| 224 errno_impl.Reset(kLastErrorSentinel); | |
| 225 struct mojio_stat buf0 = {}; | |
| 226 EXPECT_TRUE(ffdi0.Fstat(&buf0)); | |
| 227 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 228 // Note: Don't check the unfilled values. (Some of the checks may also be | |
| 229 // fragile, depending on our level of support.) | |
| 230 EXPECT_EQ(static_cast<mojio_mode_t>(MOJIO_S_IRWXU | MOJIO_S_IFREG), | |
| 231 buf0.st_mode); // Fragile. | |
| 232 EXPECT_EQ(1u, buf0.st_nlink); // Fragile. | |
| 233 EXPECT_EQ(0, buf0.st_size); | |
| 234 // Just check that |st_atim.tv_sec|, etc. are positive (a bit fragile). | |
| 235 EXPECT_GT(buf0.st_atim.tv_sec, 0); | |
| 236 EXPECT_GT(buf0.st_mtim.tv_sec, 0); | |
| 237 EXPECT_GT(buf0.st_ctim.tv_sec, 0); | |
| 238 EXPECT_EQ(1024, buf0.st_blksize); // Fragile. | |
| 239 EXPECT_EQ(0u, buf0.st_blocks); | |
| 240 | |
| 241 errno_impl.Reset(kLastErrorSentinel); | |
| 242 struct mojio_stat buf1 = {}; | |
| 243 EXPECT_TRUE(ffdi1.Fstat(&buf1)); | |
| 244 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 245 // Only check the things that should be (interestingly) different. | |
| 246 EXPECT_EQ(512, buf1.st_size); | |
| 247 EXPECT_EQ(1u, buf1.st_blocks); | |
| 248 | |
| 249 errno_impl.Reset(kLastErrorSentinel); | |
| 250 struct mojio_stat buf2 = {}; | |
| 251 EXPECT_TRUE(ffdi2.Fstat(&buf2)); | |
| 252 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 253 // Only check the things that should be (interestingly) different. | |
| 254 EXPECT_EQ(513, buf2.st_size); | |
| 255 EXPECT_EQ(2u, buf2.st_blocks); | |
| 256 } | |
| 257 | |
| 258 TEST_F(FileFDImplTest, Efault) { | |
| 259 test::MockErrnoImpl errno_impl(kLastErrorSentinel); | |
| 260 FileFDImpl ffdi(&errno_impl, | |
| 261 test::OpenFileAt(&directory(), "my_file", | |
| 262 mojo::files::kOpenFlagRead | | |
| 263 mojo::files::kOpenFlagWrite | | |
| 264 mojo::files::kOpenFlagCreate | | |
| 265 mojo::files::kOpenFlagExclusive)); | |
| 266 EXPECT_EQ(kLastErrorSentinel, errno_impl.Get()); // No error. | |
| 267 | |
| 268 errno_impl.Reset(kLastErrorSentinel); | |
| 269 EXPECT_EQ(-1, ffdi.Read(nullptr, 1)); | |
| 270 EXPECT_EQ(EFAULT, errno_impl.Get()); | |
| 271 | |
| 272 errno_impl.Reset(kLastErrorSentinel); | |
| 273 EXPECT_EQ(-1, ffdi.Write(nullptr, 1)); | |
| 274 EXPECT_EQ(EFAULT, errno_impl.Get()); | |
| 275 | |
| 276 errno_impl.Reset(kLastErrorSentinel); | |
| 277 EXPECT_FALSE(ffdi.Fstat(nullptr)); | |
| 278 EXPECT_EQ(EFAULT, errno_impl.Get()); | |
| 279 } | |
| 280 | |
| 281 } // namespace | |
| 282 } // namespace mojio | |
| OLD | NEW |