1 | //===-- Unittests for platform independent file class ---------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "src/__support/CPP/new.h" |
10 | #include "src/__support/File/file.h" |
11 | #include "src/__support/error_or.h" |
12 | #include "test/UnitTest/MemoryMatcher.h" |
13 | #include "test/UnitTest/Test.h" |
14 | |
15 | #include "hdr/types/size_t.h" |
16 | |
17 | using ModeFlags = LIBC_NAMESPACE::File::ModeFlags; |
18 | using MemoryView = LIBC_NAMESPACE::testing::MemoryView; |
19 | using LIBC_NAMESPACE::ErrorOr; |
20 | using LIBC_NAMESPACE::File; |
21 | using LIBC_NAMESPACE::FileIOResult; |
22 | |
23 | class StringFile : public File { |
24 | static constexpr size_t SIZE = 512; |
25 | size_t pos; |
26 | char str[SIZE] = {0}; |
27 | size_t eof_marker; |
28 | bool write_append; |
29 | |
30 | static FileIOResult str_read(LIBC_NAMESPACE::File *f, void *data, size_t len); |
31 | static FileIOResult str_write(LIBC_NAMESPACE::File *f, const void *data, |
32 | size_t len); |
33 | static ErrorOr<off_t> str_seek(LIBC_NAMESPACE::File *f, off_t offset, |
34 | int whence); |
35 | static int str_close(LIBC_NAMESPACE::File *f) { |
36 | delete reinterpret_cast<StringFile *>(f); |
37 | return 0; |
38 | } |
39 | |
40 | public: |
41 | explicit StringFile(char *buffer, size_t buflen, int bufmode, bool owned, |
42 | ModeFlags modeflags) |
43 | : LIBC_NAMESPACE::File(&str_write, &str_read, &str_seek, &str_close, |
44 | reinterpret_cast<uint8_t *>(buffer), buflen, |
45 | bufmode, owned, modeflags), |
46 | pos(0), eof_marker(0), write_append(false) { |
47 | if (modeflags & |
48 | static_cast<ModeFlags>(LIBC_NAMESPACE::File::OpenMode::APPEND)) |
49 | write_append = true; |
50 | } |
51 | |
52 | void reset() { pos = 0; } |
53 | size_t get_pos() const { return pos; } |
54 | char *get_str() { return str; } |
55 | |
56 | // Use this method to prefill the file. |
57 | void reset_and_fill(const char *data, size_t len) { |
58 | size_t i; |
59 | for (i = 0; i < len && i < SIZE; ++i) { |
60 | str[i] = data[i]; |
61 | } |
62 | pos = 0; |
63 | eof_marker = i; |
64 | } |
65 | }; |
66 | |
67 | FileIOResult StringFile::str_read(LIBC_NAMESPACE::File *f, void *data, |
68 | size_t len) { |
69 | StringFile *sf = static_cast<StringFile *>(f); |
70 | if (sf->pos >= sf->eof_marker) |
71 | return 0; |
72 | size_t i = 0; |
73 | for (i = 0; i < len; ++i) |
74 | reinterpret_cast<char *>(data)[i] = sf->str[sf->pos + i]; |
75 | sf->pos += i; |
76 | return i; |
77 | } |
78 | |
79 | FileIOResult StringFile::str_write(LIBC_NAMESPACE::File *f, const void *data, |
80 | size_t len) { |
81 | StringFile *sf = static_cast<StringFile *>(f); |
82 | if (sf->write_append) |
83 | sf->pos = sf->eof_marker; |
84 | if (sf->pos >= SIZE) |
85 | return 0; |
86 | size_t i = 0; |
87 | for (i = 0; i < len && sf->pos < SIZE; ++i, ++sf->pos) |
88 | sf->str[sf->pos] = reinterpret_cast<const char *>(data)[i]; |
89 | // Move the eof marker if the data was written beyond the current eof marker. |
90 | if (sf->pos > sf->eof_marker) |
91 | sf->eof_marker = sf->pos; |
92 | return i; |
93 | } |
94 | |
95 | ErrorOr<off_t> StringFile::str_seek(LIBC_NAMESPACE::File *f, off_t offset, |
96 | int whence) { |
97 | StringFile *sf = static_cast<StringFile *>(f); |
98 | if (whence == SEEK_SET) |
99 | sf->pos = offset; |
100 | if (whence == SEEK_CUR) |
101 | sf->pos += offset; |
102 | if (whence == SEEK_END) |
103 | sf->pos = SIZE + offset; |
104 | return sf->pos; |
105 | } |
106 | |
107 | StringFile *new_string_file(char *buffer, size_t buflen, int bufmode, |
108 | bool owned, const char *mode) { |
109 | LIBC_NAMESPACE::AllocChecker ac; |
110 | // We will just assume the allocation succeeds. We cannot test anything |
111 | // otherwise. |
112 | return new (ac) StringFile(buffer, buflen, bufmode, owned, |
113 | LIBC_NAMESPACE::File::mode_flags(mode)); |
114 | } |
115 | |
116 | TEST(LlvmLibcFileTest, WriteOnly) { |
117 | const char data[] = "hello, file" ; |
118 | constexpr size_t FILE_BUFFER_SIZE = sizeof(data) * 3 / 2; |
119 | char file_buffer[FILE_BUFFER_SIZE]; |
120 | StringFile *f = |
121 | new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "w" ); |
122 | |
123 | ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)).value); |
124 | EXPECT_EQ(f->get_pos(), size_t(0)); // Data is buffered in the file stream |
125 | ASSERT_EQ(f->flush(), 0); |
126 | EXPECT_EQ(f->get_pos(), sizeof(data)); // Data should now be available |
127 | EXPECT_STREQ(f->get_str(), data); |
128 | |
129 | f->reset(); |
130 | ASSERT_EQ(f->get_pos(), size_t(0)); |
131 | ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)).value); |
132 | EXPECT_EQ(f->get_pos(), size_t(0)); // Data is buffered in the file stream |
133 | // The second write should trigger a buffer flush. |
134 | ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)).value); |
135 | EXPECT_GE(f->get_pos(), size_t(0)); |
136 | ASSERT_EQ(f->flush(), 0); |
137 | EXPECT_EQ(f->get_pos(), 2 * sizeof(data)); |
138 | MemoryView src1("hello, file\0hello, file" , sizeof(data) * 2), |
139 | dst1(f->get_str(), sizeof(data) * 2); |
140 | EXPECT_MEM_EQ(src1, dst1); |
141 | |
142 | char read_data[sizeof(data)]; |
143 | { |
144 | // This is not a readable file. |
145 | auto result = f->read(read_data, sizeof(data)); |
146 | EXPECT_EQ(result.value, size_t(0)); |
147 | EXPECT_TRUE(f->error()); |
148 | EXPECT_TRUE(result.has_error()); |
149 | } |
150 | |
151 | ASSERT_EQ(f->close(), 0); |
152 | } |
153 | |
154 | TEST(LlvmLibcFileTest, WriteLineBuffered) { |
155 | const char data[] = "hello\n file" ; |
156 | constexpr size_t FILE_BUFFER_SIZE = sizeof(data) * 3 / 2; |
157 | |
158 | char file_buffer_line[FILE_BUFFER_SIZE]; |
159 | char file_buffer_full[FILE_BUFFER_SIZE]; |
160 | |
161 | StringFile *f_line = |
162 | new_string_file(file_buffer_line, FILE_BUFFER_SIZE, _IOLBF, false, "w" ); |
163 | // We also initialize a fully buffered file we'll do the same writes to for |
164 | // comparison. |
165 | StringFile *f_full = |
166 | new_string_file(file_buffer_full, FILE_BUFFER_SIZE, _IOFBF, false, "w" ); |
167 | |
168 | ASSERT_EQ(sizeof(data), f_line->write(data, sizeof(data)).value); |
169 | ASSERT_EQ(sizeof(data), f_full->write(data, sizeof(data)).value); |
170 | |
171 | EXPECT_EQ(f_line->get_pos(), size_t(6)); // buffer after the newline |
172 | EXPECT_EQ(f_full->get_pos(), size_t(0)); // buffer all of data |
173 | |
174 | MemoryView src1("hello\n" , 6), dst1(f_line->get_str(), 6); |
175 | EXPECT_MEM_EQ(src1, dst1); |
176 | |
177 | // We can't check the data in f_full, since no data has been written. |
178 | |
179 | const char data2[] = "longer for an \n overflow" ; |
180 | |
181 | ASSERT_EQ(sizeof(data2), f_line->write(data2, sizeof(data2)).value); |
182 | // The line buffer's initial contents should be " file\0" |
183 | // Writing data2 should write up until the newline, even though that doesn't |
184 | // all fit in the buffer. |
185 | |
186 | ASSERT_EQ(sizeof(data2), f_full->write(data2, sizeof(data2)).value); |
187 | // The full buffer's initial contents should be "hello\n file\0" |
188 | // Writing data2 should cause a flush of the buffer, as well as the remainder |
189 | // to be written directly since it doesn't fit in the buffer. |
190 | |
191 | EXPECT_EQ(f_line->get_pos(), size_t(27)); |
192 | EXPECT_EQ(f_full->get_pos(), sizeof(data) + sizeof(data2)); |
193 | |
194 | MemoryView src2("hello\n file\0longer for an \n" , 27), |
195 | dst2(f_line->get_str(), 27); |
196 | EXPECT_MEM_EQ(src2, dst2); |
197 | |
198 | MemoryView src3("hello\n file\0longer for an \n overflow" , 37), |
199 | dst_full_final(f_full->get_str(), 37); |
200 | EXPECT_MEM_EQ(src3, dst_full_final); |
201 | |
202 | ASSERT_EQ(f_line->flush(), 0); |
203 | ASSERT_EQ(f_full->flush(), 0); |
204 | |
205 | EXPECT_EQ(f_line->get_pos(), sizeof(data) + sizeof(data2)); |
206 | MemoryView dst_line_final(f_line->get_str(), 37); |
207 | EXPECT_MEM_EQ(src3, dst_line_final); |
208 | EXPECT_MEM_EQ(src3, dst_full_final); |
209 | |
210 | ASSERT_EQ(f_line->close(), 0); |
211 | ASSERT_EQ(f_full->close(), 0); |
212 | } |
213 | |
214 | TEST(LlvmLibcFileTest, WriteUnbuffered) { |
215 | const char data[] = "written immediately" ; |
216 | constexpr size_t FILE_BUFFER_SIZE = sizeof(data) + 1; |
217 | char file_buffer[FILE_BUFFER_SIZE]; |
218 | StringFile *f = |
219 | new_string_file(file_buffer, FILE_BUFFER_SIZE, _IONBF, false, "w" ); |
220 | |
221 | ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)).value); |
222 | EXPECT_EQ(f->get_pos(), |
223 | sizeof(data)); // no buffering means this is written immediately. |
224 | EXPECT_STREQ(f->get_str(), data); |
225 | |
226 | ASSERT_EQ(f->close(), 0); |
227 | } |
228 | |
229 | TEST(LlvmLibcFileTest, ReadOnly) { |
230 | const char initial_content[] = "1234567890987654321" ; |
231 | constexpr size_t FILE_BUFFER_SIZE = sizeof(initial_content); |
232 | char file_buffer[FILE_BUFFER_SIZE]; |
233 | StringFile *f = |
234 | new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "r" ); |
235 | f->reset_and_fill(initial_content, sizeof(initial_content)); |
236 | |
237 | constexpr size_t READ_SIZE = sizeof(initial_content) / 2; |
238 | char read_data[READ_SIZE]; |
239 | ASSERT_EQ(READ_SIZE, f->read(read_data, READ_SIZE).value); |
240 | EXPECT_FALSE(f->iseof()); |
241 | // Reading less than file buffer worth will still read one |
242 | // full buffer worth of data. |
243 | EXPECT_STREQ(file_buffer, initial_content); |
244 | EXPECT_STREQ(file_buffer, f->get_str()); |
245 | EXPECT_EQ(FILE_BUFFER_SIZE, f->get_pos()); |
246 | // The read data should match what was supposed to be read anyway. |
247 | MemoryView src1(initial_content, READ_SIZE), dst1(read_data, READ_SIZE); |
248 | EXPECT_MEM_EQ(src1, dst1); |
249 | |
250 | // Reading another buffer worth should read out everything in |
251 | // the file. |
252 | ASSERT_EQ(READ_SIZE, f->read(read_data, READ_SIZE).value); |
253 | EXPECT_FALSE(f->iseof()); |
254 | MemoryView src2(initial_content + READ_SIZE, READ_SIZE), |
255 | dst2(read_data, READ_SIZE); |
256 | EXPECT_MEM_EQ(src2, dst2); |
257 | |
258 | // Another read should trigger an EOF. |
259 | ASSERT_GT(READ_SIZE, f->read(read_data, READ_SIZE).value); |
260 | EXPECT_TRUE(f->iseof()); |
261 | |
262 | // Reset the pos to the beginning of the file which should allow |
263 | // reading again. |
264 | for (size_t i = 0; i < READ_SIZE; ++i) |
265 | read_data[i] = 0; |
266 | f->seek(0, SEEK_SET); |
267 | ASSERT_EQ(READ_SIZE, f->read(read_data, READ_SIZE).value); |
268 | MemoryView src3(initial_content, READ_SIZE), dst3(read_data, READ_SIZE); |
269 | EXPECT_MEM_EQ(src3, dst3); |
270 | |
271 | { |
272 | // This is not a writable file. |
273 | auto result = f->write(initial_content, sizeof(initial_content)); |
274 | EXPECT_EQ(result.value, size_t(0)); |
275 | EXPECT_TRUE(f->error()); |
276 | EXPECT_TRUE(result.has_error()); |
277 | } |
278 | |
279 | ASSERT_EQ(f->close(), 0); |
280 | } |
281 | |
282 | TEST(LlvmLibcFileTest, ReadSeekCurAndRead) { |
283 | const char initial_content[] = "1234567890987654321" ; |
284 | constexpr size_t FILE_BUFFER_SIZE = sizeof(initial_content); |
285 | char file_buffer[FILE_BUFFER_SIZE]; |
286 | StringFile *f = |
287 | new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "r" ); |
288 | f->reset_and_fill(initial_content, sizeof(initial_content)); |
289 | |
290 | constexpr size_t READ_SIZE = 5; |
291 | char data[READ_SIZE]; |
292 | data[READ_SIZE - 1] = '\0'; |
293 | ASSERT_EQ(f->read(data, READ_SIZE - 1).value, READ_SIZE - 1); |
294 | ASSERT_STREQ(data, "1234" ); |
295 | ASSERT_EQ(f->seek(5, SEEK_CUR).value(), 0); |
296 | ASSERT_EQ(f->read(data, READ_SIZE - 1).value, READ_SIZE - 1); |
297 | ASSERT_STREQ(data, "0987" ); |
298 | ASSERT_EQ(f->seek(-5, SEEK_CUR).value(), 0); |
299 | ASSERT_EQ(f->read(data, READ_SIZE - 1).value, READ_SIZE - 1); |
300 | ASSERT_STREQ(data, "9098" ); |
301 | ASSERT_EQ(f->close(), 0); |
302 | } |
303 | |
304 | TEST(LlvmLibcFileTest, AppendOnly) { |
305 | const char initial_content[] = "1234567890987654321" ; |
306 | const char write_data[] = "append" ; |
307 | constexpr size_t FILE_BUFFER_SIZE = sizeof(write_data) * 3 / 2; |
308 | char file_buffer[FILE_BUFFER_SIZE]; |
309 | StringFile *f = |
310 | new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "a" ); |
311 | f->reset_and_fill(initial_content, sizeof(initial_content)); |
312 | |
313 | constexpr size_t READ_SIZE = 5; |
314 | char read_data[READ_SIZE]; |
315 | |
316 | { |
317 | // This is not a readable file. |
318 | auto result = f->read(read_data, READ_SIZE); |
319 | EXPECT_EQ(result.value, size_t(0)); |
320 | EXPECT_TRUE(f->error()); |
321 | EXPECT_TRUE(result.has_error()); |
322 | } |
323 | |
324 | // Write should succeed but will be buffered in the file stream. |
325 | ASSERT_EQ(f->write(write_data, sizeof(write_data)).value, sizeof(write_data)); |
326 | EXPECT_EQ(f->get_pos(), size_t(0)); |
327 | // Flushing will write to the file. |
328 | EXPECT_EQ(f->flush(), int(0)); |
329 | EXPECT_EQ(f->get_pos(), sizeof(write_data) + sizeof(initial_content)); |
330 | |
331 | ASSERT_EQ(f->close(), 0); |
332 | } |
333 | |
334 | TEST(LlvmLibcFileTest, WriteUpdate) { |
335 | const char data[] = "hello, file" ; |
336 | constexpr size_t FILE_BUFFER_SIZE = sizeof(data) * 3 / 2; |
337 | char file_buffer[FILE_BUFFER_SIZE]; |
338 | StringFile *f = |
339 | new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "w+" ); |
340 | |
341 | ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)).value); |
342 | EXPECT_EQ(f->get_pos(), size_t(0)); // Data is buffered in the file stream |
343 | |
344 | ASSERT_EQ(f->seek(0, SEEK_SET).value(), 0); |
345 | |
346 | // Seek flushes the stream buffer so we can read the previously written data. |
347 | char read_data[sizeof(data)]; |
348 | ASSERT_EQ(f->read(read_data, sizeof(data)).value, sizeof(data)); |
349 | EXPECT_STREQ(read_data, data); |
350 | |
351 | ASSERT_EQ(f->close(), 0); |
352 | } |
353 | |
354 | TEST(LlvmLibcFileTest, ReadUpdate) { |
355 | const char initial_content[] = "1234567890987654321" ; |
356 | constexpr size_t FILE_BUFFER_SIZE = sizeof(initial_content); |
357 | char file_buffer[FILE_BUFFER_SIZE]; |
358 | StringFile *f = |
359 | new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "r+" ); |
360 | f->reset_and_fill(initial_content, sizeof(initial_content)); |
361 | |
362 | constexpr size_t READ_SIZE = sizeof(initial_content) / 2; |
363 | char read_data[READ_SIZE]; |
364 | ASSERT_EQ(READ_SIZE, f->read(read_data, READ_SIZE).value); |
365 | EXPECT_FALSE(f->iseof()); |
366 | // Reading less than file buffer worth will still read one |
367 | // full buffer worth of data. |
368 | EXPECT_STREQ(file_buffer, initial_content); |
369 | EXPECT_STREQ(file_buffer, f->get_str()); |
370 | EXPECT_EQ(FILE_BUFFER_SIZE, f->get_pos()); |
371 | // The read data should match what was supposed to be read anyway. |
372 | MemoryView src1(initial_content, READ_SIZE), dst1(read_data, READ_SIZE); |
373 | EXPECT_MEM_EQ(src1, dst1); |
374 | |
375 | ASSERT_EQ(f->seek(0, SEEK_SET).value(), 0); |
376 | const char write_data[] = "hello, file" ; |
377 | ASSERT_EQ(sizeof(write_data), f->write(write_data, sizeof(write_data)).value); |
378 | EXPECT_STREQ(file_buffer, write_data); |
379 | ASSERT_EQ(f->flush(), 0); |
380 | MemoryView dst2(f->get_str(), sizeof(write_data)), |
381 | src2(write_data, sizeof(write_data)); |
382 | EXPECT_MEM_EQ(src2, dst2); |
383 | |
384 | ASSERT_EQ(f->close(), 0); |
385 | } |
386 | |
387 | TEST(LlvmLibcFileTest, AppendUpdate) { |
388 | const char initial_content[] = "1234567890987654321" ; |
389 | const char data[] = "hello, file" ; |
390 | constexpr size_t FILE_BUFFER_SIZE = sizeof(data) * 3 / 2; |
391 | char file_buffer[FILE_BUFFER_SIZE]; |
392 | StringFile *f = |
393 | new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "a+" ); |
394 | f->reset_and_fill(initial_content, sizeof(initial_content)); |
395 | |
396 | ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)).value); |
397 | EXPECT_EQ(f->get_pos(), size_t(0)); // Data is buffered in the file stream |
398 | ASSERT_EQ(f->flush(), 0); |
399 | // The flush should write |data| to the endof the file. |
400 | EXPECT_EQ(f->get_pos(), sizeof(data) + sizeof(initial_content)); |
401 | |
402 | ASSERT_EQ(f->seek(0, SEEK_SET).value(), 0); |
403 | // Seeking to the beginning of the file should not affect the place |
404 | // where write happens. |
405 | ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)).value); |
406 | ASSERT_EQ(f->flush(), 0); |
407 | EXPECT_EQ(f->get_pos(), sizeof(data) * 2 + sizeof(initial_content)); |
408 | MemoryView src1(initial_content, sizeof(initial_content)), |
409 | dst1(f->get_str(), sizeof(initial_content)); |
410 | EXPECT_MEM_EQ(src1, dst1); |
411 | MemoryView src2(data, sizeof(data)), |
412 | dst2(f->get_str() + sizeof(initial_content), sizeof(data)); |
413 | EXPECT_MEM_EQ(src2, dst2); |
414 | MemoryView src3(data, sizeof(data)), |
415 | dst3(f->get_str() + sizeof(initial_content) + sizeof(data), sizeof(data)); |
416 | EXPECT_MEM_EQ(src3, dst3); |
417 | |
418 | // Reads can happen from any point. |
419 | ASSERT_EQ(f->seek(0, SEEK_SET).value(), 0); |
420 | constexpr size_t READ_SIZE = 10; |
421 | char read_data[READ_SIZE]; |
422 | ASSERT_EQ(READ_SIZE, f->read(read_data, READ_SIZE).value); |
423 | MemoryView src4(initial_content, READ_SIZE), dst4(read_data, READ_SIZE); |
424 | EXPECT_MEM_EQ(src4, dst4); |
425 | |
426 | ASSERT_EQ(f->close(), 0); |
427 | } |
428 | |
429 | TEST(LlvmLibcFileTest, SmallBuffer) { |
430 | const char WRITE_DATA[] = "small buffer" ; |
431 | constexpr size_t WRITE_SIZE = sizeof(WRITE_DATA); |
432 | constexpr size_t FILE_BUFFER_SIZE = sizeof(WRITE_DATA) / 2 - 1; |
433 | char file_buffer[FILE_BUFFER_SIZE]; |
434 | StringFile *f = |
435 | new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "w" ); |
436 | |
437 | ASSERT_EQ(WRITE_SIZE, f->write(WRITE_DATA, WRITE_SIZE).value); |
438 | // Since data much larger than the buffer is being written, all of it should |
439 | // be available in the file without a flush operation. |
440 | EXPECT_EQ(f->get_pos(), sizeof(WRITE_DATA)); |
441 | ASSERT_STREQ(f->get_str(), WRITE_DATA); |
442 | |
443 | ASSERT_EQ(f->close(), 0); |
444 | } |
445 | |
446 | TEST(LlvmLibcFileTest, ZeroLengthBuffer) { |
447 | const char WRITE_DATA[] = "small buffer" ; |
448 | constexpr size_t WRITE_SIZE = sizeof(WRITE_DATA); |
449 | StringFile *f_fbf = new_string_file(nullptr, 0, _IOFBF, true, "w" ); |
450 | StringFile *f_lbf = new_string_file(nullptr, 0, _IOLBF, true, "w" ); |
451 | StringFile *f_nbf = new_string_file(nullptr, 0, _IONBF, true, "w" ); |
452 | |
453 | ASSERT_EQ(WRITE_SIZE, f_fbf->write(WRITE_DATA, WRITE_SIZE).value); |
454 | ASSERT_EQ(WRITE_SIZE, f_lbf->write(WRITE_DATA, WRITE_SIZE).value); |
455 | ASSERT_EQ(WRITE_SIZE, f_nbf->write(WRITE_DATA, WRITE_SIZE).value); |
456 | // Since there is no buffer space, all of the written data should |
457 | // be available in the file without a flush operation. |
458 | EXPECT_EQ(f_fbf->get_pos(), sizeof(WRITE_DATA)); |
459 | EXPECT_EQ(f_lbf->get_pos(), sizeof(WRITE_DATA)); |
460 | EXPECT_EQ(f_nbf->get_pos(), sizeof(WRITE_DATA)); |
461 | ASSERT_STREQ(f_fbf->get_str(), WRITE_DATA); |
462 | ASSERT_STREQ(f_lbf->get_str(), WRITE_DATA); |
463 | ASSERT_STREQ(f_nbf->get_str(), WRITE_DATA); |
464 | |
465 | ASSERT_EQ(f_fbf->close(), 0); |
466 | ASSERT_EQ(f_lbf->close(), 0); |
467 | ASSERT_EQ(f_nbf->close(), 0); |
468 | } |
469 | |
470 | TEST(LlvmLibcFileTest, WriteNothing) { |
471 | const char WRITE_DATA[] = "" ; |
472 | constexpr size_t WRITE_SIZE = 0; |
473 | constexpr size_t FILE_BUFFER_SIZE = 5; |
474 | char file_buffer_fbf[FILE_BUFFER_SIZE]; |
475 | char file_buffer_lbf[FILE_BUFFER_SIZE]; |
476 | char file_buffer_nbf[FILE_BUFFER_SIZE]; |
477 | StringFile *f_fbf = |
478 | new_string_file(file_buffer_fbf, FILE_BUFFER_SIZE, _IOFBF, false, "w" ); |
479 | StringFile *f_lbf = |
480 | new_string_file(file_buffer_lbf, FILE_BUFFER_SIZE, _IOLBF, false, "w" ); |
481 | StringFile *f_nbf = |
482 | new_string_file(file_buffer_nbf, FILE_BUFFER_SIZE, _IONBF, false, "w" ); |
483 | |
484 | ASSERT_EQ(WRITE_SIZE, f_fbf->write(WRITE_DATA, WRITE_SIZE).value); |
485 | ASSERT_EQ(WRITE_SIZE, f_lbf->write(WRITE_DATA, WRITE_SIZE).value); |
486 | ASSERT_EQ(WRITE_SIZE, f_nbf->write(WRITE_DATA, WRITE_SIZE).value); |
487 | |
488 | ASSERT_FALSE(f_fbf->error_unlocked()); |
489 | ASSERT_FALSE(f_lbf->error_unlocked()); |
490 | ASSERT_FALSE(f_nbf->error_unlocked()); |
491 | |
492 | ASSERT_EQ(f_fbf->close(), 0); |
493 | ASSERT_EQ(f_lbf->close(), 0); |
494 | ASSERT_EQ(f_nbf->close(), 0); |
495 | } |
496 | |