xref: /aosp_15_r20/external/fmtlib/test/os-test.cc (revision 5c90c05cd622c0a81b57953a4d343e0e489f2e08)
1 // Formatting library for C++ - tests of the OS-specific functionality
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 "fmt/os.h"
9 
10 #include <cstdlib>  // std::exit
11 #include <cstring>
12 #include <memory>
13 
14 #include "gtest-extra.h"
15 #include "util.h"
16 
17 using fmt::buffered_file;
18 using testing::HasSubstr;
19 using wstring_view = fmt::basic_string_view<wchar_t>;
20 
uniq_file_name(unsigned line_number)21 static std::string uniq_file_name(unsigned line_number) {
22   return "test-file" + std::to_string(line_number);
23 }
24 
25 #ifdef _WIN32
26 
27 #  include <windows.h>
28 
TEST(os_test,format_windows_error)29 TEST(os_test, format_windows_error) {
30   LPWSTR message = nullptr;
31   auto result = FormatMessageW(
32       FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
33           FORMAT_MESSAGE_IGNORE_INSERTS,
34       nullptr, ERROR_FILE_EXISTS, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
35       reinterpret_cast<LPWSTR>(&message), 0, nullptr);
36   auto utf8_message =
37       fmt::detail::to_utf8<wchar_t>(wstring_view(message, result - 2));
38   LocalFree(message);
39   fmt::memory_buffer actual_message;
40   fmt::detail::format_windows_error(actual_message, ERROR_FILE_EXISTS, "test");
41   EXPECT_EQ(fmt::format("test: {}", utf8_message.str()),
42             fmt::to_string(actual_message));
43   actual_message.resize(0);
44 }
45 
TEST(os_test,format_long_windows_error)46 TEST(os_test, format_long_windows_error) {
47   LPWSTR message = nullptr;
48   // this error code is not available on all Windows platforms and
49   // Windows SDKs, so do not fail the test if the error string cannot
50   // be retrieved.
51   int provisioning_not_allowed = 0x80284013L;  // TBS_E_PROVISIONING_NOT_ALLOWED
52   auto result = FormatMessageW(
53       FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
54           FORMAT_MESSAGE_IGNORE_INSERTS,
55       nullptr, static_cast<DWORD>(provisioning_not_allowed),
56       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
57       reinterpret_cast<LPWSTR>(&message), 0, nullptr);
58   if (result == 0) {
59     LocalFree(message);
60     return;
61   }
62   auto utf8_message =
63       fmt::detail::to_utf8<wchar_t>(wstring_view(message, result - 2));
64   LocalFree(message);
65   fmt::memory_buffer actual_message;
66   fmt::detail::format_windows_error(actual_message, provisioning_not_allowed,
67                                     "test");
68   EXPECT_EQ(fmt::format("test: {}", utf8_message.str()),
69             fmt::to_string(actual_message));
70 }
71 
TEST(os_test,windows_error)72 TEST(os_test, windows_error) {
73   auto error = std::system_error(std::error_code());
74   try {
75     throw fmt::windows_error(ERROR_FILE_EXISTS, "test {}", "error");
76   } catch (const std::system_error& e) {
77     error = e;
78   }
79   fmt::memory_buffer message;
80   fmt::detail::format_windows_error(message, ERROR_FILE_EXISTS, "test error");
81   EXPECT_THAT(error.what(), HasSubstr(to_string(message)));
82   EXPECT_EQ(ERROR_FILE_EXISTS, error.code().value());
83 }
84 
TEST(os_test,report_windows_error)85 TEST(os_test, report_windows_error) {
86   fmt::memory_buffer out;
87   fmt::detail::format_windows_error(out, ERROR_FILE_EXISTS, "test error");
88   out.push_back('\n');
89   EXPECT_WRITE(stderr,
90                fmt::report_windows_error(ERROR_FILE_EXISTS, "test error"),
91                fmt::to_string(out));
92 }
93 
94 #  if FMT_USE_FCNTL && !defined(__MINGW32__)
TEST(file_test,open_windows_file)95 TEST(file_test, open_windows_file) {
96   using fmt::file;
97   file out = file::open_windows_file(L"test-file",
98                                      file::WRONLY | file::CREATE | file::TRUNC);
99   out.write("x", 1);
100   file in = file::open_windows_file(L"test-file", file::RDONLY);
101   EXPECT_READ(in, "x");
102 }
103 #  endif  // FMT_USE_FCNTL && !defined(__MINGW32__)
104 
105 #endif  // _WIN32
106 
107 #if FMT_USE_FCNTL
108 
109 using fmt::file;
110 
isclosed(int fd)111 auto isclosed(int fd) -> bool {
112   char buffer;
113   auto result = std::streamsize();
114   SUPPRESS_ASSERT(result = FMT_POSIX(read(fd, &buffer, 1)));
115   return result == -1 && errno == EBADF;
116 }
117 
118 // Opens a file for reading.
open_file()119 auto open_file() -> file {
120   auto pipe = fmt::pipe();
121   pipe.write_end.write(file_content, std::strlen(file_content));
122   pipe.write_end.close();
123   return std::move(pipe.read_end);
124 }
125 
126 // Attempts to write a string to a file.
write(file & f,fmt::string_view s)127 void write(file& f, fmt::string_view s) {
128   size_t num_chars_left = s.size();
129   const char* ptr = s.data();
130   do {
131     size_t count = f.write(ptr, num_chars_left);
132     ptr += count;
133     // We can't write more than size_t bytes since num_chars_left
134     // has type size_t.
135     num_chars_left -= count;
136   } while (num_chars_left != 0);
137 }
138 
TEST(buffered_file_test,default_ctor)139 TEST(buffered_file_test, default_ctor) {
140   auto f = buffered_file();
141   EXPECT_TRUE(f.get() == nullptr);
142 }
143 
TEST(buffered_file_test,move_ctor)144 TEST(buffered_file_test, move_ctor) {
145   buffered_file bf = open_buffered_file();
146   FILE* fp = bf.get();
147   EXPECT_TRUE(fp != nullptr);
148   buffered_file bf2(std::move(bf));
149   EXPECT_EQ(fp, bf2.get());
150   EXPECT_TRUE(bf.get() == nullptr);
151 }
152 
TEST(buffered_file_test,move_assignment)153 TEST(buffered_file_test, move_assignment) {
154   buffered_file bf = open_buffered_file();
155   FILE* fp = bf.get();
156   EXPECT_TRUE(fp != nullptr);
157   buffered_file bf2;
158   bf2 = std::move(bf);
159   EXPECT_EQ(fp, bf2.get());
160   EXPECT_TRUE(bf.get() == nullptr);
161 }
162 
TEST(buffered_file_test,move_assignment_closes_file)163 TEST(buffered_file_test, move_assignment_closes_file) {
164   buffered_file bf = open_buffered_file();
165   buffered_file bf2 = open_buffered_file();
166   int old_fd = bf2.descriptor();
167   bf2 = std::move(bf);
168   EXPECT_TRUE(isclosed(old_fd));
169 }
170 
TEST(buffered_file_test,move_from_temporary_in_ctor)171 TEST(buffered_file_test, move_from_temporary_in_ctor) {
172   FILE* fp = nullptr;
173   buffered_file f = open_buffered_file(&fp);
174   EXPECT_EQ(fp, f.get());
175 }
176 
TEST(buffered_file_test,move_from_temporary_in_assignment)177 TEST(buffered_file_test, move_from_temporary_in_assignment) {
178   FILE* fp = nullptr;
179   auto f = buffered_file();
180   f = open_buffered_file(&fp);
181   EXPECT_EQ(fp, f.get());
182 }
183 
TEST(buffered_file_test,move_from_temporary_in_assignment_closes_file)184 TEST(buffered_file_test, move_from_temporary_in_assignment_closes_file) {
185   buffered_file f = open_buffered_file();
186   int old_fd = f.descriptor();
187   f = open_buffered_file();
188   EXPECT_TRUE(isclosed(old_fd));
189 }
190 
TEST(buffered_file_test,close_file_in_dtor)191 TEST(buffered_file_test, close_file_in_dtor) {
192   int fd = 0;
193   {
194     buffered_file f = open_buffered_file();
195     fd = f.descriptor();
196   }
197   EXPECT_TRUE(isclosed(fd));
198 }
199 
TEST(buffered_file_test,close_error_in_dtor)200 TEST(buffered_file_test, close_error_in_dtor) {
201   auto f =
202       std::unique_ptr<buffered_file>(new buffered_file(open_buffered_file()));
203   EXPECT_WRITE(
204       stderr,
205       {
206         // The close function must be called inside EXPECT_WRITE,
207         // otherwise the system may recycle closed file descriptor when
208         // redirecting the output in EXPECT_STDERR and the second close
209         // will break output redirection.
210         FMT_POSIX(close(f->descriptor()));
211         SUPPRESS_ASSERT(f.reset(nullptr));
212       },
213       system_error_message(EBADF, "cannot close file") + "\n");
214 }
215 
TEST(buffered_file_test,close)216 TEST(buffered_file_test, close) {
217   buffered_file f = open_buffered_file();
218   int fd = f.descriptor();
219   f.close();
220   EXPECT_TRUE(f.get() == nullptr);
221   EXPECT_TRUE(isclosed(fd));
222 }
223 
TEST(buffered_file_test,close_error)224 TEST(buffered_file_test, close_error) {
225   buffered_file f = open_buffered_file();
226   FMT_POSIX(close(f.descriptor()));
227   EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
228   EXPECT_TRUE(f.get() == nullptr);
229 }
230 
TEST(buffered_file_test,descriptor)231 TEST(buffered_file_test, descriptor) {
232   auto f = open_buffered_file();
233   EXPECT_TRUE(f.descriptor() != -1);
234   file copy = file::dup(f.descriptor());
235   EXPECT_READ(copy, file_content);
236 }
237 
TEST(ostream_test,move)238 TEST(ostream_test, move) {
239   auto test_file = uniq_file_name(__LINE__);
240   fmt::ostream out = fmt::output_file(test_file);
241   fmt::ostream moved(std::move(out));
242   moved.print("hello");
243 }
244 
TEST(ostream_test,move_while_holding_data)245 TEST(ostream_test, move_while_holding_data) {
246   auto test_file = uniq_file_name(__LINE__);
247   {
248     fmt::ostream out = fmt::output_file(test_file);
249     out.print("Hello, ");
250     fmt::ostream moved(std::move(out));
251     moved.print("world!\n");
252   }
253   {
254     file in(test_file, file::RDONLY);
255     EXPECT_READ(in, "Hello, world!\n");
256   }
257 }
258 
TEST(ostream_test,print)259 TEST(ostream_test, print) {
260   auto test_file = uniq_file_name(__LINE__);
261   fmt::ostream out = fmt::output_file(test_file);
262   out.print("The answer is {}.\n", 42);
263   out.close();
264   file in(test_file, file::RDONLY);
265   EXPECT_READ(in, "The answer is 42.\n");
266 }
267 
TEST(ostream_test,buffer_boundary)268 TEST(ostream_test, buffer_boundary) {
269   auto str = std::string(4096, 'x');
270   auto test_file = uniq_file_name(__LINE__);
271   fmt::ostream out = fmt::output_file(test_file);
272   out.print("{}", str);
273   out.print("{}", str);
274   out.close();
275   file in(test_file, file::RDONLY);
276   EXPECT_READ(in, str + str);
277 }
278 
TEST(ostream_test,buffer_size)279 TEST(ostream_test, buffer_size) {
280   auto test_file = uniq_file_name(__LINE__);
281   fmt::ostream out = fmt::output_file(test_file, fmt::buffer_size = 1);
282   out.print("{}", "foo");
283   out.close();
284   file in(test_file, file::RDONLY);
285   EXPECT_READ(in, "foo");
286 }
287 
TEST(ostream_test,truncate)288 TEST(ostream_test, truncate) {
289   auto test_file = uniq_file_name(__LINE__);
290   {
291     fmt::ostream out = fmt::output_file(test_file);
292     out.print("0123456789");
293   }
294   {
295     fmt::ostream out = fmt::output_file(test_file);
296     out.print("foo");
297   }
298   file in(test_file, file::RDONLY);
299   EXPECT_EQ("foo", read(in, 4));
300 }
301 
TEST(ostream_test,flush)302 TEST(ostream_test, flush) {
303   auto test_file = uniq_file_name(__LINE__);
304   auto out = fmt::output_file(test_file);
305   out.print("x");
306   out.flush();
307   auto in = fmt::file(test_file, file::RDONLY);
308   EXPECT_READ(in, "x");
309 }
310 
TEST(file_test,default_ctor)311 TEST(file_test, default_ctor) {
312   file f;
313   EXPECT_EQ(-1, f.descriptor());
314 }
315 
TEST(file_test,open_buffered_file_in_ctor)316 TEST(file_test, open_buffered_file_in_ctor) {
317   auto test_file = uniq_file_name(__LINE__);
318   FILE* fp = safe_fopen(test_file.c_str(), "w");
319   std::fputs(file_content, fp);
320   std::fclose(fp);
321   file f(test_file.c_str(), file::RDONLY);
322   // Check if the file is open by reading one character from it.
323   char buffer;
324   bool isopen = FMT_POSIX(read(f.descriptor(), &buffer, 1)) == 1;
325   ASSERT_TRUE(isopen);
326 }
327 
TEST(file_test,open_buffered_file_error)328 TEST(file_test, open_buffered_file_error) {
329   EXPECT_SYSTEM_ERROR(file("nonexistent", file::RDONLY), ENOENT,
330                       "cannot open file nonexistent");
331 }
332 
TEST(file_test,move_ctor)333 TEST(file_test, move_ctor) {
334   file f = open_file();
335   int fd = f.descriptor();
336   EXPECT_NE(-1, fd);
337   file f2(std::move(f));
338   EXPECT_EQ(fd, f2.descriptor());
339   EXPECT_EQ(-1, f.descriptor());
340 }
341 
TEST(file_test,move_assignment)342 TEST(file_test, move_assignment) {
343   file f = open_file();
344   int fd = f.descriptor();
345   EXPECT_NE(-1, fd);
346   file f2;
347   f2 = std::move(f);
348   EXPECT_EQ(fd, f2.descriptor());
349   EXPECT_EQ(-1, f.descriptor());
350 }
351 
TEST(file_test,move_assignment_closes_file)352 TEST(file_test, move_assignment_closes_file) {
353   file f = open_file();
354   file f2 = open_file();
355   int old_fd = f2.descriptor();
356   f2 = std::move(f);
357   EXPECT_TRUE(isclosed(old_fd));
358 }
359 
open_buffered_file(int & fd)360 file open_buffered_file(int& fd) {
361   file f = open_file();
362   fd = f.descriptor();
363   return f;
364 }
365 
TEST(file_test,move_from_temporary_in_ctor)366 TEST(file_test, move_from_temporary_in_ctor) {
367   int fd = 0xdead;
368   file f(open_buffered_file(fd));
369   EXPECT_EQ(fd, f.descriptor());
370 }
371 
TEST(file_test,move_from_temporary_in_assignment)372 TEST(file_test, move_from_temporary_in_assignment) {
373   int fd = 0xdead;
374   file f;
375   f = open_buffered_file(fd);
376   EXPECT_EQ(fd, f.descriptor());
377 }
378 
TEST(file_test,move_from_temporary_in_assignment_closes_file)379 TEST(file_test, move_from_temporary_in_assignment_closes_file) {
380   int fd = 0xdead;
381   file f = open_file();
382   int old_fd = f.descriptor();
383   f = open_buffered_file(fd);
384   EXPECT_TRUE(isclosed(old_fd));
385 }
386 
TEST(file_test,close_file_in_dtor)387 TEST(file_test, close_file_in_dtor) {
388   int fd = 0;
389   {
390     file f = open_file();
391     fd = f.descriptor();
392   }
393   EXPECT_TRUE(isclosed(fd));
394 }
395 
TEST(file_test,close_error_in_dtor)396 TEST(file_test, close_error_in_dtor) {
397   std::unique_ptr<file> f(new file(open_file()));
398   EXPECT_WRITE(
399       stderr,
400       {
401         // The close function must be called inside EXPECT_WRITE,
402         // otherwise the system may recycle closed file descriptor when
403         // redirecting the output in EXPECT_STDERR and the second close
404         // will break output redirection.
405         FMT_POSIX(close(f->descriptor()));
406         SUPPRESS_ASSERT(f.reset(nullptr));
407       },
408       system_error_message(EBADF, "cannot close file") + "\n");
409 }
410 
TEST(file_test,close)411 TEST(file_test, close) {
412   file f = open_file();
413   int fd = f.descriptor();
414   f.close();
415   EXPECT_EQ(-1, f.descriptor());
416   EXPECT_TRUE(isclosed(fd));
417 }
418 
TEST(file_test,close_error)419 TEST(file_test, close_error) {
420   file f = open_file();
421   FMT_POSIX(close(f.descriptor()));
422   EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
423   EXPECT_EQ(-1, f.descriptor());
424 }
425 
TEST(file_test,read)426 TEST(file_test, read) {
427   file f = open_file();
428   EXPECT_READ(f, file_content);
429 }
430 
TEST(file_test,read_error)431 TEST(file_test, read_error) {
432   auto test_file = uniq_file_name(__LINE__);
433   file f(test_file, file::WRONLY | file::CREATE);
434   char buf;
435   // We intentionally read from a file opened in the write-only mode to
436   // cause error.
437   EXPECT_SYSTEM_ERROR(f.read(&buf, 1), EBADF, "cannot read from file");
438 }
439 
TEST(file_test,write)440 TEST(file_test, write) {
441   auto pipe = fmt::pipe();
442   auto test_file = uniq_file_name(__LINE__);
443   write(pipe.write_end, test_file);
444   pipe.write_end.close();
445   EXPECT_READ(pipe.read_end, test_file);
446 }
447 
TEST(file_test,write_error)448 TEST(file_test, write_error) {
449   auto test_file = uniq_file_name(__LINE__);
450   file f(test_file, file::RDONLY | file::CREATE);
451   // We intentionally write to a file opened in the read-only mode to
452   // cause error.
453   EXPECT_SYSTEM_ERROR(f.write(" ", 1), EBADF, "cannot write to file");
454 }
455 
TEST(file_test,dup)456 TEST(file_test, dup) {
457   file f = open_file();
458   file copy = file::dup(f.descriptor());
459   EXPECT_NE(f.descriptor(), copy.descriptor());
460   EXPECT_EQ(file_content, read(copy, std::strlen(file_content)));
461 }
462 
463 #  ifndef __COVERITY__
TEST(file_test,dup_error)464 TEST(file_test, dup_error) {
465   int value = -1;
466   EXPECT_SYSTEM_ERROR_NOASSERT(file::dup(value), EBADF,
467                                "cannot duplicate file descriptor -1");
468 }
469 #  endif
470 
TEST(file_test,dup2)471 TEST(file_test, dup2) {
472   file f = open_file();
473   file copy = open_file();
474   f.dup2(copy.descriptor());
475   EXPECT_NE(f.descriptor(), copy.descriptor());
476   EXPECT_READ(copy, file_content);
477 }
478 
TEST(file_test,dup2_error)479 TEST(file_test, dup2_error) {
480   file f = open_file();
481   EXPECT_SYSTEM_ERROR_NOASSERT(
482       f.dup2(-1), EBADF,
483       fmt::format("cannot duplicate file descriptor {} to -1", f.descriptor()));
484 }
485 
TEST(file_test,dup2_noexcept)486 TEST(file_test, dup2_noexcept) {
487   file f = open_file();
488   file copy = open_file();
489   std::error_code ec;
490   f.dup2(copy.descriptor(), ec);
491   EXPECT_EQ(ec.value(), 0);
492   EXPECT_NE(f.descriptor(), copy.descriptor());
493   EXPECT_READ(copy, file_content);
494 }
495 
TEST(file_test,dup2_noexcept_error)496 TEST(file_test, dup2_noexcept_error) {
497   file f = open_file();
498   std::error_code ec;
499   SUPPRESS_ASSERT(f.dup2(-1, ec));
500   EXPECT_EQ(EBADF, ec.value());
501 }
502 
TEST(file_test,pipe)503 TEST(file_test, pipe) {
504   auto pipe = fmt::pipe();
505   EXPECT_NE(-1, pipe.read_end.descriptor());
506   EXPECT_NE(-1, pipe.write_end.descriptor());
507   write(pipe.write_end, "test");
508   EXPECT_READ(pipe.read_end, "test");
509 }
510 
TEST(file_test,fdopen)511 TEST(file_test, fdopen) {
512   auto pipe = fmt::pipe();
513   int read_fd = pipe.read_end.descriptor();
514   EXPECT_EQ(read_fd, FMT_POSIX(fileno(pipe.read_end.fdopen("r").get())));
515 }
516 #endif  // FMT_USE_FCNTL
517