1//===-- Unittests for target platform file implementation -----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "src/__support/File/file.h"
10#include "test/UnitTest/Test.h"
11
12#include "hdr/stdio_macros.h" // For SEEK_* macros
13
14using File = LIBC_NAMESPACE::File;
15constexpr char TEXT[] = "Hello, File";
16constexpr size_t TEXT_SIZE = sizeof(TEXT) - 1; // Ignore the null terminator
17
18LIBC_INLINE File *openfile(const char *file_name, const char *mode) {
19 auto error_or_file = LIBC_NAMESPACE::openfile(file_name, mode);
20 return error_or_file.has_value() ? error_or_file.value() : nullptr;
21}
22
23TEST(LlvmLibcPlatformFileTest, CreateWriteCloseAndReadBack) {
24 constexpr char FILENAME[] = "testdata/create_write_close_and_readback.test";
25 File *file = openfile(FILENAME, "w");
26 ASSERT_FALSE(file == nullptr);
27 ASSERT_EQ(file->write(TEXT, TEXT_SIZE).value, TEXT_SIZE);
28 ASSERT_EQ(file->close(), 0);
29
30 file = openfile(FILENAME, "r");
31 ASSERT_FALSE(file == nullptr);
32 char data[sizeof(TEXT)];
33 ASSERT_EQ(file->read(data, TEXT_SIZE).value, TEXT_SIZE);
34 data[TEXT_SIZE] = '\0';
35 ASSERT_STREQ(data, TEXT);
36
37 // Reading more data should trigger EOF.
38 ASSERT_EQ(file->read(data, TEXT_SIZE).value, size_t(0));
39 ASSERT_TRUE(file->iseof());
40
41 ASSERT_EQ(file->close(), 0);
42}
43
44TEST(LlvmLibcPlatformFileTest, CreateWriteSeekAndReadBack) {
45 constexpr char FILENAME[] = "testdata/create_write_seek_and_readback.test";
46 File *file = openfile(FILENAME, "w+");
47 ASSERT_FALSE(file == nullptr);
48 ASSERT_EQ(file->write(TEXT, TEXT_SIZE).value, TEXT_SIZE);
49
50 ASSERT_EQ(file->seek(0, SEEK_SET).value(), 0);
51
52 char data[sizeof(TEXT)];
53 ASSERT_EQ(file->read(data, TEXT_SIZE).value, TEXT_SIZE);
54 data[TEXT_SIZE] = '\0';
55 ASSERT_STREQ(data, TEXT);
56
57 // Reading more data should trigger EOF.
58 ASSERT_EQ(file->read(data, TEXT_SIZE).value, size_t(0));
59 ASSERT_TRUE(file->iseof());
60
61 ASSERT_EQ(file->close(), 0);
62}
63
64TEST(LlvmLibcPlatformFileTest, CreateAppendCloseAndReadBack) {
65 constexpr char FILENAME[] = "testdata/create_append_close_and_readback.test";
66 File *file = openfile(FILENAME, "w");
67 ASSERT_FALSE(file == nullptr);
68 ASSERT_EQ(file->write(TEXT, TEXT_SIZE).value, TEXT_SIZE);
69 ASSERT_EQ(file->close(), 0);
70
71 file = openfile(FILENAME, "a");
72 ASSERT_FALSE(file == nullptr);
73 constexpr char APPEND_TEXT[] = " Append Text";
74 constexpr size_t APPEND_TEXT_SIZE = sizeof(APPEND_TEXT) - 1;
75 ASSERT_EQ(file->write(APPEND_TEXT, APPEND_TEXT_SIZE).value, APPEND_TEXT_SIZE);
76 ASSERT_EQ(file->close(), 0);
77
78 file = openfile(FILENAME, "r");
79 ASSERT_FALSE(file == nullptr);
80 constexpr size_t READ_SIZE = TEXT_SIZE + APPEND_TEXT_SIZE;
81 char data[READ_SIZE + 1];
82 ASSERT_EQ(file->read(data, READ_SIZE).value, READ_SIZE);
83 data[READ_SIZE] = '\0';
84 ASSERT_STREQ(data, "Hello, File Append Text");
85
86 // Reading more data should trigger EOF.
87 ASSERT_EQ(file->read(data, READ_SIZE).value, size_t(0));
88 ASSERT_TRUE(file->iseof());
89
90 ASSERT_EQ(file->close(), 0);
91}
92
93TEST(LlvmLibcPlatformFileTest, CreateAppendSeekAndReadBack) {
94 constexpr char FILENAME[] = "testdata/create_append_seek_and_readback.test";
95 File *file = openfile(FILENAME, "w");
96 ASSERT_FALSE(file == nullptr);
97 ASSERT_EQ(file->write(TEXT, TEXT_SIZE).value, TEXT_SIZE);
98 ASSERT_EQ(file->close(), 0);
99
100 file = openfile(FILENAME, "a+");
101 ASSERT_FALSE(file == nullptr);
102 constexpr char APPEND_TEXT[] = " Append Text";
103 constexpr size_t APPEND_TEXT_SIZE = sizeof(APPEND_TEXT) - 1;
104 ASSERT_EQ(file->write(APPEND_TEXT, APPEND_TEXT_SIZE).value, APPEND_TEXT_SIZE);
105
106 ASSERT_EQ(file->seek(-static_cast<off_t>(APPEND_TEXT_SIZE), SEEK_END).value(),
107 0);
108 char data[APPEND_TEXT_SIZE + 1];
109 ASSERT_EQ(file->read(data, APPEND_TEXT_SIZE).value, APPEND_TEXT_SIZE);
110 data[APPEND_TEXT_SIZE] = '\0';
111 ASSERT_STREQ(data, APPEND_TEXT);
112
113 // Reading more data should trigger EOF.
114 ASSERT_EQ(file->read(data, APPEND_TEXT_SIZE).value, size_t(0));
115 ASSERT_TRUE(file->iseof());
116
117 ASSERT_EQ(file->close(), 0);
118}
119
120TEST(LlvmLibcPlatformFileTest, LargeFile) {
121 constexpr size_t DATA_SIZE = File::DEFAULT_BUFFER_SIZE >> 2;
122 constexpr char BYTE = 123;
123 char write_data[DATA_SIZE];
124 for (size_t i = 0; i < DATA_SIZE; ++i)
125 write_data[i] = BYTE;
126
127 constexpr char FILENAME[] = "testdata/large_file.test";
128 File *file = openfile(FILENAME, "w");
129 ASSERT_FALSE(file == nullptr);
130
131 constexpr int REPEAT = 5;
132 for (int i = 0; i < REPEAT; ++i) {
133 ASSERT_EQ(file->write(write_data, DATA_SIZE).value, DATA_SIZE);
134 }
135 ASSERT_EQ(file->close(), 0);
136
137 file = openfile(FILENAME, "r");
138 ASSERT_FALSE(file == nullptr);
139 constexpr size_t READ_SIZE = DATA_SIZE * REPEAT;
140 char data[READ_SIZE] = {0};
141 ASSERT_EQ(file->read(data, READ_SIZE).value, READ_SIZE);
142
143 for (size_t i = 0; i < READ_SIZE; ++i)
144 ASSERT_EQ(data[i], BYTE);
145
146 // Reading more data should trigger EOF.
147 ASSERT_EQ(file->read(data, 1).value, size_t(0));
148 ASSERT_TRUE(file->iseof());
149
150 ASSERT_EQ(file->close(), 0);
151}
152
153TEST(LlvmLibcPlatformFileTest, ReadSeekCurAndRead) {
154 constexpr char FILENAME[] = "testdata/read_seek_cur_and_read.test";
155 File *file = openfile(FILENAME, "w");
156 ASSERT_FALSE(file == nullptr);
157 constexpr char CONTENT[] = "1234567890987654321";
158 ASSERT_EQ(sizeof(CONTENT) - 1,
159 file->write(CONTENT, sizeof(CONTENT) - 1).value);
160 ASSERT_EQ(0, file->close());
161
162 file = openfile(FILENAME, "r");
163 ASSERT_FALSE(file == nullptr);
164
165 constexpr size_t READ_SIZE = 5;
166 char data[READ_SIZE];
167 data[READ_SIZE - 1] = '\0';
168 ASSERT_EQ(file->read(data, READ_SIZE - 1).value, READ_SIZE - 1);
169 ASSERT_STREQ(data, "1234");
170 ASSERT_EQ(file->seek(5, SEEK_CUR).value(), 0);
171 ASSERT_EQ(file->read(data, READ_SIZE - 1).value, READ_SIZE - 1);
172 ASSERT_STREQ(data, "0987");
173 ASSERT_EQ(file->seek(-5, SEEK_CUR).value(), 0);
174 ASSERT_EQ(file->read(data, READ_SIZE - 1).value, READ_SIZE - 1);
175 ASSERT_STREQ(data, "9098");
176
177 ASSERT_EQ(file->close(), 0);
178}
179
180TEST(LlvmLibcPlatformFileTest, IncorrectOperation) {
181 constexpr char FILENAME[] = "testdata/incorrect_operation.test";
182 char data[1] = {123};
183
184 File *file = openfile(FILENAME, "w");
185 ASSERT_FALSE(file == nullptr);
186 ASSERT_EQ(file->read(data, 1).value, size_t(0)); // Cannot read
187 ASSERT_FALSE(file->iseof());
188 ASSERT_TRUE(file->error());
189 ASSERT_EQ(file->close(), 0);
190
191 file = openfile(FILENAME, "r");
192 ASSERT_FALSE(file == nullptr);
193 ASSERT_EQ(file->write(data, 1).value, size_t(0)); // Cannot write
194 ASSERT_FALSE(file->iseof());
195 ASSERT_TRUE(file->error());
196 ASSERT_EQ(file->close(), 0);
197
198 file = openfile(FILENAME, "a");
199 ASSERT_FALSE(file == nullptr);
200 ASSERT_EQ(file->read(data, 1).value, size_t(0)); // Cannot read
201 ASSERT_FALSE(file->iseof());
202 ASSERT_TRUE(file->error());
203 ASSERT_EQ(file->close(), 0);
204}
205

source code of libc/test/src/__support/File/platform_file_test.cpp