1 // Formatting library for C++ - tests of the C++ interface to POSIX functions
2 //
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
5 //
6 // For the license information refer to format.h.
7
8 #include <cstdlib> // std::exit
9 #include <cstring>
10 #include <memory>
11
12 #include "fmt/posix.h"
13 #include "gtest-extra.h"
14 #include "util.h"
15
16 #ifdef fileno
17 # undef fileno
18 #endif
19
20 using fmt::buffered_file;
21 using fmt::error_code;
22
23 #if FMT_USE_FCNTL
24
25 using fmt::file;
26
27 // Checks if the file is open by reading one character from it.
isopen(int fd)28 static bool isopen(int fd) {
29 char buffer;
30 return FMT_POSIX(read(fd, &buffer, 1)) == 1;
31 }
32
isclosed(int fd)33 static bool isclosed(int fd) {
34 char buffer;
35 std::streamsize result = 0;
36 SUPPRESS_ASSERT(result = FMT_POSIX(read(fd, &buffer, 1)));
37 return result == -1 && errno == EBADF;
38 }
39
40 // Opens a file for reading.
open_file()41 static file open_file() {
42 file read_end, write_end;
43 file::pipe(read_end, write_end);
44 write_end.write(FILE_CONTENT, std::strlen(FILE_CONTENT));
45 write_end.close();
46 return read_end;
47 }
48
49 // Attempts to write a string to a file.
write(file & f,fmt::string_view s)50 static void write(file& f, fmt::string_view s) {
51 std::size_t num_chars_left = s.size();
52 const char* ptr = s.data();
53 do {
54 std::size_t count = f.write(ptr, num_chars_left);
55 ptr += count;
56 // We can't write more than size_t bytes since num_chars_left
57 // has type size_t.
58 num_chars_left -= count;
59 } while (num_chars_left != 0);
60 }
61
TEST(BufferedFileTest,DefaultCtor)62 TEST(BufferedFileTest, DefaultCtor) {
63 buffered_file f;
64 EXPECT_TRUE(f.get() == nullptr);
65 }
66
TEST(BufferedFileTest,MoveCtor)67 TEST(BufferedFileTest, MoveCtor) {
68 buffered_file bf = open_buffered_file();
69 FILE* fp = bf.get();
70 EXPECT_TRUE(fp != nullptr);
71 buffered_file bf2(std::move(bf));
72 EXPECT_EQ(fp, bf2.get());
73 EXPECT_TRUE(bf.get() == nullptr);
74 }
75
TEST(BufferedFileTest,MoveAssignment)76 TEST(BufferedFileTest, MoveAssignment) {
77 buffered_file bf = open_buffered_file();
78 FILE* fp = bf.get();
79 EXPECT_TRUE(fp != nullptr);
80 buffered_file bf2;
81 bf2 = std::move(bf);
82 EXPECT_EQ(fp, bf2.get());
83 EXPECT_TRUE(bf.get() == nullptr);
84 }
85
TEST(BufferedFileTest,MoveAssignmentClosesFile)86 TEST(BufferedFileTest, MoveAssignmentClosesFile) {
87 buffered_file bf = open_buffered_file();
88 buffered_file bf2 = open_buffered_file();
89 int old_fd = bf2.fileno();
90 bf2 = std::move(bf);
91 EXPECT_TRUE(isclosed(old_fd));
92 }
93
TEST(BufferedFileTest,MoveFromTemporaryInCtor)94 TEST(BufferedFileTest, MoveFromTemporaryInCtor) {
95 FILE* fp = nullptr;
96 buffered_file f(open_buffered_file(&fp));
97 EXPECT_EQ(fp, f.get());
98 }
99
TEST(BufferedFileTest,MoveFromTemporaryInAssignment)100 TEST(BufferedFileTest, MoveFromTemporaryInAssignment) {
101 FILE* fp = nullptr;
102 buffered_file f;
103 f = open_buffered_file(&fp);
104 EXPECT_EQ(fp, f.get());
105 }
106
TEST(BufferedFileTest,MoveFromTemporaryInAssignmentClosesFile)107 TEST(BufferedFileTest, MoveFromTemporaryInAssignmentClosesFile) {
108 buffered_file f = open_buffered_file();
109 int old_fd = f.fileno();
110 f = open_buffered_file();
111 EXPECT_TRUE(isclosed(old_fd));
112 }
113
TEST(BufferedFileTest,CloseFileInDtor)114 TEST(BufferedFileTest, CloseFileInDtor) {
115 int fd = 0;
116 {
117 buffered_file f = open_buffered_file();
118 fd = f.fileno();
119 }
120 EXPECT_TRUE(isclosed(fd));
121 }
122
TEST(BufferedFileTest,CloseErrorInDtor)123 TEST(BufferedFileTest, CloseErrorInDtor) {
124 std::unique_ptr<buffered_file> f(new buffered_file(open_buffered_file()));
125 EXPECT_WRITE(stderr,
126 {
127 // The close function must be called inside EXPECT_WRITE,
128 // otherwise the system may recycle closed file descriptor when
129 // redirecting the output in EXPECT_STDERR and the second close
130 // will break output redirection.
131 FMT_POSIX(close(f->fileno()));
132 SUPPRESS_ASSERT(f.reset(nullptr));
133 },
134 format_system_error(EBADF, "cannot close file") + "\n");
135 }
136
TEST(BufferedFileTest,Close)137 TEST(BufferedFileTest, Close) {
138 buffered_file f = open_buffered_file();
139 int fd = f.fileno();
140 f.close();
141 EXPECT_TRUE(f.get() == nullptr);
142 EXPECT_TRUE(isclosed(fd));
143 }
144
TEST(BufferedFileTest,CloseError)145 TEST(BufferedFileTest, CloseError) {
146 buffered_file f = open_buffered_file();
147 FMT_POSIX(close(f.fileno()));
148 EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
149 EXPECT_TRUE(f.get() == nullptr);
150 }
151
TEST(BufferedFileTest,Fileno)152 TEST(BufferedFileTest, Fileno) {
153 buffered_file f;
154 #ifndef __COVERITY__
155 // fileno on a null FILE pointer either crashes or returns an error.
156 // Disable Coverity because this is intentional.
157 EXPECT_DEATH_IF_SUPPORTED(
158 {
159 try {
160 f.fileno();
161 } catch (const fmt::system_error&) {
162 std::exit(1);
163 }
164 },
165 "");
166 #endif
167 f = open_buffered_file();
168 EXPECT_TRUE(f.fileno() != -1);
169 file copy = file::dup(f.fileno());
170 EXPECT_READ(copy, FILE_CONTENT);
171 }
172
TEST(FileTest,DefaultCtor)173 TEST(FileTest, DefaultCtor) {
174 file f;
175 EXPECT_EQ(-1, f.descriptor());
176 }
177
TEST(FileTest,OpenBufferedFileInCtor)178 TEST(FileTest, OpenBufferedFileInCtor) {
179 FILE* fp = safe_fopen("test-file", "w");
180 std::fputs(FILE_CONTENT, fp);
181 std::fclose(fp);
182 file f("test-file", file::RDONLY);
183 ASSERT_TRUE(isopen(f.descriptor()));
184 }
185
TEST(FileTest,OpenBufferedFileError)186 TEST(FileTest, OpenBufferedFileError) {
187 EXPECT_SYSTEM_ERROR(file("nonexistent", file::RDONLY), ENOENT,
188 "cannot open file nonexistent");
189 }
190
TEST(FileTest,MoveCtor)191 TEST(FileTest, MoveCtor) {
192 file f = open_file();
193 int fd = f.descriptor();
194 EXPECT_NE(-1, fd);
195 file f2(std::move(f));
196 EXPECT_EQ(fd, f2.descriptor());
197 EXPECT_EQ(-1, f.descriptor());
198 }
199
TEST(FileTest,MoveAssignment)200 TEST(FileTest, MoveAssignment) {
201 file f = open_file();
202 int fd = f.descriptor();
203 EXPECT_NE(-1, fd);
204 file f2;
205 f2 = std::move(f);
206 EXPECT_EQ(fd, f2.descriptor());
207 EXPECT_EQ(-1, f.descriptor());
208 }
209
TEST(FileTest,MoveAssignmentClosesFile)210 TEST(FileTest, MoveAssignmentClosesFile) {
211 file f = open_file();
212 file f2 = open_file();
213 int old_fd = f2.descriptor();
214 f2 = std::move(f);
215 EXPECT_TRUE(isclosed(old_fd));
216 }
217
OpenBufferedFile(int & fd)218 static file OpenBufferedFile(int& fd) {
219 file f = open_file();
220 fd = f.descriptor();
221 return f;
222 }
223
TEST(FileTest,MoveFromTemporaryInCtor)224 TEST(FileTest, MoveFromTemporaryInCtor) {
225 int fd = 0xdead;
226 file f(OpenBufferedFile(fd));
227 EXPECT_EQ(fd, f.descriptor());
228 }
229
TEST(FileTest,MoveFromTemporaryInAssignment)230 TEST(FileTest, MoveFromTemporaryInAssignment) {
231 int fd = 0xdead;
232 file f;
233 f = OpenBufferedFile(fd);
234 EXPECT_EQ(fd, f.descriptor());
235 }
236
TEST(FileTest,MoveFromTemporaryInAssignmentClosesFile)237 TEST(FileTest, MoveFromTemporaryInAssignmentClosesFile) {
238 int fd = 0xdead;
239 file f = open_file();
240 int old_fd = f.descriptor();
241 f = OpenBufferedFile(fd);
242 EXPECT_TRUE(isclosed(old_fd));
243 }
244
TEST(FileTest,CloseFileInDtor)245 TEST(FileTest, CloseFileInDtor) {
246 int fd = 0;
247 {
248 file f = open_file();
249 fd = f.descriptor();
250 }
251 EXPECT_TRUE(isclosed(fd));
252 }
253
TEST(FileTest,CloseErrorInDtor)254 TEST(FileTest, CloseErrorInDtor) {
255 std::unique_ptr<file> f(new file(open_file()));
256 EXPECT_WRITE(stderr,
257 {
258 // The close function must be called inside EXPECT_WRITE,
259 // otherwise the system may recycle closed file descriptor when
260 // redirecting the output in EXPECT_STDERR and the second close
261 // will break output redirection.
262 FMT_POSIX(close(f->descriptor()));
263 SUPPRESS_ASSERT(f.reset(nullptr));
264 },
265 format_system_error(EBADF, "cannot close file") + "\n");
266 }
267
TEST(FileTest,Close)268 TEST(FileTest, Close) {
269 file f = open_file();
270 int fd = f.descriptor();
271 f.close();
272 EXPECT_EQ(-1, f.descriptor());
273 EXPECT_TRUE(isclosed(fd));
274 }
275
TEST(FileTest,CloseError)276 TEST(FileTest, CloseError) {
277 file f = open_file();
278 FMT_POSIX(close(f.descriptor()));
279 EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
280 EXPECT_EQ(-1, f.descriptor());
281 }
282
TEST(FileTest,Read)283 TEST(FileTest, Read) {
284 file f = open_file();
285 EXPECT_READ(f, FILE_CONTENT);
286 }
287
TEST(FileTest,ReadError)288 TEST(FileTest, ReadError) {
289 file f("test-file", file::WRONLY);
290 char buf;
291 // We intentionally read from a file opened in the write-only mode to
292 // cause error.
293 EXPECT_SYSTEM_ERROR(f.read(&buf, 1), EBADF, "cannot read from file");
294 }
295
TEST(FileTest,Write)296 TEST(FileTest, Write) {
297 file read_end, write_end;
298 file::pipe(read_end, write_end);
299 write(write_end, "test");
300 write_end.close();
301 EXPECT_READ(read_end, "test");
302 }
303
TEST(FileTest,WriteError)304 TEST(FileTest, WriteError) {
305 file f("test-file", file::RDONLY);
306 // We intentionally write to a file opened in the read-only mode to
307 // cause error.
308 EXPECT_SYSTEM_ERROR(f.write(" ", 1), EBADF, "cannot write to file");
309 }
310
TEST(FileTest,Dup)311 TEST(FileTest, Dup) {
312 file f = open_file();
313 file copy = file::dup(f.descriptor());
314 EXPECT_NE(f.descriptor(), copy.descriptor());
315 EXPECT_EQ(FILE_CONTENT, read(copy, std::strlen(FILE_CONTENT)));
316 }
317
318 #ifndef __COVERITY__
TEST(FileTest,DupError)319 TEST(FileTest, DupError) {
320 int value = -1;
321 EXPECT_SYSTEM_ERROR_NOASSERT(file::dup(value), EBADF,
322 "cannot duplicate file descriptor -1");
323 }
324 #endif
325
TEST(FileTest,Dup2)326 TEST(FileTest, Dup2) {
327 file f = open_file();
328 file copy = open_file();
329 f.dup2(copy.descriptor());
330 EXPECT_NE(f.descriptor(), copy.descriptor());
331 EXPECT_READ(copy, FILE_CONTENT);
332 }
333
TEST(FileTest,Dup2Error)334 TEST(FileTest, Dup2Error) {
335 file f = open_file();
336 EXPECT_SYSTEM_ERROR_NOASSERT(
337 f.dup2(-1), EBADF,
338 fmt::format("cannot duplicate file descriptor {} to -1", f.descriptor()));
339 }
340
TEST(FileTest,Dup2NoExcept)341 TEST(FileTest, Dup2NoExcept) {
342 file f = open_file();
343 file copy = open_file();
344 error_code ec;
345 f.dup2(copy.descriptor(), ec);
346 EXPECT_EQ(ec.get(), 0);
347 EXPECT_NE(f.descriptor(), copy.descriptor());
348 EXPECT_READ(copy, FILE_CONTENT);
349 }
350
TEST(FileTest,Dup2NoExceptError)351 TEST(FileTest, Dup2NoExceptError) {
352 file f = open_file();
353 error_code ec;
354 SUPPRESS_ASSERT(f.dup2(-1, ec));
355 EXPECT_EQ(EBADF, ec.get());
356 }
357
TEST(FileTest,Pipe)358 TEST(FileTest, Pipe) {
359 file read_end, write_end;
360 file::pipe(read_end, write_end);
361 EXPECT_NE(-1, read_end.descriptor());
362 EXPECT_NE(-1, write_end.descriptor());
363 write(write_end, "test");
364 EXPECT_READ(read_end, "test");
365 }
366
TEST(FileTest,Fdopen)367 TEST(FileTest, Fdopen) {
368 file read_end, write_end;
369 file::pipe(read_end, write_end);
370 int read_fd = read_end.descriptor();
371 EXPECT_EQ(read_fd, FMT_POSIX(fileno(read_end.fdopen("r").get())));
372 }
373
374 #ifdef FMT_LOCALE
TEST(LocaleTest,Strtod)375 TEST(LocaleTest, Strtod) {
376 fmt::Locale locale;
377 const char *start = "4.2", *ptr = start;
378 EXPECT_EQ(4.2, locale.strtod(ptr));
379 EXPECT_EQ(start + 3, ptr);
380 }
381 #endif
382 #endif // FMT_USE_FCNTL