xref: /llvm-project/libc/test/src/__support/File/file_test.cpp (revision 33bdb53d864e3e244d8fd5649062f17b7d4c958d)
14ef02da0SSiva Chandra Reddy //===-- Unittests for platform independent file class ---------------------===//
24ef02da0SSiva Chandra Reddy //
34ef02da0SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44ef02da0SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information.
54ef02da0SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64ef02da0SSiva Chandra Reddy //
74ef02da0SSiva Chandra Reddy //===----------------------------------------------------------------------===//
84ef02da0SSiva Chandra Reddy 
9d06308dfSSiva Chandra Reddy #include "src/__support/CPP/new.h"
104ef02da0SSiva Chandra Reddy #include "src/__support/File/file.h"
119beb8d11SMichael Jones #include "src/__support/error_or.h"
12af1315c2SSiva Chandra Reddy #include "test/UnitTest/MemoryMatcher.h"
13af1315c2SSiva Chandra Reddy #include "test/UnitTest/Test.h"
144ef02da0SSiva Chandra Reddy 
15*33bdb53dSJob Henandez Lara #include "hdr/types/size_t.h"
164ef02da0SSiva Chandra Reddy 
17b6bc9d72SGuillaume Chatelet using ModeFlags = LIBC_NAMESPACE::File::ModeFlags;
18b6bc9d72SGuillaume Chatelet using MemoryView = LIBC_NAMESPACE::testing::MemoryView;
19b6bc9d72SGuillaume Chatelet using LIBC_NAMESPACE::ErrorOr;
20b6bc9d72SGuillaume Chatelet using LIBC_NAMESPACE::File;
21b6bc9d72SGuillaume Chatelet using LIBC_NAMESPACE::FileIOResult;
224ef02da0SSiva Chandra Reddy 
23f9868aa7SSiva Chandra Reddy class StringFile : public File {
244ef02da0SSiva Chandra Reddy   static constexpr size_t SIZE = 512;
254ef02da0SSiva Chandra Reddy   size_t pos;
264ef02da0SSiva Chandra Reddy   char str[SIZE] = {0};
274ef02da0SSiva Chandra Reddy   size_t eof_marker;
284ef02da0SSiva Chandra Reddy   bool write_append;
294ef02da0SSiva Chandra Reddy 
30b6bc9d72SGuillaume Chatelet   static FileIOResult str_read(LIBC_NAMESPACE::File *f, void *data, size_t len);
31b6bc9d72SGuillaume Chatelet   static FileIOResult str_write(LIBC_NAMESPACE::File *f, const void *data,
329beb8d11SMichael Jones                                 size_t len);
337776fba4SMikhail R. Gadelha   static ErrorOr<off_t> str_seek(LIBC_NAMESPACE::File *f, off_t offset,
34b6bc9d72SGuillaume Chatelet                                  int whence);
35b6bc9d72SGuillaume Chatelet   static int str_close(LIBC_NAMESPACE::File *f) {
3675d70b73SSiva Chandra Reddy     delete reinterpret_cast<StringFile *>(f);
3775d70b73SSiva Chandra Reddy     return 0;
3875d70b73SSiva Chandra Reddy   }
394ef02da0SSiva Chandra Reddy 
404ef02da0SSiva Chandra Reddy public:
414ef02da0SSiva Chandra Reddy   explicit StringFile(char *buffer, size_t buflen, int bufmode, bool owned,
424ef02da0SSiva Chandra Reddy                       ModeFlags modeflags)
43b6bc9d72SGuillaume Chatelet       : LIBC_NAMESPACE::File(&str_write, &str_read, &str_seek, &str_close,
44b6bc9d72SGuillaume Chatelet                              reinterpret_cast<uint8_t *>(buffer), buflen,
45b6bc9d72SGuillaume Chatelet                              bufmode, owned, modeflags),
464ef02da0SSiva Chandra Reddy         pos(0), eof_marker(0), write_append(false) {
47b6bc9d72SGuillaume Chatelet     if (modeflags &
48b6bc9d72SGuillaume Chatelet         static_cast<ModeFlags>(LIBC_NAMESPACE::File::OpenMode::APPEND))
494ef02da0SSiva Chandra Reddy       write_append = true;
504ef02da0SSiva Chandra Reddy   }
514ef02da0SSiva Chandra Reddy 
524ef02da0SSiva Chandra Reddy   void reset() { pos = 0; }
534ef02da0SSiva Chandra Reddy   size_t get_pos() const { return pos; }
544ef02da0SSiva Chandra Reddy   char *get_str() { return str; }
554ef02da0SSiva Chandra Reddy 
564ef02da0SSiva Chandra Reddy   // Use this method to prefill the file.
574ef02da0SSiva Chandra Reddy   void reset_and_fill(const char *data, size_t len) {
584ef02da0SSiva Chandra Reddy     size_t i;
594ef02da0SSiva Chandra Reddy     for (i = 0; i < len && i < SIZE; ++i) {
604ef02da0SSiva Chandra Reddy       str[i] = data[i];
614ef02da0SSiva Chandra Reddy     }
624ef02da0SSiva Chandra Reddy     pos = 0;
634ef02da0SSiva Chandra Reddy     eof_marker = i;
644ef02da0SSiva Chandra Reddy   }
654ef02da0SSiva Chandra Reddy };
664ef02da0SSiva Chandra Reddy 
67b6bc9d72SGuillaume Chatelet FileIOResult StringFile::str_read(LIBC_NAMESPACE::File *f, void *data,
689beb8d11SMichael Jones                                   size_t len) {
694ef02da0SSiva Chandra Reddy   StringFile *sf = static_cast<StringFile *>(f);
704ef02da0SSiva Chandra Reddy   if (sf->pos >= sf->eof_marker)
714ef02da0SSiva Chandra Reddy     return 0;
724ef02da0SSiva Chandra Reddy   size_t i = 0;
734ef02da0SSiva Chandra Reddy   for (i = 0; i < len; ++i)
744ef02da0SSiva Chandra Reddy     reinterpret_cast<char *>(data)[i] = sf->str[sf->pos + i];
754ef02da0SSiva Chandra Reddy   sf->pos += i;
764ef02da0SSiva Chandra Reddy   return i;
774ef02da0SSiva Chandra Reddy }
784ef02da0SSiva Chandra Reddy 
79b6bc9d72SGuillaume Chatelet FileIOResult StringFile::str_write(LIBC_NAMESPACE::File *f, const void *data,
804ef02da0SSiva Chandra Reddy                                    size_t len) {
814ef02da0SSiva Chandra Reddy   StringFile *sf = static_cast<StringFile *>(f);
824ef02da0SSiva Chandra Reddy   if (sf->write_append)
834ef02da0SSiva Chandra Reddy     sf->pos = sf->eof_marker;
844ef02da0SSiva Chandra Reddy   if (sf->pos >= SIZE)
854ef02da0SSiva Chandra Reddy     return 0;
864ef02da0SSiva Chandra Reddy   size_t i = 0;
874ef02da0SSiva Chandra Reddy   for (i = 0; i < len && sf->pos < SIZE; ++i, ++sf->pos)
884ef02da0SSiva Chandra Reddy     sf->str[sf->pos] = reinterpret_cast<const char *>(data)[i];
894ef02da0SSiva Chandra Reddy   // Move the eof marker if the data was written beyond the current eof marker.
904ef02da0SSiva Chandra Reddy   if (sf->pos > sf->eof_marker)
914ef02da0SSiva Chandra Reddy     sf->eof_marker = sf->pos;
924ef02da0SSiva Chandra Reddy   return i;
934ef02da0SSiva Chandra Reddy }
944ef02da0SSiva Chandra Reddy 
957776fba4SMikhail R. Gadelha ErrorOr<off_t> StringFile::str_seek(LIBC_NAMESPACE::File *f, off_t offset,
969beb8d11SMichael Jones                                     int whence) {
974ef02da0SSiva Chandra Reddy   StringFile *sf = static_cast<StringFile *>(f);
984ef02da0SSiva Chandra Reddy   if (whence == SEEK_SET)
994ef02da0SSiva Chandra Reddy     sf->pos = offset;
1004ef02da0SSiva Chandra Reddy   if (whence == SEEK_CUR)
1014ef02da0SSiva Chandra Reddy     sf->pos += offset;
1024ef02da0SSiva Chandra Reddy   if (whence == SEEK_END)
1034ef02da0SSiva Chandra Reddy     sf->pos = SIZE + offset;
10443e52ad5SSiva Chandra Reddy   return sf->pos;
1054ef02da0SSiva Chandra Reddy }
1064ef02da0SSiva Chandra Reddy 
1074ef02da0SSiva Chandra Reddy StringFile *new_string_file(char *buffer, size_t buflen, int bufmode,
1084ef02da0SSiva Chandra Reddy                             bool owned, const char *mode) {
109b6bc9d72SGuillaume Chatelet   LIBC_NAMESPACE::AllocChecker ac;
110d06308dfSSiva Chandra Reddy   // We will just assume the allocation succeeds. We cannot test anything
111d06308dfSSiva Chandra Reddy   // otherwise.
112d06308dfSSiva Chandra Reddy   return new (ac) StringFile(buffer, buflen, bufmode, owned,
113b6bc9d72SGuillaume Chatelet                              LIBC_NAMESPACE::File::mode_flags(mode));
1144ef02da0SSiva Chandra Reddy }
1154ef02da0SSiva Chandra Reddy 
1164ef02da0SSiva Chandra Reddy TEST(LlvmLibcFileTest, WriteOnly) {
1174ef02da0SSiva Chandra Reddy   const char data[] = "hello, file";
1184ef02da0SSiva Chandra Reddy   constexpr size_t FILE_BUFFER_SIZE = sizeof(data) * 3 / 2;
1194ef02da0SSiva Chandra Reddy   char file_buffer[FILE_BUFFER_SIZE];
1206ce490e5SMichael Jones   StringFile *f =
1216ce490e5SMichael Jones       new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "w");
1224ef02da0SSiva Chandra Reddy 
1239beb8d11SMichael Jones   ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)).value);
1244ef02da0SSiva Chandra Reddy   EXPECT_EQ(f->get_pos(), size_t(0)); // Data is buffered in the file stream
1254ef02da0SSiva Chandra Reddy   ASSERT_EQ(f->flush(), 0);
1264ef02da0SSiva Chandra Reddy   EXPECT_EQ(f->get_pos(), sizeof(data)); // Data should now be available
1274ef02da0SSiva Chandra Reddy   EXPECT_STREQ(f->get_str(), data);
1284ef02da0SSiva Chandra Reddy 
1294ef02da0SSiva Chandra Reddy   f->reset();
1304ef02da0SSiva Chandra Reddy   ASSERT_EQ(f->get_pos(), size_t(0));
1319beb8d11SMichael Jones   ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)).value);
1324ef02da0SSiva Chandra Reddy   EXPECT_EQ(f->get_pos(), size_t(0)); // Data is buffered in the file stream
1334ef02da0SSiva Chandra Reddy   // The second write should trigger a buffer flush.
1349beb8d11SMichael Jones   ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)).value);
1354ef02da0SSiva Chandra Reddy   EXPECT_GE(f->get_pos(), size_t(0));
1364ef02da0SSiva Chandra Reddy   ASSERT_EQ(f->flush(), 0);
1374ef02da0SSiva Chandra Reddy   EXPECT_EQ(f->get_pos(), 2 * sizeof(data));
1386ce490e5SMichael Jones   MemoryView src1("hello, file\0hello, file", sizeof(data) * 2),
1396ce490e5SMichael Jones       dst1(f->get_str(), sizeof(data) * 2);
1406ce490e5SMichael Jones   EXPECT_MEM_EQ(src1, dst1);
1414ef02da0SSiva Chandra Reddy 
1424ef02da0SSiva Chandra Reddy   char read_data[sizeof(data)];
1439beb8d11SMichael Jones   {
1444ef02da0SSiva Chandra Reddy     // This is not a readable file.
1459beb8d11SMichael Jones     auto result = f->read(read_data, sizeof(data));
1469beb8d11SMichael Jones     EXPECT_EQ(result.value, size_t(0));
1474ef02da0SSiva Chandra Reddy     EXPECT_TRUE(f->error());
1489beb8d11SMichael Jones     EXPECT_TRUE(result.has_error());
1499beb8d11SMichael Jones   }
1504ef02da0SSiva Chandra Reddy 
15175d70b73SSiva Chandra Reddy   ASSERT_EQ(f->close(), 0);
1524ef02da0SSiva Chandra Reddy }
1534ef02da0SSiva Chandra Reddy 
1546ce490e5SMichael Jones TEST(LlvmLibcFileTest, WriteLineBuffered) {
1556ce490e5SMichael Jones   const char data[] = "hello\n file";
1566ce490e5SMichael Jones   constexpr size_t FILE_BUFFER_SIZE = sizeof(data) * 3 / 2;
1576ce490e5SMichael Jones 
1586ce490e5SMichael Jones   char file_buffer_line[FILE_BUFFER_SIZE];
1596ce490e5SMichael Jones   char file_buffer_full[FILE_BUFFER_SIZE];
1606ce490e5SMichael Jones 
1616ce490e5SMichael Jones   StringFile *f_line =
1626ce490e5SMichael Jones       new_string_file(file_buffer_line, FILE_BUFFER_SIZE, _IOLBF, false, "w");
1636ce490e5SMichael Jones   // We also initialize a fully buffered file we'll do the same writes to for
1646ce490e5SMichael Jones   // comparison.
1656ce490e5SMichael Jones   StringFile *f_full =
1666ce490e5SMichael Jones       new_string_file(file_buffer_full, FILE_BUFFER_SIZE, _IOFBF, false, "w");
1676ce490e5SMichael Jones 
1689beb8d11SMichael Jones   ASSERT_EQ(sizeof(data), f_line->write(data, sizeof(data)).value);
1699beb8d11SMichael Jones   ASSERT_EQ(sizeof(data), f_full->write(data, sizeof(data)).value);
1706ce490e5SMichael Jones 
1716ce490e5SMichael Jones   EXPECT_EQ(f_line->get_pos(), size_t(6)); // buffer after the newline
1726ce490e5SMichael Jones   EXPECT_EQ(f_full->get_pos(), size_t(0)); // buffer all of data
1736ce490e5SMichael Jones 
1746ce490e5SMichael Jones   MemoryView src1("hello\n", 6), dst1(f_line->get_str(), 6);
1756ce490e5SMichael Jones   EXPECT_MEM_EQ(src1, dst1);
1766ce490e5SMichael Jones 
1776ce490e5SMichael Jones   // We can't check the data in f_full, since no data has been written.
1786ce490e5SMichael Jones 
1796ce490e5SMichael Jones   const char data2[] = "longer for an \n overflow";
1806ce490e5SMichael Jones 
1819beb8d11SMichael Jones   ASSERT_EQ(sizeof(data2), f_line->write(data2, sizeof(data2)).value);
1826ce490e5SMichael Jones   // The line buffer's initial contents should be " file\0"
1836ce490e5SMichael Jones   // Writing data2 should write up until the newline, even though that doesn't
1846ce490e5SMichael Jones   // all fit in the buffer.
1856ce490e5SMichael Jones 
1869beb8d11SMichael Jones   ASSERT_EQ(sizeof(data2), f_full->write(data2, sizeof(data2)).value);
1876ce490e5SMichael Jones   // The full buffer's initial contents should be "hello\n file\0"
1886ce490e5SMichael Jones   // Writing data2 should cause a flush of the buffer, as well as the remainder
1896ce490e5SMichael Jones   // to be written directly since it doesn't fit in the buffer.
1906ce490e5SMichael Jones 
1916ce490e5SMichael Jones   EXPECT_EQ(f_line->get_pos(), size_t(27));
1926ce490e5SMichael Jones   EXPECT_EQ(f_full->get_pos(), sizeof(data) + sizeof(data2));
1936ce490e5SMichael Jones 
1946ce490e5SMichael Jones   MemoryView src2("hello\n file\0longer for an \n", 27),
1956ce490e5SMichael Jones       dst2(f_line->get_str(), 27);
1966ce490e5SMichael Jones   EXPECT_MEM_EQ(src2, dst2);
1976ce490e5SMichael Jones 
1986ce490e5SMichael Jones   MemoryView src3("hello\n file\0longer for an \n overflow", 37),
1996ce490e5SMichael Jones       dst_full_final(f_full->get_str(), 37);
2006ce490e5SMichael Jones   EXPECT_MEM_EQ(src3, dst_full_final);
2016ce490e5SMichael Jones 
2026ce490e5SMichael Jones   ASSERT_EQ(f_line->flush(), 0);
2036ce490e5SMichael Jones   ASSERT_EQ(f_full->flush(), 0);
2046ce490e5SMichael Jones 
2056ce490e5SMichael Jones   EXPECT_EQ(f_line->get_pos(), sizeof(data) + sizeof(data2));
2066ce490e5SMichael Jones   MemoryView dst_line_final(f_line->get_str(), 37);
2076ce490e5SMichael Jones   EXPECT_MEM_EQ(src3, dst_line_final);
2086ce490e5SMichael Jones   EXPECT_MEM_EQ(src3, dst_full_final);
2096ce490e5SMichael Jones 
21075d70b73SSiva Chandra Reddy   ASSERT_EQ(f_line->close(), 0);
21175d70b73SSiva Chandra Reddy   ASSERT_EQ(f_full->close(), 0);
2126ce490e5SMichael Jones }
2136ce490e5SMichael Jones 
2146ce490e5SMichael Jones TEST(LlvmLibcFileTest, WriteUnbuffered) {
2156ce490e5SMichael Jones   const char data[] = "written immediately";
2166ce490e5SMichael Jones   constexpr size_t FILE_BUFFER_SIZE = sizeof(data) + 1;
2176ce490e5SMichael Jones   char file_buffer[FILE_BUFFER_SIZE];
2186ce490e5SMichael Jones   StringFile *f =
2196ce490e5SMichael Jones       new_string_file(file_buffer, FILE_BUFFER_SIZE, _IONBF, false, "w");
2206ce490e5SMichael Jones 
2219beb8d11SMichael Jones   ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)).value);
2226ce490e5SMichael Jones   EXPECT_EQ(f->get_pos(),
2236ce490e5SMichael Jones             sizeof(data)); // no buffering means this is written immediately.
2246ce490e5SMichael Jones   EXPECT_STREQ(f->get_str(), data);
2256ce490e5SMichael Jones 
22675d70b73SSiva Chandra Reddy   ASSERT_EQ(f->close(), 0);
2276ce490e5SMichael Jones }
2286ce490e5SMichael Jones 
2294ef02da0SSiva Chandra Reddy TEST(LlvmLibcFileTest, ReadOnly) {
2304ef02da0SSiva Chandra Reddy   const char initial_content[] = "1234567890987654321";
2314ef02da0SSiva Chandra Reddy   constexpr size_t FILE_BUFFER_SIZE = sizeof(initial_content);
2324ef02da0SSiva Chandra Reddy   char file_buffer[FILE_BUFFER_SIZE];
2336ce490e5SMichael Jones   StringFile *f =
2346ce490e5SMichael Jones       new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "r");
2354ef02da0SSiva Chandra Reddy   f->reset_and_fill(initial_content, sizeof(initial_content));
2364ef02da0SSiva Chandra Reddy 
2374ef02da0SSiva Chandra Reddy   constexpr size_t READ_SIZE = sizeof(initial_content) / 2;
2384ef02da0SSiva Chandra Reddy   char read_data[READ_SIZE];
2399beb8d11SMichael Jones   ASSERT_EQ(READ_SIZE, f->read(read_data, READ_SIZE).value);
2404ef02da0SSiva Chandra Reddy   EXPECT_FALSE(f->iseof());
2414ef02da0SSiva Chandra Reddy   // Reading less than file buffer worth will still read one
2424ef02da0SSiva Chandra Reddy   // full buffer worth of data.
2434ef02da0SSiva Chandra Reddy   EXPECT_STREQ(file_buffer, initial_content);
2444ef02da0SSiva Chandra Reddy   EXPECT_STREQ(file_buffer, f->get_str());
2454ef02da0SSiva Chandra Reddy   EXPECT_EQ(FILE_BUFFER_SIZE, f->get_pos());
2464ef02da0SSiva Chandra Reddy   // The read data should match what was supposed to be read anyway.
2474ef02da0SSiva Chandra Reddy   MemoryView src1(initial_content, READ_SIZE), dst1(read_data, READ_SIZE);
2484ef02da0SSiva Chandra Reddy   EXPECT_MEM_EQ(src1, dst1);
2494ef02da0SSiva Chandra Reddy 
2504ef02da0SSiva Chandra Reddy   // Reading another buffer worth should read out everything in
2514ef02da0SSiva Chandra Reddy   // the file.
2529beb8d11SMichael Jones   ASSERT_EQ(READ_SIZE, f->read(read_data, READ_SIZE).value);
2534ef02da0SSiva Chandra Reddy   EXPECT_FALSE(f->iseof());
2544ef02da0SSiva Chandra Reddy   MemoryView src2(initial_content + READ_SIZE, READ_SIZE),
2554ef02da0SSiva Chandra Reddy       dst2(read_data, READ_SIZE);
2564ef02da0SSiva Chandra Reddy   EXPECT_MEM_EQ(src2, dst2);
2574ef02da0SSiva Chandra Reddy 
2584ef02da0SSiva Chandra Reddy   // Another read should trigger an EOF.
2599beb8d11SMichael Jones   ASSERT_GT(READ_SIZE, f->read(read_data, READ_SIZE).value);
2604ef02da0SSiva Chandra Reddy   EXPECT_TRUE(f->iseof());
2614ef02da0SSiva Chandra Reddy 
2624ef02da0SSiva Chandra Reddy   // Reset the pos to the beginning of the file which should allow
2634ef02da0SSiva Chandra Reddy   // reading again.
2644ef02da0SSiva Chandra Reddy   for (size_t i = 0; i < READ_SIZE; ++i)
2654ef02da0SSiva Chandra Reddy     read_data[i] = 0;
2664ef02da0SSiva Chandra Reddy   f->seek(0, SEEK_SET);
2679beb8d11SMichael Jones   ASSERT_EQ(READ_SIZE, f->read(read_data, READ_SIZE).value);
2684ef02da0SSiva Chandra Reddy   MemoryView src3(initial_content, READ_SIZE), dst3(read_data, READ_SIZE);
2694ef02da0SSiva Chandra Reddy   EXPECT_MEM_EQ(src3, dst3);
2704ef02da0SSiva Chandra Reddy 
2719beb8d11SMichael Jones   {
2724ef02da0SSiva Chandra Reddy     // This is not a writable file.
2739beb8d11SMichael Jones     auto result = f->write(initial_content, sizeof(initial_content));
2749beb8d11SMichael Jones     EXPECT_EQ(result.value, size_t(0));
2754ef02da0SSiva Chandra Reddy     EXPECT_TRUE(f->error());
2769beb8d11SMichael Jones     EXPECT_TRUE(result.has_error());
2779beb8d11SMichael Jones   }
2784ef02da0SSiva Chandra Reddy 
27975d70b73SSiva Chandra Reddy   ASSERT_EQ(f->close(), 0);
2804ef02da0SSiva Chandra Reddy }
2814ef02da0SSiva Chandra Reddy 
282a0f6d12cSSiva Chandra Reddy TEST(LlvmLibcFileTest, ReadSeekCurAndRead) {
283a0f6d12cSSiva Chandra Reddy   const char initial_content[] = "1234567890987654321";
284a0f6d12cSSiva Chandra Reddy   constexpr size_t FILE_BUFFER_SIZE = sizeof(initial_content);
285a0f6d12cSSiva Chandra Reddy   char file_buffer[FILE_BUFFER_SIZE];
2866ce490e5SMichael Jones   StringFile *f =
2876ce490e5SMichael Jones       new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "r");
288a0f6d12cSSiva Chandra Reddy   f->reset_and_fill(initial_content, sizeof(initial_content));
289a0f6d12cSSiva Chandra Reddy 
290a0f6d12cSSiva Chandra Reddy   constexpr size_t READ_SIZE = 5;
291a0f6d12cSSiva Chandra Reddy   char data[READ_SIZE];
292a0f6d12cSSiva Chandra Reddy   data[READ_SIZE - 1] = '\0';
2939beb8d11SMichael Jones   ASSERT_EQ(f->read(data, READ_SIZE - 1).value, READ_SIZE - 1);
294a0f6d12cSSiva Chandra Reddy   ASSERT_STREQ(data, "1234");
2959beb8d11SMichael Jones   ASSERT_EQ(f->seek(5, SEEK_CUR).value(), 0);
2969beb8d11SMichael Jones   ASSERT_EQ(f->read(data, READ_SIZE - 1).value, READ_SIZE - 1);
297a0f6d12cSSiva Chandra Reddy   ASSERT_STREQ(data, "0987");
2989beb8d11SMichael Jones   ASSERT_EQ(f->seek(-5, SEEK_CUR).value(), 0);
2999beb8d11SMichael Jones   ASSERT_EQ(f->read(data, READ_SIZE - 1).value, READ_SIZE - 1);
300a0f6d12cSSiva Chandra Reddy   ASSERT_STREQ(data, "9098");
30175d70b73SSiva Chandra Reddy   ASSERT_EQ(f->close(), 0);
302a0f6d12cSSiva Chandra Reddy }
303a0f6d12cSSiva Chandra Reddy 
3044ef02da0SSiva Chandra Reddy TEST(LlvmLibcFileTest, AppendOnly) {
3054ef02da0SSiva Chandra Reddy   const char initial_content[] = "1234567890987654321";
3064ef02da0SSiva Chandra Reddy   const char write_data[] = "append";
3074ef02da0SSiva Chandra Reddy   constexpr size_t FILE_BUFFER_SIZE = sizeof(write_data) * 3 / 2;
3084ef02da0SSiva Chandra Reddy   char file_buffer[FILE_BUFFER_SIZE];
3096ce490e5SMichael Jones   StringFile *f =
3106ce490e5SMichael Jones       new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "a");
3114ef02da0SSiva Chandra Reddy   f->reset_and_fill(initial_content, sizeof(initial_content));
3124ef02da0SSiva Chandra Reddy 
3134ef02da0SSiva Chandra Reddy   constexpr size_t READ_SIZE = 5;
3144ef02da0SSiva Chandra Reddy   char read_data[READ_SIZE];
3159beb8d11SMichael Jones 
3169beb8d11SMichael Jones   {
3174ef02da0SSiva Chandra Reddy     // This is not a readable file.
3189beb8d11SMichael Jones     auto result = f->read(read_data, READ_SIZE);
3199beb8d11SMichael Jones     EXPECT_EQ(result.value, size_t(0));
3204ef02da0SSiva Chandra Reddy     EXPECT_TRUE(f->error());
3219beb8d11SMichael Jones     EXPECT_TRUE(result.has_error());
3229beb8d11SMichael Jones   }
3234ef02da0SSiva Chandra Reddy 
3244ef02da0SSiva Chandra Reddy   // Write should succeed but will be buffered in the file stream.
3259beb8d11SMichael Jones   ASSERT_EQ(f->write(write_data, sizeof(write_data)).value, sizeof(write_data));
3264ef02da0SSiva Chandra Reddy   EXPECT_EQ(f->get_pos(), size_t(0));
3274ef02da0SSiva Chandra Reddy   // Flushing will write to the file.
3284ef02da0SSiva Chandra Reddy   EXPECT_EQ(f->flush(), int(0));
3294ef02da0SSiva Chandra Reddy   EXPECT_EQ(f->get_pos(), sizeof(write_data) + sizeof(initial_content));
3304ef02da0SSiva Chandra Reddy 
33175d70b73SSiva Chandra Reddy   ASSERT_EQ(f->close(), 0);
3324ef02da0SSiva Chandra Reddy }
3334ef02da0SSiva Chandra Reddy 
3344ef02da0SSiva Chandra Reddy TEST(LlvmLibcFileTest, WriteUpdate) {
3354ef02da0SSiva Chandra Reddy   const char data[] = "hello, file";
3364ef02da0SSiva Chandra Reddy   constexpr size_t FILE_BUFFER_SIZE = sizeof(data) * 3 / 2;
3374ef02da0SSiva Chandra Reddy   char file_buffer[FILE_BUFFER_SIZE];
3384ef02da0SSiva Chandra Reddy   StringFile *f =
3396ce490e5SMichael Jones       new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "w+");
3404ef02da0SSiva Chandra Reddy 
3419beb8d11SMichael Jones   ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)).value);
3424ef02da0SSiva Chandra Reddy   EXPECT_EQ(f->get_pos(), size_t(0)); // Data is buffered in the file stream
3434ef02da0SSiva Chandra Reddy 
3449beb8d11SMichael Jones   ASSERT_EQ(f->seek(0, SEEK_SET).value(), 0);
3454ef02da0SSiva Chandra Reddy 
3464ef02da0SSiva Chandra Reddy   // Seek flushes the stream buffer so we can read the previously written data.
3474ef02da0SSiva Chandra Reddy   char read_data[sizeof(data)];
3489beb8d11SMichael Jones   ASSERT_EQ(f->read(read_data, sizeof(data)).value, sizeof(data));
3494ef02da0SSiva Chandra Reddy   EXPECT_STREQ(read_data, data);
3504ef02da0SSiva Chandra Reddy 
35175d70b73SSiva Chandra Reddy   ASSERT_EQ(f->close(), 0);
3524ef02da0SSiva Chandra Reddy }
3534ef02da0SSiva Chandra Reddy 
3544ef02da0SSiva Chandra Reddy TEST(LlvmLibcFileTest, ReadUpdate) {
3554ef02da0SSiva Chandra Reddy   const char initial_content[] = "1234567890987654321";
3564ef02da0SSiva Chandra Reddy   constexpr size_t FILE_BUFFER_SIZE = sizeof(initial_content);
3574ef02da0SSiva Chandra Reddy   char file_buffer[FILE_BUFFER_SIZE];
3584ef02da0SSiva Chandra Reddy   StringFile *f =
3596ce490e5SMichael Jones       new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "r+");
3604ef02da0SSiva Chandra Reddy   f->reset_and_fill(initial_content, sizeof(initial_content));
3614ef02da0SSiva Chandra Reddy 
3624ef02da0SSiva Chandra Reddy   constexpr size_t READ_SIZE = sizeof(initial_content) / 2;
3634ef02da0SSiva Chandra Reddy   char read_data[READ_SIZE];
3649beb8d11SMichael Jones   ASSERT_EQ(READ_SIZE, f->read(read_data, READ_SIZE).value);
3654ef02da0SSiva Chandra Reddy   EXPECT_FALSE(f->iseof());
3664ef02da0SSiva Chandra Reddy   // Reading less than file buffer worth will still read one
3674ef02da0SSiva Chandra Reddy   // full buffer worth of data.
3684ef02da0SSiva Chandra Reddy   EXPECT_STREQ(file_buffer, initial_content);
3694ef02da0SSiva Chandra Reddy   EXPECT_STREQ(file_buffer, f->get_str());
3704ef02da0SSiva Chandra Reddy   EXPECT_EQ(FILE_BUFFER_SIZE, f->get_pos());
3714ef02da0SSiva Chandra Reddy   // The read data should match what was supposed to be read anyway.
3724ef02da0SSiva Chandra Reddy   MemoryView src1(initial_content, READ_SIZE), dst1(read_data, READ_SIZE);
3734ef02da0SSiva Chandra Reddy   EXPECT_MEM_EQ(src1, dst1);
3744ef02da0SSiva Chandra Reddy 
3759beb8d11SMichael Jones   ASSERT_EQ(f->seek(0, SEEK_SET).value(), 0);
3764ef02da0SSiva Chandra Reddy   const char write_data[] = "hello, file";
3779beb8d11SMichael Jones   ASSERT_EQ(sizeof(write_data), f->write(write_data, sizeof(write_data)).value);
3784ef02da0SSiva Chandra Reddy   EXPECT_STREQ(file_buffer, write_data);
3794ef02da0SSiva Chandra Reddy   ASSERT_EQ(f->flush(), 0);
3804ef02da0SSiva Chandra Reddy   MemoryView dst2(f->get_str(), sizeof(write_data)),
3814ef02da0SSiva Chandra Reddy       src2(write_data, sizeof(write_data));
3824ef02da0SSiva Chandra Reddy   EXPECT_MEM_EQ(src2, dst2);
3834ef02da0SSiva Chandra Reddy 
38475d70b73SSiva Chandra Reddy   ASSERT_EQ(f->close(), 0);
3854ef02da0SSiva Chandra Reddy }
3864ef02da0SSiva Chandra Reddy 
3874ef02da0SSiva Chandra Reddy TEST(LlvmLibcFileTest, AppendUpdate) {
3884ef02da0SSiva Chandra Reddy   const char initial_content[] = "1234567890987654321";
3894ef02da0SSiva Chandra Reddy   const char data[] = "hello, file";
3904ef02da0SSiva Chandra Reddy   constexpr size_t FILE_BUFFER_SIZE = sizeof(data) * 3 / 2;
3914ef02da0SSiva Chandra Reddy   char file_buffer[FILE_BUFFER_SIZE];
3924ef02da0SSiva Chandra Reddy   StringFile *f =
3936ce490e5SMichael Jones       new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "a+");
3944ef02da0SSiva Chandra Reddy   f->reset_and_fill(initial_content, sizeof(initial_content));
3954ef02da0SSiva Chandra Reddy 
3969beb8d11SMichael Jones   ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)).value);
3974ef02da0SSiva Chandra Reddy   EXPECT_EQ(f->get_pos(), size_t(0)); // Data is buffered in the file stream
3984ef02da0SSiva Chandra Reddy   ASSERT_EQ(f->flush(), 0);
3994ef02da0SSiva Chandra Reddy   // The flush should write |data| to the endof the file.
4004ef02da0SSiva Chandra Reddy   EXPECT_EQ(f->get_pos(), sizeof(data) + sizeof(initial_content));
4014ef02da0SSiva Chandra Reddy 
4029beb8d11SMichael Jones   ASSERT_EQ(f->seek(0, SEEK_SET).value(), 0);
4034ef02da0SSiva Chandra Reddy   // Seeking to the beginning of the file should not affect the place
4044ef02da0SSiva Chandra Reddy   // where write happens.
4059beb8d11SMichael Jones   ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)).value);
4064ef02da0SSiva Chandra Reddy   ASSERT_EQ(f->flush(), 0);
4074ef02da0SSiva Chandra Reddy   EXPECT_EQ(f->get_pos(), sizeof(data) * 2 + sizeof(initial_content));
4084ef02da0SSiva Chandra Reddy   MemoryView src1(initial_content, sizeof(initial_content)),
4094ef02da0SSiva Chandra Reddy       dst1(f->get_str(), sizeof(initial_content));
4104ef02da0SSiva Chandra Reddy   EXPECT_MEM_EQ(src1, dst1);
4114ef02da0SSiva Chandra Reddy   MemoryView src2(data, sizeof(data)),
4124ef02da0SSiva Chandra Reddy       dst2(f->get_str() + sizeof(initial_content), sizeof(data));
4134ef02da0SSiva Chandra Reddy   EXPECT_MEM_EQ(src2, dst2);
4144ef02da0SSiva Chandra Reddy   MemoryView src3(data, sizeof(data)),
4154ef02da0SSiva Chandra Reddy       dst3(f->get_str() + sizeof(initial_content) + sizeof(data), sizeof(data));
4164ef02da0SSiva Chandra Reddy   EXPECT_MEM_EQ(src3, dst3);
4174ef02da0SSiva Chandra Reddy 
4184ef02da0SSiva Chandra Reddy   // Reads can happen from any point.
4199beb8d11SMichael Jones   ASSERT_EQ(f->seek(0, SEEK_SET).value(), 0);
4204ef02da0SSiva Chandra Reddy   constexpr size_t READ_SIZE = 10;
4214ef02da0SSiva Chandra Reddy   char read_data[READ_SIZE];
4229beb8d11SMichael Jones   ASSERT_EQ(READ_SIZE, f->read(read_data, READ_SIZE).value);
4234ef02da0SSiva Chandra Reddy   MemoryView src4(initial_content, READ_SIZE), dst4(read_data, READ_SIZE);
4244ef02da0SSiva Chandra Reddy   EXPECT_MEM_EQ(src4, dst4);
4254ef02da0SSiva Chandra Reddy 
42675d70b73SSiva Chandra Reddy   ASSERT_EQ(f->close(), 0);
4274ef02da0SSiva Chandra Reddy }
4286ce490e5SMichael Jones 
4296ce490e5SMichael Jones TEST(LlvmLibcFileTest, SmallBuffer) {
4306ce490e5SMichael Jones   const char WRITE_DATA[] = "small buffer";
4316ce490e5SMichael Jones   constexpr size_t WRITE_SIZE = sizeof(WRITE_DATA);
4326ce490e5SMichael Jones   constexpr size_t FILE_BUFFER_SIZE = sizeof(WRITE_DATA) / 2 - 1;
4336ce490e5SMichael Jones   char file_buffer[FILE_BUFFER_SIZE];
4346ce490e5SMichael Jones   StringFile *f =
4356ce490e5SMichael Jones       new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "w");
4366ce490e5SMichael Jones 
4379beb8d11SMichael Jones   ASSERT_EQ(WRITE_SIZE, f->write(WRITE_DATA, WRITE_SIZE).value);
4386ce490e5SMichael Jones   // Since data much larger than the buffer is being written, all of it should
4396ce490e5SMichael Jones   // be available in the file without a flush operation.
4406ce490e5SMichael Jones   EXPECT_EQ(f->get_pos(), sizeof(WRITE_DATA));
4416ce490e5SMichael Jones   ASSERT_STREQ(f->get_str(), WRITE_DATA);
4426ce490e5SMichael Jones 
44375d70b73SSiva Chandra Reddy   ASSERT_EQ(f->close(), 0);
4446ce490e5SMichael Jones }
4456ce490e5SMichael Jones 
4466ce490e5SMichael Jones TEST(LlvmLibcFileTest, ZeroLengthBuffer) {
4476ce490e5SMichael Jones   const char WRITE_DATA[] = "small buffer";
4486ce490e5SMichael Jones   constexpr size_t WRITE_SIZE = sizeof(WRITE_DATA);
4496ce490e5SMichael Jones   StringFile *f_fbf = new_string_file(nullptr, 0, _IOFBF, true, "w");
4506ce490e5SMichael Jones   StringFile *f_lbf = new_string_file(nullptr, 0, _IOLBF, true, "w");
4516ce490e5SMichael Jones   StringFile *f_nbf = new_string_file(nullptr, 0, _IONBF, true, "w");
4526ce490e5SMichael Jones 
4539beb8d11SMichael Jones   ASSERT_EQ(WRITE_SIZE, f_fbf->write(WRITE_DATA, WRITE_SIZE).value);
4549beb8d11SMichael Jones   ASSERT_EQ(WRITE_SIZE, f_lbf->write(WRITE_DATA, WRITE_SIZE).value);
4559beb8d11SMichael Jones   ASSERT_EQ(WRITE_SIZE, f_nbf->write(WRITE_DATA, WRITE_SIZE).value);
4566ce490e5SMichael Jones   // Since there is no buffer space, all of the written data should
4576ce490e5SMichael Jones   // be available in the file without a flush operation.
4586ce490e5SMichael Jones   EXPECT_EQ(f_fbf->get_pos(), sizeof(WRITE_DATA));
4596ce490e5SMichael Jones   EXPECT_EQ(f_lbf->get_pos(), sizeof(WRITE_DATA));
4606ce490e5SMichael Jones   EXPECT_EQ(f_nbf->get_pos(), sizeof(WRITE_DATA));
4616ce490e5SMichael Jones   ASSERT_STREQ(f_fbf->get_str(), WRITE_DATA);
4626ce490e5SMichael Jones   ASSERT_STREQ(f_lbf->get_str(), WRITE_DATA);
4636ce490e5SMichael Jones   ASSERT_STREQ(f_nbf->get_str(), WRITE_DATA);
4646ce490e5SMichael Jones 
46575d70b73SSiva Chandra Reddy   ASSERT_EQ(f_fbf->close(), 0);
46675d70b73SSiva Chandra Reddy   ASSERT_EQ(f_lbf->close(), 0);
46775d70b73SSiva Chandra Reddy   ASSERT_EQ(f_nbf->close(), 0);
4686ce490e5SMichael Jones }
4695bcda1d3SMichael Jones 
4705bcda1d3SMichael Jones TEST(LlvmLibcFileTest, WriteNothing) {
4715bcda1d3SMichael Jones   const char WRITE_DATA[] = "";
4725bcda1d3SMichael Jones   constexpr size_t WRITE_SIZE = 0;
4735bcda1d3SMichael Jones   constexpr size_t FILE_BUFFER_SIZE = 5;
4745bcda1d3SMichael Jones   char file_buffer_fbf[FILE_BUFFER_SIZE];
4755bcda1d3SMichael Jones   char file_buffer_lbf[FILE_BUFFER_SIZE];
4765bcda1d3SMichael Jones   char file_buffer_nbf[FILE_BUFFER_SIZE];
4775bcda1d3SMichael Jones   StringFile *f_fbf =
4785bcda1d3SMichael Jones       new_string_file(file_buffer_fbf, FILE_BUFFER_SIZE, _IOFBF, false, "w");
4795bcda1d3SMichael Jones   StringFile *f_lbf =
4805bcda1d3SMichael Jones       new_string_file(file_buffer_lbf, FILE_BUFFER_SIZE, _IOLBF, false, "w");
4815bcda1d3SMichael Jones   StringFile *f_nbf =
4825bcda1d3SMichael Jones       new_string_file(file_buffer_nbf, FILE_BUFFER_SIZE, _IONBF, false, "w");
4835bcda1d3SMichael Jones 
4849beb8d11SMichael Jones   ASSERT_EQ(WRITE_SIZE, f_fbf->write(WRITE_DATA, WRITE_SIZE).value);
4859beb8d11SMichael Jones   ASSERT_EQ(WRITE_SIZE, f_lbf->write(WRITE_DATA, WRITE_SIZE).value);
4869beb8d11SMichael Jones   ASSERT_EQ(WRITE_SIZE, f_nbf->write(WRITE_DATA, WRITE_SIZE).value);
4875bcda1d3SMichael Jones 
4885bcda1d3SMichael Jones   ASSERT_FALSE(f_fbf->error_unlocked());
4895bcda1d3SMichael Jones   ASSERT_FALSE(f_lbf->error_unlocked());
4905bcda1d3SMichael Jones   ASSERT_FALSE(f_nbf->error_unlocked());
4915bcda1d3SMichael Jones 
49275d70b73SSiva Chandra Reddy   ASSERT_EQ(f_fbf->close(), 0);
49375d70b73SSiva Chandra Reddy   ASSERT_EQ(f_lbf->close(), 0);
49475d70b73SSiva Chandra Reddy   ASSERT_EQ(f_nbf->close(), 0);
4955bcda1d3SMichael Jones }
496