• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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