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