xref: /aosp_15_r20/external/llvm-libc/test/src/__support/File/file_test.cpp (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
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);
str_close(LIBC_NAMESPACE::File * f)35   static int str_close(LIBC_NAMESPACE::File *f) {
36     delete reinterpret_cast<StringFile *>(f);
37     return 0;
38   }
39 
40 public:
StringFile(char * buffer,size_t buflen,int bufmode,bool owned,ModeFlags modeflags)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 
reset()52   void reset() { pos = 0; }
get_pos() const53   size_t get_pos() const { return pos; }
get_str()54   char *get_str() { return str; }
55 
56   // Use this method to prefill the file.
reset_and_fill(const char * data,size_t len)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 
str_read(LIBC_NAMESPACE::File * f,void * data,size_t len)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 
str_write(LIBC_NAMESPACE::File * f,const void * data,size_t len)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 
str_seek(LIBC_NAMESPACE::File * f,off_t offset,int whence)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 
new_string_file(char * buffer,size_t buflen,int bufmode,bool owned,const char * mode)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 
TEST(LlvmLibcFileTest,WriteOnly)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 
TEST(LlvmLibcFileTest,WriteLineBuffered)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 
TEST(LlvmLibcFileTest,WriteUnbuffered)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 
TEST(LlvmLibcFileTest,ReadOnly)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 
TEST(LlvmLibcFileTest,ReadSeekCurAndRead)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 
TEST(LlvmLibcFileTest,AppendOnly)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 
TEST(LlvmLibcFileTest,WriteUpdate)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 
TEST(LlvmLibcFileTest,ReadUpdate)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 
TEST(LlvmLibcFileTest,AppendUpdate)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 
TEST(LlvmLibcFileTest,SmallBuffer)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 
TEST(LlvmLibcFileTest,ZeroLengthBuffer)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 
TEST(LlvmLibcFileTest,WriteNothing)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