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 <stdio.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(path: 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(file_name: FILENAME, mode: "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(file_name: FILENAME, mode: "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(file_name: FILENAME, mode: "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(file_name: FILENAME, mode: "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(file_name: FILENAME, mode: "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(file_name: FILENAME, mode: "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(file_name: FILENAME, mode: "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(file_name: FILENAME, mode: "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(-APPEND_TEXT_SIZE, SEEK_END).value(), 0);
107 char data[APPEND_TEXT_SIZE + 1];
108 ASSERT_EQ(file->read(data, APPEND_TEXT_SIZE).value, APPEND_TEXT_SIZE);
109 data[APPEND_TEXT_SIZE] = '\0';
110 ASSERT_STREQ(data, APPEND_TEXT);
111
112 // Reading more data should trigger EOF.
113 ASSERT_EQ(file->read(data, APPEND_TEXT_SIZE).value, size_t(0));
114 ASSERT_TRUE(file->iseof());
115
116 ASSERT_EQ(file->close(), 0);
117}
118
119TEST(LlvmLibcPlatformFileTest, LargeFile) {
120 constexpr size_t DATA_SIZE = File::DEFAULT_BUFFER_SIZE >> 2;
121 constexpr char BYTE = 123;
122 char write_data[DATA_SIZE];
123 for (size_t i = 0; i < DATA_SIZE; ++i)
124 write_data[i] = BYTE;
125
126 constexpr char FILENAME[] = "testdata/large_file.test";
127 File *file = openfile(file_name: FILENAME, mode: "w");
128 ASSERT_FALSE(file == nullptr);
129
130 constexpr int REPEAT = 5;
131 for (int i = 0; i < REPEAT; ++i) {
132 ASSERT_EQ(file->write(write_data, DATA_SIZE).value, DATA_SIZE);
133 }
134 ASSERT_EQ(file->close(), 0);
135
136 file = openfile(file_name: FILENAME, mode: "r");
137 ASSERT_FALSE(file == nullptr);
138 constexpr size_t READ_SIZE = DATA_SIZE * REPEAT;
139 char data[READ_SIZE] = {0};
140 ASSERT_EQ(file->read(data, READ_SIZE).value, READ_SIZE);
141
142 for (size_t i = 0; i < READ_SIZE; ++i)
143 ASSERT_EQ(data[i], BYTE);
144
145 // Reading more data should trigger EOF.
146 ASSERT_EQ(file->read(data, 1).value, size_t(0));
147 ASSERT_TRUE(file->iseof());
148
149 ASSERT_EQ(file->close(), 0);
150}
151
152TEST(LlvmLibcPlatformFileTest, ReadSeekCurAndRead) {
153 constexpr char FILENAME[] = "testdata/read_seek_cur_and_read.test";
154 File *file = openfile(file_name: FILENAME, mode: "w");
155 ASSERT_FALSE(file == nullptr);
156 constexpr char CONTENT[] = "1234567890987654321";
157 ASSERT_EQ(sizeof(CONTENT) - 1,
158 file->write(CONTENT, sizeof(CONTENT) - 1).value);
159 ASSERT_EQ(0, file->close());
160
161 file = openfile(file_name: FILENAME, mode: "r");
162 ASSERT_FALSE(file == nullptr);
163
164 constexpr size_t READ_SIZE = 5;
165 char data[READ_SIZE];
166 data[READ_SIZE - 1] = '\0';
167 ASSERT_EQ(file->read(data, READ_SIZE - 1).value, READ_SIZE - 1);
168 ASSERT_STREQ(data, "1234");
169 ASSERT_EQ(file->seek(5, SEEK_CUR).value(), 0);
170 ASSERT_EQ(file->read(data, READ_SIZE - 1).value, READ_SIZE - 1);
171 ASSERT_STREQ(data, "0987");
172 ASSERT_EQ(file->seek(-5, SEEK_CUR).value(), 0);
173 ASSERT_EQ(file->read(data, READ_SIZE - 1).value, READ_SIZE - 1);
174 ASSERT_STREQ(data, "9098");
175
176 ASSERT_EQ(file->close(), 0);
177}
178
179TEST(LlvmLibcPlatformFileTest, IncorrectOperation) {
180 constexpr char FILENAME[] = "testdata/incorrect_operation.test";
181 char data[1] = {123};
182
183 File *file = openfile(file_name: FILENAME, mode: "w");
184 ASSERT_FALSE(file == nullptr);
185 ASSERT_EQ(file->read(data, 1).value, size_t(0)); // Cannot read
186 ASSERT_FALSE(file->iseof());
187 ASSERT_TRUE(file->error());
188 ASSERT_EQ(file->close(), 0);
189
190 file = openfile(file_name: FILENAME, mode: "r");
191 ASSERT_FALSE(file == nullptr);
192 ASSERT_EQ(file->write(data, 1).value, size_t(0)); // Cannot write
193 ASSERT_FALSE(file->iseof());
194 ASSERT_TRUE(file->error());
195 ASSERT_EQ(file->close(), 0);
196
197 file = openfile(file_name: FILENAME, mode: "a");
198 ASSERT_FALSE(file == nullptr);
199 ASSERT_EQ(file->read(data, 1).value, size_t(0)); // Cannot read
200 ASSERT_FALSE(file->iseof());
201 ASSERT_TRUE(file->error());
202 ASSERT_EQ(file->close(), 0);
203}
204

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