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
94ef02da0SSiva Chandra Reddy #include "src/__support/File/file.h"
104ef02da0SSiva Chandra Reddy #include "utils/UnitTest/MemoryMatcher.h"
114ef02da0SSiva Chandra Reddy #include "utils/UnitTest/Test.h"
124ef02da0SSiva Chandra Reddy
134ef02da0SSiva Chandra Reddy #include <errno.h>
144ef02da0SSiva Chandra Reddy #include <stdio.h>
154ef02da0SSiva Chandra Reddy #include <stdlib.h>
164ef02da0SSiva Chandra Reddy
174ef02da0SSiva Chandra Reddy using ModeFlags = __llvm_libc::File::ModeFlags;
184ef02da0SSiva Chandra Reddy using MemoryView = __llvm_libc::memory::testing::MemoryView;
194ef02da0SSiva Chandra Reddy
204ef02da0SSiva Chandra Reddy class StringFile : public __llvm_libc::File {
214ef02da0SSiva Chandra Reddy static constexpr size_t SIZE = 512;
224ef02da0SSiva Chandra Reddy size_t pos;
234ef02da0SSiva Chandra Reddy char str[SIZE] = {0};
244ef02da0SSiva Chandra Reddy size_t eof_marker;
254ef02da0SSiva Chandra Reddy bool write_append;
264ef02da0SSiva Chandra Reddy
274ef02da0SSiva Chandra Reddy static size_t str_read(__llvm_libc::File *f, void *data, size_t len);
284ef02da0SSiva Chandra Reddy static size_t str_write(__llvm_libc::File *f, const void *data, size_t len);
294ef02da0SSiva Chandra Reddy static int str_seek(__llvm_libc::File *f, long offset, int whence);
str_close(__llvm_libc::File * f)304ef02da0SSiva Chandra Reddy static int str_close(__llvm_libc::File *f) { return 0; }
str_flush(__llvm_libc::File * f)314ef02da0SSiva Chandra Reddy static int str_flush(__llvm_libc::File *f) { return 0; }
324ef02da0SSiva Chandra Reddy
334ef02da0SSiva Chandra Reddy public:
StringFile(char * buffer,size_t buflen,int bufmode,bool owned,ModeFlags modeflags)344ef02da0SSiva Chandra Reddy explicit StringFile(char *buffer, size_t buflen, int bufmode, bool owned,
354ef02da0SSiva Chandra Reddy ModeFlags modeflags)
364ef02da0SSiva Chandra Reddy : __llvm_libc::File(&str_write, &str_read, &str_seek, &str_close,
379527a2f5SSiva Chandra Reddy &str_flush, buffer, buflen, bufmode, owned,
389527a2f5SSiva Chandra Reddy modeflags),
394ef02da0SSiva Chandra Reddy pos(0), eof_marker(0), write_append(false) {
404ef02da0SSiva Chandra Reddy if (modeflags & static_cast<ModeFlags>(__llvm_libc::File::OpenMode::APPEND))
414ef02da0SSiva Chandra Reddy write_append = true;
424ef02da0SSiva Chandra Reddy }
434ef02da0SSiva Chandra Reddy
init(char * buffer,size_t buflen,int bufmode,bool owned,ModeFlags modeflags)444ef02da0SSiva Chandra Reddy void init(char *buffer, size_t buflen, int bufmode, bool owned,
454ef02da0SSiva Chandra Reddy ModeFlags modeflags) {
464ef02da0SSiva Chandra Reddy File::init(this, &str_write, &str_read, &str_seek, &str_close, &str_flush,
479527a2f5SSiva Chandra Reddy buffer, buflen, bufmode, owned, modeflags);
484ef02da0SSiva Chandra Reddy pos = eof_marker = 0;
494ef02da0SSiva Chandra Reddy if (modeflags & static_cast<ModeFlags>(__llvm_libc::File::OpenMode::APPEND))
504ef02da0SSiva Chandra Reddy write_append = true;
514ef02da0SSiva Chandra Reddy else
524ef02da0SSiva Chandra Reddy write_append = false;
534ef02da0SSiva Chandra Reddy }
544ef02da0SSiva Chandra Reddy
reset()554ef02da0SSiva Chandra Reddy void reset() { pos = 0; }
get_pos() const564ef02da0SSiva Chandra Reddy size_t get_pos() const { return pos; }
get_str()574ef02da0SSiva Chandra Reddy char *get_str() { return str; }
584ef02da0SSiva Chandra Reddy
594ef02da0SSiva Chandra Reddy // Use this method to prefill the file.
reset_and_fill(const char * data,size_t len)604ef02da0SSiva Chandra Reddy void reset_and_fill(const char *data, size_t len) {
614ef02da0SSiva Chandra Reddy size_t i;
624ef02da0SSiva Chandra Reddy for (i = 0; i < len && i < SIZE; ++i) {
634ef02da0SSiva Chandra Reddy str[i] = data[i];
644ef02da0SSiva Chandra Reddy }
654ef02da0SSiva Chandra Reddy pos = 0;
664ef02da0SSiva Chandra Reddy eof_marker = i;
674ef02da0SSiva Chandra Reddy }
684ef02da0SSiva Chandra Reddy };
694ef02da0SSiva Chandra Reddy
str_read(__llvm_libc::File * f,void * data,size_t len)704ef02da0SSiva Chandra Reddy size_t StringFile::str_read(__llvm_libc::File *f, void *data, size_t len) {
714ef02da0SSiva Chandra Reddy StringFile *sf = static_cast<StringFile *>(f);
724ef02da0SSiva Chandra Reddy if (sf->pos >= sf->eof_marker)
734ef02da0SSiva Chandra Reddy return 0;
744ef02da0SSiva Chandra Reddy size_t i = 0;
754ef02da0SSiva Chandra Reddy for (i = 0; i < len; ++i)
764ef02da0SSiva Chandra Reddy reinterpret_cast<char *>(data)[i] = sf->str[sf->pos + i];
774ef02da0SSiva Chandra Reddy sf->pos += i;
784ef02da0SSiva Chandra Reddy return i;
794ef02da0SSiva Chandra Reddy }
804ef02da0SSiva Chandra Reddy
str_write(__llvm_libc::File * f,const void * data,size_t len)814ef02da0SSiva Chandra Reddy size_t StringFile::str_write(__llvm_libc::File *f, const void *data,
824ef02da0SSiva Chandra Reddy size_t len) {
834ef02da0SSiva Chandra Reddy StringFile *sf = static_cast<StringFile *>(f);
844ef02da0SSiva Chandra Reddy if (sf->write_append)
854ef02da0SSiva Chandra Reddy sf->pos = sf->eof_marker;
864ef02da0SSiva Chandra Reddy if (sf->pos >= SIZE)
874ef02da0SSiva Chandra Reddy return 0;
884ef02da0SSiva Chandra Reddy size_t i = 0;
894ef02da0SSiva Chandra Reddy for (i = 0; i < len && sf->pos < SIZE; ++i, ++sf->pos)
904ef02da0SSiva Chandra Reddy sf->str[sf->pos] = reinterpret_cast<const char *>(data)[i];
914ef02da0SSiva Chandra Reddy // Move the eof marker if the data was written beyond the current eof marker.
924ef02da0SSiva Chandra Reddy if (sf->pos > sf->eof_marker)
934ef02da0SSiva Chandra Reddy sf->eof_marker = sf->pos;
944ef02da0SSiva Chandra Reddy return i;
954ef02da0SSiva Chandra Reddy }
964ef02da0SSiva Chandra Reddy
str_seek(__llvm_libc::File * f,long offset,int whence)974ef02da0SSiva Chandra Reddy int StringFile::str_seek(__llvm_libc::File *f, long offset, int whence) {
984ef02da0SSiva Chandra Reddy StringFile *sf = static_cast<StringFile *>(f);
994ef02da0SSiva Chandra Reddy if (whence == SEEK_SET)
1004ef02da0SSiva Chandra Reddy sf->pos = offset;
1014ef02da0SSiva Chandra Reddy if (whence == SEEK_CUR)
1024ef02da0SSiva Chandra Reddy sf->pos += offset;
1034ef02da0SSiva Chandra Reddy if (whence == SEEK_END)
1044ef02da0SSiva Chandra Reddy sf->pos = SIZE + offset;
1054ef02da0SSiva Chandra Reddy return 0;
1064ef02da0SSiva Chandra Reddy }
1074ef02da0SSiva Chandra Reddy
new_string_file(char * buffer,size_t buflen,int bufmode,bool owned,const char * mode)1084ef02da0SSiva Chandra Reddy StringFile *new_string_file(char *buffer, size_t buflen, int bufmode,
1094ef02da0SSiva Chandra Reddy bool owned, const char *mode) {
1104ef02da0SSiva Chandra Reddy StringFile *f = reinterpret_cast<StringFile *>(malloc(sizeof(StringFile)));
1114ef02da0SSiva Chandra Reddy f->init(buffer, buflen, bufmode, owned, __llvm_libc::File::mode_flags(mode));
1124ef02da0SSiva Chandra Reddy return f;
1134ef02da0SSiva Chandra Reddy }
1144ef02da0SSiva Chandra Reddy
TEST(LlvmLibcFileTest,WriteOnly)1154ef02da0SSiva Chandra Reddy TEST(LlvmLibcFileTest, WriteOnly) {
1164ef02da0SSiva Chandra Reddy const char data[] = "hello, file";
1174ef02da0SSiva Chandra Reddy constexpr size_t FILE_BUFFER_SIZE = sizeof(data) * 3 / 2;
1184ef02da0SSiva Chandra Reddy char file_buffer[FILE_BUFFER_SIZE];
1196ce490e5SMichael Jones StringFile *f =
1206ce490e5SMichael Jones new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "w");
1214ef02da0SSiva Chandra Reddy
1224ef02da0SSiva Chandra Reddy ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)));
1234ef02da0SSiva Chandra Reddy EXPECT_EQ(f->get_pos(), size_t(0)); // Data is buffered in the file stream
1244ef02da0SSiva Chandra Reddy ASSERT_EQ(f->flush(), 0);
1254ef02da0SSiva Chandra Reddy EXPECT_EQ(f->get_pos(), sizeof(data)); // Data should now be available
1264ef02da0SSiva Chandra Reddy EXPECT_STREQ(f->get_str(), data);
1274ef02da0SSiva Chandra Reddy
1284ef02da0SSiva Chandra Reddy f->reset();
1294ef02da0SSiva Chandra Reddy ASSERT_EQ(f->get_pos(), size_t(0));
1304ef02da0SSiva Chandra Reddy ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)));
1314ef02da0SSiva Chandra Reddy EXPECT_EQ(f->get_pos(), size_t(0)); // Data is buffered in the file stream
1324ef02da0SSiva Chandra Reddy // The second write should trigger a buffer flush.
1334ef02da0SSiva Chandra Reddy ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)));
1344ef02da0SSiva Chandra Reddy EXPECT_GE(f->get_pos(), size_t(0));
1354ef02da0SSiva Chandra Reddy ASSERT_EQ(f->flush(), 0);
1364ef02da0SSiva Chandra Reddy EXPECT_EQ(f->get_pos(), 2 * sizeof(data));
1376ce490e5SMichael Jones MemoryView src1("hello, file\0hello, file", sizeof(data) * 2),
1386ce490e5SMichael Jones dst1(f->get_str(), sizeof(data) * 2);
1396ce490e5SMichael Jones EXPECT_MEM_EQ(src1, dst1);
1404ef02da0SSiva Chandra Reddy
1414ef02da0SSiva Chandra Reddy char read_data[sizeof(data)];
1424ef02da0SSiva Chandra Reddy // This is not a readable file.
1434ef02da0SSiva Chandra Reddy EXPECT_EQ(f->read(read_data, sizeof(data)), size_t(0));
1444ef02da0SSiva Chandra Reddy EXPECT_TRUE(f->error());
1454ef02da0SSiva Chandra Reddy EXPECT_NE(errno, 0);
1464ef02da0SSiva Chandra Reddy errno = 0;
1474ef02da0SSiva Chandra Reddy
1484ef02da0SSiva Chandra Reddy ASSERT_EQ(f->close(), 0);
1494ef02da0SSiva Chandra Reddy }
1504ef02da0SSiva Chandra Reddy
TEST(LlvmLibcFileTest,WriteLineBuffered)1516ce490e5SMichael Jones TEST(LlvmLibcFileTest, WriteLineBuffered) {
1526ce490e5SMichael Jones const char data[] = "hello\n file";
1536ce490e5SMichael Jones constexpr size_t FILE_BUFFER_SIZE = sizeof(data) * 3 / 2;
1546ce490e5SMichael Jones
1556ce490e5SMichael Jones char file_buffer_line[FILE_BUFFER_SIZE];
1566ce490e5SMichael Jones char file_buffer_full[FILE_BUFFER_SIZE];
1576ce490e5SMichael Jones
1586ce490e5SMichael Jones StringFile *f_line =
1596ce490e5SMichael Jones new_string_file(file_buffer_line, FILE_BUFFER_SIZE, _IOLBF, false, "w");
1606ce490e5SMichael Jones // We also initialize a fully buffered file we'll do the same writes to for
1616ce490e5SMichael Jones // comparison.
1626ce490e5SMichael Jones StringFile *f_full =
1636ce490e5SMichael Jones new_string_file(file_buffer_full, FILE_BUFFER_SIZE, _IOFBF, false, "w");
1646ce490e5SMichael Jones
1656ce490e5SMichael Jones ASSERT_EQ(sizeof(data), f_line->write(data, sizeof(data)));
1666ce490e5SMichael Jones ASSERT_EQ(sizeof(data), f_full->write(data, sizeof(data)));
1676ce490e5SMichael Jones
1686ce490e5SMichael Jones EXPECT_EQ(f_line->get_pos(), size_t(6)); // buffer after the newline
1696ce490e5SMichael Jones EXPECT_EQ(f_full->get_pos(), size_t(0)); // buffer all of data
1706ce490e5SMichael Jones
1716ce490e5SMichael Jones MemoryView src1("hello\n", 6), dst1(f_line->get_str(), 6);
1726ce490e5SMichael Jones EXPECT_MEM_EQ(src1, dst1);
1736ce490e5SMichael Jones
1746ce490e5SMichael Jones // We can't check the data in f_full, since no data has been written.
1756ce490e5SMichael Jones
1766ce490e5SMichael Jones const char data2[] = "longer for an \n overflow";
1776ce490e5SMichael Jones
1786ce490e5SMichael Jones ASSERT_EQ(sizeof(data2), f_line->write(data2, sizeof(data2)));
1796ce490e5SMichael Jones // The line buffer's initial contents should be " file\0"
1806ce490e5SMichael Jones // Writing data2 should write up until the newline, even though that doesn't
1816ce490e5SMichael Jones // all fit in the buffer.
1826ce490e5SMichael Jones
1836ce490e5SMichael Jones ASSERT_EQ(sizeof(data2), f_full->write(data2, sizeof(data2)));
1846ce490e5SMichael Jones // The full buffer's initial contents should be "hello\n file\0"
1856ce490e5SMichael Jones // Writing data2 should cause a flush of the buffer, as well as the remainder
1866ce490e5SMichael Jones // to be written directly since it doesn't fit in the buffer.
1876ce490e5SMichael Jones
1886ce490e5SMichael Jones EXPECT_EQ(f_line->get_pos(), size_t(27));
1896ce490e5SMichael Jones EXPECT_EQ(f_full->get_pos(), sizeof(data) + sizeof(data2));
1906ce490e5SMichael Jones
1916ce490e5SMichael Jones MemoryView src2("hello\n file\0longer for an \n", 27),
1926ce490e5SMichael Jones dst2(f_line->get_str(), 27);
1936ce490e5SMichael Jones EXPECT_MEM_EQ(src2, dst2);
1946ce490e5SMichael Jones
1956ce490e5SMichael Jones MemoryView src3("hello\n file\0longer for an \n overflow", 37),
1966ce490e5SMichael Jones dst_full_final(f_full->get_str(), 37);
1976ce490e5SMichael Jones EXPECT_MEM_EQ(src3, dst_full_final);
1986ce490e5SMichael Jones
1996ce490e5SMichael Jones ASSERT_EQ(f_line->flush(), 0);
2006ce490e5SMichael Jones ASSERT_EQ(f_full->flush(), 0);
2016ce490e5SMichael Jones
2026ce490e5SMichael Jones EXPECT_EQ(f_line->get_pos(), sizeof(data) + sizeof(data2));
2036ce490e5SMichael Jones MemoryView dst_line_final(f_line->get_str(), 37);
2046ce490e5SMichael Jones EXPECT_MEM_EQ(src3, dst_line_final);
2056ce490e5SMichael Jones EXPECT_MEM_EQ(src3, dst_full_final);
2066ce490e5SMichael Jones
2076ce490e5SMichael Jones ASSERT_EQ(f_line->close(), 0);
2086ce490e5SMichael Jones ASSERT_EQ(f_full->close(), 0);
2096ce490e5SMichael Jones }
2106ce490e5SMichael Jones
TEST(LlvmLibcFileTest,WriteUnbuffered)2116ce490e5SMichael Jones TEST(LlvmLibcFileTest, WriteUnbuffered) {
2126ce490e5SMichael Jones const char data[] = "written immediately";
2136ce490e5SMichael Jones constexpr size_t FILE_BUFFER_SIZE = sizeof(data) + 1;
2146ce490e5SMichael Jones char file_buffer[FILE_BUFFER_SIZE];
2156ce490e5SMichael Jones StringFile *f =
2166ce490e5SMichael Jones new_string_file(file_buffer, FILE_BUFFER_SIZE, _IONBF, false, "w");
2176ce490e5SMichael Jones
2186ce490e5SMichael Jones ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)));
2196ce490e5SMichael Jones EXPECT_EQ(f->get_pos(),
2206ce490e5SMichael Jones sizeof(data)); // no buffering means this is written immediately.
2216ce490e5SMichael Jones EXPECT_STREQ(f->get_str(), data);
2226ce490e5SMichael Jones
2236ce490e5SMichael Jones ASSERT_EQ(f->close(), 0);
2246ce490e5SMichael Jones }
2256ce490e5SMichael Jones
TEST(LlvmLibcFileTest,ReadOnly)2264ef02da0SSiva Chandra Reddy TEST(LlvmLibcFileTest, ReadOnly) {
2274ef02da0SSiva Chandra Reddy const char initial_content[] = "1234567890987654321";
2284ef02da0SSiva Chandra Reddy constexpr size_t FILE_BUFFER_SIZE = sizeof(initial_content);
2294ef02da0SSiva Chandra Reddy char file_buffer[FILE_BUFFER_SIZE];
2306ce490e5SMichael Jones StringFile *f =
2316ce490e5SMichael Jones new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "r");
2324ef02da0SSiva Chandra Reddy f->reset_and_fill(initial_content, sizeof(initial_content));
2334ef02da0SSiva Chandra Reddy
2344ef02da0SSiva Chandra Reddy constexpr size_t READ_SIZE = sizeof(initial_content) / 2;
2354ef02da0SSiva Chandra Reddy char read_data[READ_SIZE];
2364ef02da0SSiva Chandra Reddy ASSERT_EQ(READ_SIZE, f->read(read_data, READ_SIZE));
2374ef02da0SSiva Chandra Reddy EXPECT_FALSE(f->iseof());
2384ef02da0SSiva Chandra Reddy // Reading less than file buffer worth will still read one
2394ef02da0SSiva Chandra Reddy // full buffer worth of data.
2404ef02da0SSiva Chandra Reddy EXPECT_STREQ(file_buffer, initial_content);
2414ef02da0SSiva Chandra Reddy EXPECT_STREQ(file_buffer, f->get_str());
2424ef02da0SSiva Chandra Reddy EXPECT_EQ(FILE_BUFFER_SIZE, f->get_pos());
2434ef02da0SSiva Chandra Reddy // The read data should match what was supposed to be read anyway.
2444ef02da0SSiva Chandra Reddy MemoryView src1(initial_content, READ_SIZE), dst1(read_data, READ_SIZE);
2454ef02da0SSiva Chandra Reddy EXPECT_MEM_EQ(src1, dst1);
2464ef02da0SSiva Chandra Reddy
2474ef02da0SSiva Chandra Reddy // Reading another buffer worth should read out everything in
2484ef02da0SSiva Chandra Reddy // the file.
2494ef02da0SSiva Chandra Reddy ASSERT_EQ(READ_SIZE, f->read(read_data, READ_SIZE));
2504ef02da0SSiva Chandra Reddy EXPECT_FALSE(f->iseof());
2514ef02da0SSiva Chandra Reddy MemoryView src2(initial_content + READ_SIZE, READ_SIZE),
2524ef02da0SSiva Chandra Reddy dst2(read_data, READ_SIZE);
2534ef02da0SSiva Chandra Reddy EXPECT_MEM_EQ(src2, dst2);
2544ef02da0SSiva Chandra Reddy
2554ef02da0SSiva Chandra Reddy // Another read should trigger an EOF.
2564ef02da0SSiva Chandra Reddy ASSERT_GT(READ_SIZE, f->read(read_data, READ_SIZE));
2574ef02da0SSiva Chandra Reddy EXPECT_TRUE(f->iseof());
2584ef02da0SSiva Chandra Reddy
2594ef02da0SSiva Chandra Reddy // Reset the pos to the beginning of the file which should allow
2604ef02da0SSiva Chandra Reddy // reading again.
2614ef02da0SSiva Chandra Reddy for (size_t i = 0; i < READ_SIZE; ++i)
2624ef02da0SSiva Chandra Reddy read_data[i] = 0;
2634ef02da0SSiva Chandra Reddy f->seek(0, SEEK_SET);
2644ef02da0SSiva Chandra Reddy ASSERT_EQ(READ_SIZE, f->read(read_data, READ_SIZE));
2654ef02da0SSiva Chandra Reddy MemoryView src3(initial_content, READ_SIZE), dst3(read_data, READ_SIZE);
2664ef02da0SSiva Chandra Reddy EXPECT_MEM_EQ(src3, dst3);
2674ef02da0SSiva Chandra Reddy
2684ef02da0SSiva Chandra Reddy // This is not a writable file.
2694ef02da0SSiva Chandra Reddy EXPECT_EQ(f->write(initial_content, sizeof(initial_content)), size_t(0));
2704ef02da0SSiva Chandra Reddy EXPECT_TRUE(f->error());
2714ef02da0SSiva Chandra Reddy EXPECT_NE(errno, 0);
2724ef02da0SSiva Chandra Reddy errno = 0;
2734ef02da0SSiva Chandra Reddy
2744ef02da0SSiva Chandra Reddy ASSERT_EQ(f->close(), 0);
2754ef02da0SSiva Chandra Reddy }
2764ef02da0SSiva Chandra Reddy
TEST(LlvmLibcFileTest,ReadSeekCurAndRead)277a0f6d12cSSiva Chandra Reddy TEST(LlvmLibcFileTest, ReadSeekCurAndRead) {
278a0f6d12cSSiva Chandra Reddy const char initial_content[] = "1234567890987654321";
279a0f6d12cSSiva Chandra Reddy constexpr size_t FILE_BUFFER_SIZE = sizeof(initial_content);
280a0f6d12cSSiva Chandra Reddy char file_buffer[FILE_BUFFER_SIZE];
2816ce490e5SMichael Jones StringFile *f =
2826ce490e5SMichael Jones new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "r");
283a0f6d12cSSiva Chandra Reddy f->reset_and_fill(initial_content, sizeof(initial_content));
284a0f6d12cSSiva Chandra Reddy
285a0f6d12cSSiva Chandra Reddy constexpr size_t READ_SIZE = 5;
286a0f6d12cSSiva Chandra Reddy char data[READ_SIZE];
287a0f6d12cSSiva Chandra Reddy data[READ_SIZE - 1] = '\0';
288a0f6d12cSSiva Chandra Reddy ASSERT_EQ(f->read(data, READ_SIZE - 1), READ_SIZE - 1);
289a0f6d12cSSiva Chandra Reddy ASSERT_STREQ(data, "1234");
290a0f6d12cSSiva Chandra Reddy ASSERT_EQ(f->seek(5, SEEK_CUR), 0);
291a0f6d12cSSiva Chandra Reddy ASSERT_EQ(f->read(data, READ_SIZE - 1), READ_SIZE - 1);
292a0f6d12cSSiva Chandra Reddy ASSERT_STREQ(data, "0987");
293a0f6d12cSSiva Chandra Reddy ASSERT_EQ(f->seek(-5, SEEK_CUR), 0);
294a0f6d12cSSiva Chandra Reddy ASSERT_EQ(f->read(data, READ_SIZE - 1), READ_SIZE - 1);
295a0f6d12cSSiva Chandra Reddy ASSERT_STREQ(data, "9098");
296a0f6d12cSSiva Chandra Reddy ASSERT_EQ(f->close(), 0);
297a0f6d12cSSiva Chandra Reddy }
298a0f6d12cSSiva Chandra Reddy
TEST(LlvmLibcFileTest,AppendOnly)2994ef02da0SSiva Chandra Reddy TEST(LlvmLibcFileTest, AppendOnly) {
3004ef02da0SSiva Chandra Reddy const char initial_content[] = "1234567890987654321";
3014ef02da0SSiva Chandra Reddy const char write_data[] = "append";
3024ef02da0SSiva Chandra Reddy constexpr size_t FILE_BUFFER_SIZE = sizeof(write_data) * 3 / 2;
3034ef02da0SSiva Chandra Reddy char file_buffer[FILE_BUFFER_SIZE];
3046ce490e5SMichael Jones StringFile *f =
3056ce490e5SMichael Jones new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "a");
3064ef02da0SSiva Chandra Reddy f->reset_and_fill(initial_content, sizeof(initial_content));
3074ef02da0SSiva Chandra Reddy
3084ef02da0SSiva Chandra Reddy constexpr size_t READ_SIZE = 5;
3094ef02da0SSiva Chandra Reddy char read_data[READ_SIZE];
3104ef02da0SSiva Chandra Reddy // This is not a readable file.
3114ef02da0SSiva Chandra Reddy ASSERT_EQ(f->read(read_data, READ_SIZE), size_t(0));
3124ef02da0SSiva Chandra Reddy EXPECT_TRUE(f->error());
3134ef02da0SSiva Chandra Reddy EXPECT_NE(errno, 0);
3144ef02da0SSiva Chandra Reddy errno = 0;
3154ef02da0SSiva Chandra Reddy
3164ef02da0SSiva Chandra Reddy // Write should succeed but will be buffered in the file stream.
3174ef02da0SSiva Chandra Reddy ASSERT_EQ(f->write(write_data, sizeof(write_data)), sizeof(write_data));
3184ef02da0SSiva Chandra Reddy EXPECT_EQ(f->get_pos(), size_t(0));
3194ef02da0SSiva Chandra Reddy // Flushing will write to the file.
3204ef02da0SSiva Chandra Reddy EXPECT_EQ(f->flush(), int(0));
3214ef02da0SSiva Chandra Reddy EXPECT_EQ(f->get_pos(), sizeof(write_data) + sizeof(initial_content));
3224ef02da0SSiva Chandra Reddy
3234ef02da0SSiva Chandra Reddy ASSERT_EQ(f->close(), 0);
3244ef02da0SSiva Chandra Reddy }
3254ef02da0SSiva Chandra Reddy
TEST(LlvmLibcFileTest,WriteUpdate)3264ef02da0SSiva Chandra Reddy TEST(LlvmLibcFileTest, WriteUpdate) {
3274ef02da0SSiva Chandra Reddy const char data[] = "hello, file";
3284ef02da0SSiva Chandra Reddy constexpr size_t FILE_BUFFER_SIZE = sizeof(data) * 3 / 2;
3294ef02da0SSiva Chandra Reddy char file_buffer[FILE_BUFFER_SIZE];
3304ef02da0SSiva Chandra Reddy StringFile *f =
3316ce490e5SMichael Jones new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "w+");
3324ef02da0SSiva Chandra Reddy
3334ef02da0SSiva Chandra Reddy ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)));
3344ef02da0SSiva Chandra Reddy EXPECT_EQ(f->get_pos(), size_t(0)); // Data is buffered in the file stream
3354ef02da0SSiva Chandra Reddy
3364ef02da0SSiva Chandra Reddy ASSERT_EQ(f->seek(0, SEEK_SET), 0);
3374ef02da0SSiva Chandra Reddy
3384ef02da0SSiva Chandra Reddy // Seek flushes the stream buffer so we can read the previously written data.
3394ef02da0SSiva Chandra Reddy char read_data[sizeof(data)];
3404ef02da0SSiva Chandra Reddy ASSERT_EQ(f->read(read_data, sizeof(data)), sizeof(data));
3414ef02da0SSiva Chandra Reddy EXPECT_STREQ(read_data, data);
3424ef02da0SSiva Chandra Reddy
3434ef02da0SSiva Chandra Reddy ASSERT_EQ(f->close(), 0);
3444ef02da0SSiva Chandra Reddy }
3454ef02da0SSiva Chandra Reddy
TEST(LlvmLibcFileTest,ReadUpdate)3464ef02da0SSiva Chandra Reddy TEST(LlvmLibcFileTest, ReadUpdate) {
3474ef02da0SSiva Chandra Reddy const char initial_content[] = "1234567890987654321";
3484ef02da0SSiva Chandra Reddy constexpr size_t FILE_BUFFER_SIZE = sizeof(initial_content);
3494ef02da0SSiva Chandra Reddy char file_buffer[FILE_BUFFER_SIZE];
3504ef02da0SSiva Chandra Reddy StringFile *f =
3516ce490e5SMichael Jones new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "r+");
3524ef02da0SSiva Chandra Reddy f->reset_and_fill(initial_content, sizeof(initial_content));
3534ef02da0SSiva Chandra Reddy
3544ef02da0SSiva Chandra Reddy constexpr size_t READ_SIZE = sizeof(initial_content) / 2;
3554ef02da0SSiva Chandra Reddy char read_data[READ_SIZE];
3564ef02da0SSiva Chandra Reddy ASSERT_EQ(READ_SIZE, f->read(read_data, READ_SIZE));
3574ef02da0SSiva Chandra Reddy EXPECT_FALSE(f->iseof());
3584ef02da0SSiva Chandra Reddy // Reading less than file buffer worth will still read one
3594ef02da0SSiva Chandra Reddy // full buffer worth of data.
3604ef02da0SSiva Chandra Reddy EXPECT_STREQ(file_buffer, initial_content);
3614ef02da0SSiva Chandra Reddy EXPECT_STREQ(file_buffer, f->get_str());
3624ef02da0SSiva Chandra Reddy EXPECT_EQ(FILE_BUFFER_SIZE, f->get_pos());
3634ef02da0SSiva Chandra Reddy // The read data should match what was supposed to be read anyway.
3644ef02da0SSiva Chandra Reddy MemoryView src1(initial_content, READ_SIZE), dst1(read_data, READ_SIZE);
3654ef02da0SSiva Chandra Reddy EXPECT_MEM_EQ(src1, dst1);
3664ef02da0SSiva Chandra Reddy
3674ef02da0SSiva Chandra Reddy ASSERT_EQ(f->seek(0, SEEK_SET), 0);
3684ef02da0SSiva Chandra Reddy const char write_data[] = "hello, file";
3694ef02da0SSiva Chandra Reddy ASSERT_EQ(sizeof(write_data), f->write(write_data, sizeof(write_data)));
3704ef02da0SSiva Chandra Reddy EXPECT_STREQ(file_buffer, write_data);
3714ef02da0SSiva Chandra Reddy ASSERT_EQ(f->flush(), 0);
3724ef02da0SSiva Chandra Reddy MemoryView dst2(f->get_str(), sizeof(write_data)),
3734ef02da0SSiva Chandra Reddy src2(write_data, sizeof(write_data));
3744ef02da0SSiva Chandra Reddy EXPECT_MEM_EQ(src2, dst2);
3754ef02da0SSiva Chandra Reddy
3764ef02da0SSiva Chandra Reddy ASSERT_EQ(f->close(), 0);
3774ef02da0SSiva Chandra Reddy }
3784ef02da0SSiva Chandra Reddy
TEST(LlvmLibcFileTest,AppendUpdate)3794ef02da0SSiva Chandra Reddy TEST(LlvmLibcFileTest, AppendUpdate) {
3804ef02da0SSiva Chandra Reddy const char initial_content[] = "1234567890987654321";
3814ef02da0SSiva Chandra Reddy const char data[] = "hello, file";
3824ef02da0SSiva Chandra Reddy constexpr size_t FILE_BUFFER_SIZE = sizeof(data) * 3 / 2;
3834ef02da0SSiva Chandra Reddy char file_buffer[FILE_BUFFER_SIZE];
3844ef02da0SSiva Chandra Reddy StringFile *f =
3856ce490e5SMichael Jones new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "a+");
3864ef02da0SSiva Chandra Reddy f->reset_and_fill(initial_content, sizeof(initial_content));
3874ef02da0SSiva Chandra Reddy
3884ef02da0SSiva Chandra Reddy ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)));
3894ef02da0SSiva Chandra Reddy EXPECT_EQ(f->get_pos(), size_t(0)); // Data is buffered in the file stream
3904ef02da0SSiva Chandra Reddy ASSERT_EQ(f->flush(), 0);
3914ef02da0SSiva Chandra Reddy // The flush should write |data| to the endof the file.
3924ef02da0SSiva Chandra Reddy EXPECT_EQ(f->get_pos(), sizeof(data) + sizeof(initial_content));
3934ef02da0SSiva Chandra Reddy
3944ef02da0SSiva Chandra Reddy ASSERT_EQ(f->seek(0, SEEK_SET), 0);
3954ef02da0SSiva Chandra Reddy // Seeking to the beginning of the file should not affect the place
3964ef02da0SSiva Chandra Reddy // where write happens.
3974ef02da0SSiva Chandra Reddy ASSERT_EQ(sizeof(data), f->write(data, sizeof(data)));
3984ef02da0SSiva Chandra Reddy ASSERT_EQ(f->flush(), 0);
3994ef02da0SSiva Chandra Reddy EXPECT_EQ(f->get_pos(), sizeof(data) * 2 + sizeof(initial_content));
4004ef02da0SSiva Chandra Reddy MemoryView src1(initial_content, sizeof(initial_content)),
4014ef02da0SSiva Chandra Reddy dst1(f->get_str(), sizeof(initial_content));
4024ef02da0SSiva Chandra Reddy EXPECT_MEM_EQ(src1, dst1);
4034ef02da0SSiva Chandra Reddy MemoryView src2(data, sizeof(data)),
4044ef02da0SSiva Chandra Reddy dst2(f->get_str() + sizeof(initial_content), sizeof(data));
4054ef02da0SSiva Chandra Reddy EXPECT_MEM_EQ(src2, dst2);
4064ef02da0SSiva Chandra Reddy MemoryView src3(data, sizeof(data)),
4074ef02da0SSiva Chandra Reddy dst3(f->get_str() + sizeof(initial_content) + sizeof(data), sizeof(data));
4084ef02da0SSiva Chandra Reddy EXPECT_MEM_EQ(src3, dst3);
4094ef02da0SSiva Chandra Reddy
4104ef02da0SSiva Chandra Reddy // Reads can happen from any point.
4114ef02da0SSiva Chandra Reddy ASSERT_EQ(f->seek(0, SEEK_SET), 0);
4124ef02da0SSiva Chandra Reddy constexpr size_t READ_SIZE = 10;
4134ef02da0SSiva Chandra Reddy char read_data[READ_SIZE];
4144ef02da0SSiva Chandra Reddy ASSERT_EQ(READ_SIZE, f->read(read_data, READ_SIZE));
4154ef02da0SSiva Chandra Reddy MemoryView src4(initial_content, READ_SIZE), dst4(read_data, READ_SIZE);
4164ef02da0SSiva Chandra Reddy EXPECT_MEM_EQ(src4, dst4);
4174ef02da0SSiva Chandra Reddy
4184ef02da0SSiva Chandra Reddy ASSERT_EQ(f->close(), 0);
4194ef02da0SSiva Chandra Reddy }
4206ce490e5SMichael Jones
TEST(LlvmLibcFileTest,SmallBuffer)4216ce490e5SMichael Jones TEST(LlvmLibcFileTest, SmallBuffer) {
4226ce490e5SMichael Jones const char WRITE_DATA[] = "small buffer";
4236ce490e5SMichael Jones constexpr size_t WRITE_SIZE = sizeof(WRITE_DATA);
4246ce490e5SMichael Jones constexpr size_t FILE_BUFFER_SIZE = sizeof(WRITE_DATA) / 2 - 1;
4256ce490e5SMichael Jones char file_buffer[FILE_BUFFER_SIZE];
4266ce490e5SMichael Jones StringFile *f =
4276ce490e5SMichael Jones new_string_file(file_buffer, FILE_BUFFER_SIZE, _IOFBF, false, "w");
4286ce490e5SMichael Jones
4296ce490e5SMichael Jones ASSERT_EQ(WRITE_SIZE, f->write(WRITE_DATA, WRITE_SIZE));
4306ce490e5SMichael Jones // Since data much larger than the buffer is being written, all of it should
4316ce490e5SMichael Jones // be available in the file without a flush operation.
4326ce490e5SMichael Jones EXPECT_EQ(f->get_pos(), sizeof(WRITE_DATA));
4336ce490e5SMichael Jones ASSERT_STREQ(f->get_str(), WRITE_DATA);
4346ce490e5SMichael Jones
4356ce490e5SMichael Jones ASSERT_EQ(f->close(), 0);
4366ce490e5SMichael Jones }
4376ce490e5SMichael Jones
TEST(LlvmLibcFileTest,ZeroLengthBuffer)4386ce490e5SMichael Jones TEST(LlvmLibcFileTest, ZeroLengthBuffer) {
4396ce490e5SMichael Jones const char WRITE_DATA[] = "small buffer";
4406ce490e5SMichael Jones constexpr size_t WRITE_SIZE = sizeof(WRITE_DATA);
4416ce490e5SMichael Jones StringFile *f_fbf = new_string_file(nullptr, 0, _IOFBF, true, "w");
4426ce490e5SMichael Jones StringFile *f_lbf = new_string_file(nullptr, 0, _IOLBF, true, "w");
4436ce490e5SMichael Jones StringFile *f_nbf = new_string_file(nullptr, 0, _IONBF, true, "w");
4446ce490e5SMichael Jones
4456ce490e5SMichael Jones ASSERT_EQ(WRITE_SIZE, f_fbf->write(WRITE_DATA, WRITE_SIZE));
4466ce490e5SMichael Jones ASSERT_EQ(WRITE_SIZE, f_lbf->write(WRITE_DATA, WRITE_SIZE));
4476ce490e5SMichael Jones ASSERT_EQ(WRITE_SIZE, f_nbf->write(WRITE_DATA, WRITE_SIZE));
4486ce490e5SMichael Jones // Since there is no buffer space, all of the written data should
4496ce490e5SMichael Jones // be available in the file without a flush operation.
4506ce490e5SMichael Jones EXPECT_EQ(f_fbf->get_pos(), sizeof(WRITE_DATA));
4516ce490e5SMichael Jones EXPECT_EQ(f_lbf->get_pos(), sizeof(WRITE_DATA));
4526ce490e5SMichael Jones EXPECT_EQ(f_nbf->get_pos(), sizeof(WRITE_DATA));
4536ce490e5SMichael Jones ASSERT_STREQ(f_fbf->get_str(), WRITE_DATA);
4546ce490e5SMichael Jones ASSERT_STREQ(f_lbf->get_str(), WRITE_DATA);
4556ce490e5SMichael Jones ASSERT_STREQ(f_nbf->get_str(), WRITE_DATA);
4566ce490e5SMichael Jones
4576ce490e5SMichael Jones ASSERT_EQ(f_fbf->close(), 0);
4586ce490e5SMichael Jones ASSERT_EQ(f_lbf->close(), 0);
4596ce490e5SMichael Jones ASSERT_EQ(f_nbf->close(), 0);
4606ce490e5SMichael Jones }
461*5bcda1d3SMichael Jones
TEST(LlvmLibcFileTest,WriteNothing)462*5bcda1d3SMichael Jones TEST(LlvmLibcFileTest, WriteNothing) {
463*5bcda1d3SMichael Jones const char WRITE_DATA[] = "";
464*5bcda1d3SMichael Jones constexpr size_t WRITE_SIZE = 0;
465*5bcda1d3SMichael Jones constexpr size_t FILE_BUFFER_SIZE = 5;
466*5bcda1d3SMichael Jones char file_buffer_fbf[FILE_BUFFER_SIZE];
467*5bcda1d3SMichael Jones char file_buffer_lbf[FILE_BUFFER_SIZE];
468*5bcda1d3SMichael Jones char file_buffer_nbf[FILE_BUFFER_SIZE];
469*5bcda1d3SMichael Jones StringFile *f_fbf =
470*5bcda1d3SMichael Jones new_string_file(file_buffer_fbf, FILE_BUFFER_SIZE, _IOFBF, false, "w");
471*5bcda1d3SMichael Jones StringFile *f_lbf =
472*5bcda1d3SMichael Jones new_string_file(file_buffer_lbf, FILE_BUFFER_SIZE, _IOLBF, false, "w");
473*5bcda1d3SMichael Jones StringFile *f_nbf =
474*5bcda1d3SMichael Jones new_string_file(file_buffer_nbf, FILE_BUFFER_SIZE, _IONBF, false, "w");
475*5bcda1d3SMichael Jones
476*5bcda1d3SMichael Jones ASSERT_EQ(WRITE_SIZE, f_fbf->write(WRITE_DATA, WRITE_SIZE));
477*5bcda1d3SMichael Jones ASSERT_EQ(WRITE_SIZE, f_lbf->write(WRITE_DATA, WRITE_SIZE));
478*5bcda1d3SMichael Jones ASSERT_EQ(WRITE_SIZE, f_nbf->write(WRITE_DATA, WRITE_SIZE));
479*5bcda1d3SMichael Jones
480*5bcda1d3SMichael Jones ASSERT_FALSE(f_fbf->error_unlocked());
481*5bcda1d3SMichael Jones ASSERT_FALSE(f_lbf->error_unlocked());
482*5bcda1d3SMichael Jones ASSERT_FALSE(f_nbf->error_unlocked());
483*5bcda1d3SMichael Jones
484*5bcda1d3SMichael Jones ASSERT_EQ(f_fbf->close(), 0);
485*5bcda1d3SMichael Jones ASSERT_EQ(f_lbf->close(), 0);
486*5bcda1d3SMichael Jones ASSERT_EQ(f_nbf->close(), 0);
487*5bcda1d3SMichael Jones }
488