1 // Formatting library for C++ - tests of the C++ interface to POSIX functions
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
6 // For the license information refer to format.h.
8 #include <cstdlib> // std::exit
11 #include "fmt/posix.h"
12 #include "gtest-extra.h"
19 using fmt::buffered_file
;
20 using fmt::error_code
;
23 using testing::internal::scoped_ptr
;
25 // Checks if the file is open by reading one character from it.
26 static bool isopen(int fd
) {
28 return FMT_POSIX(read(fd
, &buffer
, 1)) == 1;
31 static bool isclosed(int fd
) {
33 std::streamsize result
= 0;
34 SUPPRESS_ASSERT(result
= FMT_POSIX(read(fd
, &buffer
, 1)));
35 return result
== -1 && errno
== EBADF
;
38 // Opens a file for reading.
39 static file
open_file() {
40 file read_end
, write_end
;
41 file::pipe(read_end
, write_end
);
42 write_end
.write(FILE_CONTENT
, std::strlen(FILE_CONTENT
));
47 // Attempts to write a string to a file.
48 static void write(file
&f
, fmt::string_view s
) {
49 std::size_t num_chars_left
= s
.size();
50 const char *ptr
= s
.data();
52 std::size_t count
= f
.write(ptr
, num_chars_left
);
54 // We can't write more than size_t bytes since num_chars_left
56 num_chars_left
-= count
;
57 } while (num_chars_left
!= 0);
60 TEST(BufferedFileTest
, DefaultCtor
) {
62 EXPECT_TRUE(f
.get() == nullptr);
65 TEST(BufferedFileTest
, MoveCtor
) {
66 buffered_file bf
= open_buffered_file();
68 EXPECT_TRUE(fp
!= nullptr);
69 buffered_file
bf2(std::move(bf
));
70 EXPECT_EQ(fp
, bf2
.get());
71 EXPECT_TRUE(bf
.get() == nullptr);
74 TEST(BufferedFileTest
, MoveAssignment
) {
75 buffered_file bf
= open_buffered_file();
77 EXPECT_TRUE(fp
!= nullptr);
80 EXPECT_EQ(fp
, bf2
.get());
81 EXPECT_TRUE(bf
.get() == nullptr);
84 TEST(BufferedFileTest
, MoveAssignmentClosesFile
) {
85 buffered_file bf
= open_buffered_file();
86 buffered_file bf2
= open_buffered_file();
87 int old_fd
= bf2
.fileno();
89 EXPECT_TRUE(isclosed(old_fd
));
92 TEST(BufferedFileTest
, MoveFromTemporaryInCtor
) {
94 buffered_file
f(open_buffered_file(&fp
));
95 EXPECT_EQ(fp
, f
.get());
98 TEST(BufferedFileTest
, MoveFromTemporaryInAssignment
) {
101 f
= open_buffered_file(&fp
);
102 EXPECT_EQ(fp
, f
.get());
105 TEST(BufferedFileTest
, MoveFromTemporaryInAssignmentClosesFile
) {
106 buffered_file f
= open_buffered_file();
107 int old_fd
= f
.fileno();
108 f
= open_buffered_file();
109 EXPECT_TRUE(isclosed(old_fd
));
112 TEST(BufferedFileTest
, CloseFileInDtor
) {
115 buffered_file f
= open_buffered_file();
118 EXPECT_TRUE(isclosed(fd
));
121 TEST(BufferedFileTest
, CloseErrorInDtor
) {
122 scoped_ptr
<buffered_file
> f(new buffered_file(open_buffered_file()));
123 EXPECT_WRITE(stderr
, {
124 // The close function must be called inside EXPECT_WRITE, otherwise
125 // the system may recycle closed file descriptor when redirecting the
126 // output in EXPECT_STDERR and the second close will break output
128 FMT_POSIX(close(f
->fileno()));
129 SUPPRESS_ASSERT(f
.reset(nullptr));
130 }, format_system_error(EBADF
, "cannot close file") + "\n");
133 TEST(BufferedFileTest
, Close
) {
134 buffered_file f
= open_buffered_file();
137 EXPECT_TRUE(f
.get() == nullptr);
138 EXPECT_TRUE(isclosed(fd
));
141 TEST(BufferedFileTest
, CloseError
) {
142 buffered_file f
= open_buffered_file();
143 FMT_POSIX(close(f
.fileno()));
144 EXPECT_SYSTEM_ERROR_NOASSERT(f
.close(), EBADF
, "cannot close file");
145 EXPECT_TRUE(f
.get() == nullptr);
148 TEST(BufferedFileTest
, Fileno
) {
151 // fileno on a null FILE pointer either crashes or returns an error.
152 // Disable Coverity because this is intentional.
153 EXPECT_DEATH_IF_SUPPORTED({
156 } catch (const fmt::system_error
&) {
161 f
= open_buffered_file();
162 EXPECT_TRUE(f
.fileno() != -1);
163 file copy
= file::dup(f
.fileno());
164 EXPECT_READ(copy
, FILE_CONTENT
);
167 TEST(FileTest
, DefaultCtor
) {
169 EXPECT_EQ(-1, f
.descriptor());
172 TEST(FileTest
, OpenBufferedFileInCtor
) {
173 FILE *fp
= safe_fopen("test-file", "w");
174 std::fputs(FILE_CONTENT
, fp
);
176 file
f("test-file", file::RDONLY
);
177 ASSERT_TRUE(isopen(f
.descriptor()));
180 TEST(FileTest
, OpenBufferedFileError
) {
181 EXPECT_SYSTEM_ERROR(file("nonexistent", file::RDONLY
),
182 ENOENT
, "cannot open file nonexistent");
185 TEST(FileTest
, MoveCtor
) {
186 file f
= open_file();
187 int fd
= f
.descriptor();
189 file
f2(std::move(f
));
190 EXPECT_EQ(fd
, f2
.descriptor());
191 EXPECT_EQ(-1, f
.descriptor());
194 TEST(FileTest
, MoveAssignment
) {
195 file f
= open_file();
196 int fd
= f
.descriptor();
200 EXPECT_EQ(fd
, f2
.descriptor());
201 EXPECT_EQ(-1, f
.descriptor());
204 TEST(FileTest
, MoveAssignmentClosesFile
) {
205 file f
= open_file();
206 file f2
= open_file();
207 int old_fd
= f2
.descriptor();
209 EXPECT_TRUE(isclosed(old_fd
));
212 static file
OpenBufferedFile(int &fd
) {
213 file f
= open_file();
218 TEST(FileTest
, MoveFromTemporaryInCtor
) {
220 file
f(OpenBufferedFile(fd
));
221 EXPECT_EQ(fd
, f
.descriptor());
224 TEST(FileTest
, MoveFromTemporaryInAssignment
) {
227 f
= OpenBufferedFile(fd
);
228 EXPECT_EQ(fd
, f
.descriptor());
231 TEST(FileTest
, MoveFromTemporaryInAssignmentClosesFile
) {
233 file f
= open_file();
234 int old_fd
= f
.descriptor();
235 f
= OpenBufferedFile(fd
);
236 EXPECT_TRUE(isclosed(old_fd
));
239 TEST(FileTest
, CloseFileInDtor
) {
242 file f
= open_file();
245 EXPECT_TRUE(isclosed(fd
));
248 TEST(FileTest
, CloseErrorInDtor
) {
249 scoped_ptr
<file
> f(new file(open_file()));
250 EXPECT_WRITE(stderr
, {
251 // The close function must be called inside EXPECT_WRITE, otherwise
252 // the system may recycle closed file descriptor when redirecting the
253 // output in EXPECT_STDERR and the second close will break output
255 FMT_POSIX(close(f
->descriptor()));
256 SUPPRESS_ASSERT(f
.reset(nullptr));
257 }, format_system_error(EBADF
, "cannot close file") + "\n");
260 TEST(FileTest
, Close
) {
261 file f
= open_file();
262 int fd
= f
.descriptor();
264 EXPECT_EQ(-1, f
.descriptor());
265 EXPECT_TRUE(isclosed(fd
));
268 TEST(FileTest
, CloseError
) {
269 file f
= open_file();
270 FMT_POSIX(close(f
.descriptor()));
271 EXPECT_SYSTEM_ERROR_NOASSERT(f
.close(), EBADF
, "cannot close file");
272 EXPECT_EQ(-1, f
.descriptor());
275 TEST(FileTest
, Read
) {
276 file f
= open_file();
277 EXPECT_READ(f
, FILE_CONTENT
);
280 TEST(FileTest
, ReadError
) {
281 file
f("test-file", file::WRONLY
);
283 // We intentionally read from a file opened in the write-only mode to
285 EXPECT_SYSTEM_ERROR(f
.read(&buf
, 1), EBADF
, "cannot read from file");
288 TEST(FileTest
, Write
) {
289 file read_end
, write_end
;
290 file::pipe(read_end
, write_end
);
291 write(write_end
, "test");
293 EXPECT_READ(read_end
, "test");
296 TEST(FileTest
, WriteError
) {
297 file
f("test-file", file::RDONLY
);
298 // We intentionally write to a file opened in the read-only mode to
300 EXPECT_SYSTEM_ERROR(f
.write(" ", 1), EBADF
, "cannot write to file");
303 TEST(FileTest
, Dup
) {
304 file f
= open_file();
305 file copy
= file::dup(f
.descriptor());
306 EXPECT_NE(f
.descriptor(), copy
.descriptor());
307 EXPECT_EQ(FILE_CONTENT
, read(copy
, std::strlen(FILE_CONTENT
)));
311 TEST(FileTest
, DupError
) {
313 EXPECT_SYSTEM_ERROR_NOASSERT(file::dup(value
),
314 EBADF
, "cannot duplicate file descriptor -1");
318 TEST(FileTest
, Dup2
) {
319 file f
= open_file();
320 file copy
= open_file();
321 f
.dup2(copy
.descriptor());
322 EXPECT_NE(f
.descriptor(), copy
.descriptor());
323 EXPECT_READ(copy
, FILE_CONTENT
);
326 TEST(FileTest
, Dup2Error
) {
327 file f
= open_file();
328 EXPECT_SYSTEM_ERROR_NOASSERT(f
.dup2(-1), EBADF
,
329 fmt::format("cannot duplicate file descriptor {} to -1", f
.descriptor()));
332 TEST(FileTest
, Dup2NoExcept
) {
333 file f
= open_file();
334 file copy
= open_file();
336 f
.dup2(copy
.descriptor(), ec
);
337 EXPECT_EQ(0, ec
.get());
338 EXPECT_NE(f
.descriptor(), copy
.descriptor());
339 EXPECT_READ(copy
, FILE_CONTENT
);
342 TEST(FileTest
, Dup2NoExceptError
) {
343 file f
= open_file();
345 SUPPRESS_ASSERT(f
.dup2(-1, ec
));
346 EXPECT_EQ(EBADF
, ec
.get());
349 TEST(FileTest
, Pipe
) {
350 file read_end
, write_end
;
351 file::pipe(read_end
, write_end
);
352 EXPECT_NE(-1, read_end
.descriptor());
353 EXPECT_NE(-1, write_end
.descriptor());
354 write(write_end
, "test");
355 EXPECT_READ(read_end
, "test");
358 TEST(FileTest
, Fdopen
) {
359 file read_end
, write_end
;
360 file::pipe(read_end
, write_end
);
361 int read_fd
= read_end
.descriptor();
362 EXPECT_EQ(read_fd
, FMT_POSIX(fileno(read_end
.fdopen("r").get())));
365 TEST(FileTest
, FdopenError
) {
367 EXPECT_SYSTEM_ERROR_NOASSERT(
368 f
.fdopen("r"), EBADF
, "cannot associate stream with file descriptor");
372 TEST(LocaleTest
, Strtod
) {
374 const char *start
= "4.2", *ptr
= start
;
375 EXPECT_EQ(4.2, locale
.strtod(ptr
));
376 EXPECT_EQ(start
+ 3, ptr
);