xref: /aosp_15_r20/external/llvm-libc/test/src/stdio/fileop_test.cpp (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
1 //===-- Unittests for file operations like fopen, flcose etc --------------===//
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/stdio/clearerr.h"
10 #include "src/stdio/fclose.h"
11 #include "src/stdio/feof.h"
12 #include "src/stdio/ferror.h"
13 #include "src/stdio/fflush.h"
14 #include "src/stdio/fileno.h"
15 #include "src/stdio/fopen.h"
16 #include "src/stdio/fputs.h"
17 #include "src/stdio/fread.h"
18 #include "src/stdio/fseek.h"
19 #include "src/stdio/fwrite.h"
20 #include "test/UnitTest/ErrnoSetterMatcher.h"
21 #include "test/UnitTest/Test.h"
22 
23 #include "hdr/stdio_macros.h"
24 #include "src/errno/libc_errno.h"
25 
26 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::EQ;
27 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::NE;
28 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::returns;
29 
TEST(LlvmLibcFILETest,SimpleFileOperations)30 TEST(LlvmLibcFILETest, SimpleFileOperations) {
31   constexpr char FILENAME[] = "testdata/simple_operations.test";
32   ::FILE *file = LIBC_NAMESPACE::fopen(FILENAME, "w");
33   ASSERT_FALSE(file == nullptr);
34   ASSERT_EQ(LIBC_NAMESPACE::fileno(file), 3);
35   constexpr char CONTENT[] = "1234567890987654321";
36   ASSERT_EQ(sizeof(CONTENT) - 1,
37             LIBC_NAMESPACE::fwrite(CONTENT, 1, sizeof(CONTENT) - 1, file));
38 
39   // This is not a readable file.
40   char read_data[sizeof(CONTENT)];
41   ASSERT_THAT(LIBC_NAMESPACE::fread(read_data, 1, sizeof(CONTENT), file),
42               returns(EQ(size_t(0))).with_errno(NE(0)));
43   ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0);
44   LIBC_NAMESPACE::libc_errno = 0;
45 
46   LIBC_NAMESPACE::clearerr(file);
47   ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0);
48 
49   ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file));
50 
51   file = LIBC_NAMESPACE::fopen(FILENAME, "r");
52   ASSERT_FALSE(file == nullptr);
53 
54   constexpr size_t READ_SIZE = 5;
55   char data[READ_SIZE];
56   data[READ_SIZE - 1] = '\0';
57   ASSERT_EQ(LIBC_NAMESPACE::fread(data, 1, READ_SIZE - 1, file), READ_SIZE - 1);
58   ASSERT_STREQ(data, "1234");
59   ASSERT_EQ(LIBC_NAMESPACE::fseek(file, 5, SEEK_CUR), 0);
60   ASSERT_EQ(LIBC_NAMESPACE::fread(data, 1, READ_SIZE - 1, file), READ_SIZE - 1);
61   ASSERT_STREQ(data, "0987");
62   ASSERT_EQ(LIBC_NAMESPACE::fseek(file, -5, SEEK_CUR), 0);
63   ASSERT_EQ(LIBC_NAMESPACE::fread(data, 1, READ_SIZE - 1, file), READ_SIZE - 1);
64   ASSERT_STREQ(data, "9098");
65 
66   // Reading another time should trigger eof.
67   ASSERT_NE(sizeof(CONTENT),
68             LIBC_NAMESPACE::fread(read_data, 1, sizeof(CONTENT), file));
69   ASSERT_NE(LIBC_NAMESPACE::feof(file), 0);
70 
71   // Should be an error to write.
72   ASSERT_THAT(LIBC_NAMESPACE::fwrite(CONTENT, 1, sizeof(CONTENT), file),
73               returns(EQ(size_t(0))).with_errno(NE(0)));
74   ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0);
75   LIBC_NAMESPACE::libc_errno = 0;
76 
77   LIBC_NAMESPACE::clearerr(file);
78 
79   // Should be an error to puts.
80   ASSERT_THAT(LIBC_NAMESPACE::fputs(CONTENT, file),
81               returns(EQ(EOF)).with_errno(NE(0)));
82   ASSERT_NE(LIBC_NAMESPACE::ferror(file), 0);
83   LIBC_NAMESPACE::libc_errno = 0;
84 
85   LIBC_NAMESPACE::clearerr(file);
86   ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0);
87 
88   LIBC_NAMESPACE::libc_errno = 0;
89   ASSERT_THAT(LIBC_NAMESPACE::fwrite("nothing", 1, 1, file),
90               returns(EQ(0)).with_errno(NE(0)));
91   LIBC_NAMESPACE::libc_errno = 0;
92 
93   ASSERT_EQ(LIBC_NAMESPACE::fclose(file), 0);
94 
95   // Now try puts.
96   file = LIBC_NAMESPACE::fopen(FILENAME, "w");
97   ASSERT_FALSE(file == nullptr);
98   // fputs returns a negative value on error (EOF) or any non-negative value on
99   // success. This assert checks that the return value is non-negative.
100   ASSERT_GE(LIBC_NAMESPACE::fputs(CONTENT, file), 0);
101 
102   LIBC_NAMESPACE::clearerr(file);
103   ASSERT_EQ(LIBC_NAMESPACE::ferror(file), 0);
104 
105   // This is not a readable file.
106   LIBC_NAMESPACE::libc_errno = 0;
107   ASSERT_THAT(LIBC_NAMESPACE::fread(data, 1, 1, file),
108               returns(EQ(0)).with_errno(NE(0)));
109   LIBC_NAMESPACE::libc_errno = 0;
110 
111   ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file));
112 
113   file = LIBC_NAMESPACE::fopen(FILENAME, "r");
114   ASSERT_FALSE(file == nullptr);
115 
116   ASSERT_EQ(LIBC_NAMESPACE::fread(read_data, 1, sizeof(CONTENT) - 1, file),
117             sizeof(CONTENT) - 1);
118   read_data[sizeof(CONTENT) - 1] = '\0';
119   ASSERT_STREQ(read_data, CONTENT);
120   ASSERT_EQ(LIBC_NAMESPACE::fclose(file), 0);
121 
122   // Check that the other functions correctly set libc_errno.
123 
124   // LIBC_NAMESPACE::libc_errno = 0;
125   // ASSERT_NE(LIBC_NAMESPACE::fseek(file, 0, SEEK_SET), 0);
126   // ASSERT_ERRNO_FAILURE();
127 
128   // LIBC_NAMESPACE::libc_errno = 0;
129   // ASSERT_NE(LIBC_NAMESPACE::fclose(file), 0);
130   // ASSERT_ERRNO_FAILURE();
131 
132   // LIBC_NAMESPACE::libc_errno = 0;
133   // ASSERT_EQ(LIBC_NAMESPACE::fopen("INVALID FILE NAME", "r"),
134   //           static_cast<FILE *>(nullptr));
135   // ASSERT_ERRNO_FAILURE();
136 }
137 
TEST(LlvmLibcFILETest,FFlush)138 TEST(LlvmLibcFILETest, FFlush) {
139   constexpr char FILENAME[] = "testdata/fflush.test";
140   ::FILE *file = LIBC_NAMESPACE::fopen(FILENAME, "w+");
141   ASSERT_FALSE(file == nullptr);
142   constexpr char CONTENT[] = "1234567890987654321";
143   ASSERT_EQ(sizeof(CONTENT),
144             LIBC_NAMESPACE::fwrite(CONTENT, 1, sizeof(CONTENT), file));
145 
146   // Flushing at this point should write the data to disk. So, we should be
147   // able to read it back.
148   ASSERT_EQ(0, LIBC_NAMESPACE::fflush(file));
149 
150   char data[sizeof(CONTENT)];
151   ASSERT_EQ(LIBC_NAMESPACE::fseek(file, 0, SEEK_SET), 0);
152   ASSERT_EQ(LIBC_NAMESPACE::fread(data, 1, sizeof(CONTENT), file),
153             sizeof(CONTENT));
154   ASSERT_STREQ(data, CONTENT);
155 
156   ASSERT_EQ(LIBC_NAMESPACE::fclose(file), 0);
157 }
158 
TEST(LlvmLibcFILETest,FOpenFWriteSizeGreaterThanOne)159 TEST(LlvmLibcFILETest, FOpenFWriteSizeGreaterThanOne) {
160   using MyStruct = struct {
161     char c;
162     unsigned long long i;
163   };
164   constexpr MyStruct WRITE_DATA[] = {{'a', 1}, {'b', 2}, {'c', 3}};
165   constexpr size_t WRITE_NMEMB = sizeof(WRITE_DATA) / sizeof(MyStruct);
166   constexpr char FILENAME[] = "testdata/fread_fwrite.test";
167 
168   LIBC_NAMESPACE::libc_errno = 0;
169   FILE *file = LIBC_NAMESPACE::fopen(FILENAME, "w");
170   ASSERT_FALSE(file == nullptr);
171   ASSERT_EQ(size_t(0), LIBC_NAMESPACE::fwrite(WRITE_DATA, 0, 1, file));
172   ASSERT_THAT(
173       LIBC_NAMESPACE::fwrite(WRITE_DATA, sizeof(MyStruct), WRITE_NMEMB, file),
174       returns(EQ(WRITE_NMEMB)).with_errno(EQ(0)));
175   ASSERT_EQ(LIBC_NAMESPACE::fclose(file), 0);
176 
177   file = LIBC_NAMESPACE::fopen(FILENAME, "r");
178   ASSERT_FALSE(file == nullptr);
179   MyStruct read_data[WRITE_NMEMB];
180   ASSERT_EQ(size_t(0), LIBC_NAMESPACE::fread(read_data, 0, 1, file));
181   ASSERT_THAT(
182       LIBC_NAMESPACE::fread(read_data, sizeof(MyStruct), WRITE_NMEMB, file),
183       returns(EQ(WRITE_NMEMB)).with_errno(EQ(0)));
184   // Trying to read more should fetch nothing.
185   ASSERT_THAT(
186       LIBC_NAMESPACE::fread(read_data, sizeof(MyStruct), WRITE_NMEMB, file),
187       returns(EQ(0)).with_errno(EQ(0)));
188   EXPECT_NE(LIBC_NAMESPACE::feof(file), 0);
189   EXPECT_EQ(LIBC_NAMESPACE::ferror(file), 0);
190   ASSERT_EQ(LIBC_NAMESPACE::fclose(file), 0);
191   // Verify that the data which was read is correct.
192   for (size_t i = 0; i < WRITE_NMEMB; ++i) {
193     ASSERT_EQ(read_data[i].c, WRITE_DATA[i].c);
194     ASSERT_EQ(read_data[i].i, WRITE_DATA[i].i);
195   }
196 }
197