1 // Formatting library for C++ - tests of the OS-specific functionality
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
6 // For the license information refer to format.h.
10 #include <cstdlib> // std::exit
14 #include "gtest-extra.h"
17 using fmt::buffered_file
;
18 using testing::HasSubstr
;
19 using wstring_view
= fmt::basic_string_view
<wchar_t>;
25 TEST(util_test
, utf16_to_utf8
) {
26 auto s
= std::string("ёжик");
27 fmt::detail::utf16_to_utf8
u(L
"\x0451\x0436\x0438\x043A");
28 EXPECT_EQ(s
, u
.str());
29 EXPECT_EQ(s
.size(), u
.size());
32 TEST(util_test
, utf16_to_utf8_empty_string
) {
34 fmt::detail::utf16_to_utf8
u(L
"");
35 EXPECT_EQ(s
, u
.str());
36 EXPECT_EQ(s
.size(), u
.size());
39 template <typename Converter
, typename Char
>
40 void check_utf_conversion_error(const char* message
,
41 fmt::basic_string_view
<Char
> str
=
42 fmt::basic_string_view
<Char
>(nullptr, 1)) {
43 fmt::memory_buffer out
;
44 fmt::detail::format_windows_error(out
, ERROR_INVALID_PARAMETER
, message
);
45 auto error
= std::system_error(std::error_code());
48 } catch (const std::system_error
& e
) {
51 EXPECT_EQ(ERROR_INVALID_PARAMETER
, error
.code().value());
52 EXPECT_THAT(error
.what(), HasSubstr(fmt::to_string(out
)));
55 TEST(util_test
, utf16_to_utf8_error
) {
56 check_utf_conversion_error
<fmt::detail::utf16_to_utf8
, wchar_t>(
57 "cannot convert string from UTF-16 to UTF-8");
60 TEST(util_test
, utf16_to_utf8_convert
) {
61 fmt::detail::utf16_to_utf8 u
;
62 EXPECT_EQ(ERROR_INVALID_PARAMETER
, u
.convert(wstring_view(nullptr, 1)));
63 EXPECT_EQ(ERROR_INVALID_PARAMETER
,
64 u
.convert(wstring_view(L
"foo", INT_MAX
+ 1u)));
67 TEST(os_test
, format_std_error_code
) {
68 EXPECT_EQ("generic:42",
69 fmt::format(FMT_STRING("{0}"),
70 std::error_code(42, std::generic_category())));
71 EXPECT_EQ("system:42",
72 fmt::format(FMT_STRING("{0}"),
73 std::error_code(42, fmt::system_category())));
74 EXPECT_EQ("system:-42",
75 fmt::format(FMT_STRING("{0}"),
76 std::error_code(-42, fmt::system_category())));
79 TEST(os_test
, format_windows_error
) {
80 LPWSTR message
= nullptr;
81 auto result
= FormatMessageW(
82 FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
|
83 FORMAT_MESSAGE_IGNORE_INSERTS
,
84 nullptr, ERROR_FILE_EXISTS
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
85 reinterpret_cast<LPWSTR
>(&message
), 0, nullptr);
86 fmt::detail::utf16_to_utf8
utf8_message(wstring_view(message
, result
- 2));
88 fmt::memory_buffer actual_message
;
89 fmt::detail::format_windows_error(actual_message
, ERROR_FILE_EXISTS
, "test");
90 EXPECT_EQ(fmt::format("test: {}", utf8_message
.str()),
91 fmt::to_string(actual_message
));
92 actual_message
.resize(0);
95 TEST(os_test
, format_long_windows_error
) {
96 LPWSTR message
= nullptr;
97 // this error code is not available on all Windows platforms and
98 // Windows SDKs, so do not fail the test if the error string cannot
100 int provisioning_not_allowed
= 0x80284013L
; // TBS_E_PROVISIONING_NOT_ALLOWED
101 auto result
= FormatMessageW(
102 FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
|
103 FORMAT_MESSAGE_IGNORE_INSERTS
,
104 nullptr, static_cast<DWORD
>(provisioning_not_allowed
),
105 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
106 reinterpret_cast<LPWSTR
>(&message
), 0, nullptr);
111 fmt::detail::utf16_to_utf8
utf8_message(wstring_view(message
, result
- 2));
113 fmt::memory_buffer actual_message
;
114 fmt::detail::format_windows_error(actual_message
, provisioning_not_allowed
,
116 EXPECT_EQ(fmt::format("test: {}", utf8_message
.str()),
117 fmt::to_string(actual_message
));
120 TEST(os_test
, windows_error
) {
121 auto error
= std::system_error(std::error_code());
123 throw fmt::windows_error(ERROR_FILE_EXISTS
, "test {}", "error");
124 } catch (const std::system_error
& e
) {
127 fmt::memory_buffer message
;
128 fmt::detail::format_windows_error(message
, ERROR_FILE_EXISTS
, "test error");
129 EXPECT_THAT(error
.what(), HasSubstr(to_string(message
)));
130 EXPECT_EQ(ERROR_FILE_EXISTS
, error
.code().value());
133 TEST(os_test
, report_windows_error
) {
134 fmt::memory_buffer out
;
135 fmt::detail::format_windows_error(out
, ERROR_FILE_EXISTS
, "test error");
138 fmt::report_windows_error(ERROR_FILE_EXISTS
, "test error"),
139 fmt::to_string(out
));
148 bool isclosed(int fd
) {
150 auto result
= std::streamsize();
151 SUPPRESS_ASSERT(result
= FMT_POSIX(read(fd
, &buffer
, 1)));
152 return result
== -1 && errno
== EBADF
;
155 // Opens a file for reading.
157 file read_end
, write_end
;
158 file::pipe(read_end
, write_end
);
159 write_end
.write(file_content
, std::strlen(file_content
));
164 // Attempts to write a string to a file.
165 void write(file
& f
, fmt::string_view s
) {
166 size_t num_chars_left
= s
.size();
167 const char* ptr
= s
.data();
169 size_t count
= f
.write(ptr
, num_chars_left
);
171 // We can't write more than size_t bytes since num_chars_left
173 num_chars_left
-= count
;
174 } while (num_chars_left
!= 0);
177 TEST(buffered_file_test
, default_ctor
) {
178 auto f
= buffered_file();
179 EXPECT_TRUE(f
.get() == nullptr);
182 TEST(buffered_file_test
, move_ctor
) {
183 buffered_file bf
= open_buffered_file();
185 EXPECT_TRUE(fp
!= nullptr);
186 buffered_file
bf2(std::move(bf
));
187 EXPECT_EQ(fp
, bf2
.get());
188 EXPECT_TRUE(bf
.get() == nullptr);
191 TEST(buffered_file_test
, move_assignment
) {
192 buffered_file bf
= open_buffered_file();
194 EXPECT_TRUE(fp
!= nullptr);
197 EXPECT_EQ(fp
, bf2
.get());
198 EXPECT_TRUE(bf
.get() == nullptr);
201 TEST(buffered_file_test
, move_assignment_closes_file
) {
202 buffered_file bf
= open_buffered_file();
203 buffered_file bf2
= open_buffered_file();
204 int old_fd
= bf2
.descriptor();
206 EXPECT_TRUE(isclosed(old_fd
));
209 TEST(buffered_file_test
, move_from_temporary_in_ctor
) {
211 buffered_file f
= open_buffered_file(&fp
);
212 EXPECT_EQ(fp
, f
.get());
215 TEST(buffered_file_test
, move_from_temporary_in_assignment
) {
217 auto f
= buffered_file();
218 f
= open_buffered_file(&fp
);
219 EXPECT_EQ(fp
, f
.get());
222 TEST(buffered_file_test
, move_from_temporary_in_assignment_closes_file
) {
223 buffered_file f
= open_buffered_file();
224 int old_fd
= f
.descriptor();
225 f
= open_buffered_file();
226 EXPECT_TRUE(isclosed(old_fd
));
229 TEST(buffered_file_test
, close_file_in_dtor
) {
232 buffered_file f
= open_buffered_file();
235 EXPECT_TRUE(isclosed(fd
));
238 TEST(buffered_file_test
, close_error_in_dtor
) {
240 std::unique_ptr
<buffered_file
>(new buffered_file(open_buffered_file()));
244 // The close function must be called inside EXPECT_WRITE,
245 // otherwise the system may recycle closed file descriptor when
246 // redirecting the output in EXPECT_STDERR and the second close
247 // will break output redirection.
248 FMT_POSIX(close(f
->descriptor()));
249 SUPPRESS_ASSERT(f
.reset(nullptr));
251 system_error_message(EBADF
, "cannot close file") + "\n");
254 TEST(buffered_file_test
, close
) {
255 buffered_file f
= open_buffered_file();
256 int fd
= f
.descriptor();
258 EXPECT_TRUE(f
.get() == nullptr);
259 EXPECT_TRUE(isclosed(fd
));
262 TEST(buffered_file_test
, close_error
) {
263 buffered_file f
= open_buffered_file();
264 FMT_POSIX(close(f
.descriptor()));
265 EXPECT_SYSTEM_ERROR_NOASSERT(f
.close(), EBADF
, "cannot close file");
266 EXPECT_TRUE(f
.get() == nullptr);
269 TEST(buffered_file_test
, descriptor
) {
270 auto f
= open_buffered_file();
271 EXPECT_TRUE(f
.descriptor() != -1);
272 file copy
= file::dup(f
.descriptor());
273 EXPECT_READ(copy
, file_content
);
276 TEST(ostream_test
, move
) {
277 fmt::ostream out
= fmt::output_file("test-file");
278 fmt::ostream
moved(std::move(out
));
279 moved
.print("hello");
282 TEST(ostream_test
, move_while_holding_data
) {
284 fmt::ostream out
= fmt::output_file("test-file");
285 out
.print("Hello, ");
286 fmt::ostream
moved(std::move(out
));
287 moved
.print("world!\n");
290 file
in("test-file", file::RDONLY
);
291 EXPECT_READ(in
, "Hello, world!\n");
295 TEST(ostream_test
, print
) {
296 fmt::ostream out
= fmt::output_file("test-file");
297 out
.print("The answer is {}.\n",
298 fmt::join(std::initializer_list
<int>{42}, ", "));
300 file
in("test-file", file::RDONLY
);
301 EXPECT_READ(in
, "The answer is 42.\n");
304 TEST(ostream_test
, buffer_boundary
) {
305 auto str
= std::string(4096, 'x');
306 fmt::ostream out
= fmt::output_file("test-file");
307 out
.print("{}", str
);
308 out
.print("{}", str
);
310 file
in("test-file", file::RDONLY
);
311 EXPECT_READ(in
, str
+ str
);
314 TEST(ostream_test
, buffer_size
) {
315 fmt::ostream out
= fmt::output_file("test-file", fmt::buffer_size
= 1);
316 out
.print("{}", "foo");
318 file
in("test-file", file::RDONLY
);
319 EXPECT_READ(in
, "foo");
322 TEST(ostream_test
, truncate
) {
324 fmt::ostream out
= fmt::output_file("test-file");
325 out
.print("0123456789");
328 fmt::ostream out
= fmt::output_file("test-file");
331 file
in("test-file", file::RDONLY
);
332 EXPECT_EQ("foo", read(in
, 4));
335 TEST(ostream_test
, flush
) {
336 auto out
= fmt::output_file("test-file");
339 auto in
= fmt::file("test-file", file::RDONLY
);
340 EXPECT_READ(in
, "x");
343 TEST(file_test
, default_ctor
) {
345 EXPECT_EQ(-1, f
.descriptor());
348 TEST(file_test
, open_buffered_file_in_ctor
) {
349 FILE* fp
= safe_fopen("test-file", "w");
350 std::fputs(file_content
, fp
);
352 file
f("test-file", file::RDONLY
);
353 // Check if the file is open by reading one character from it.
355 bool isopen
= FMT_POSIX(read(f
.descriptor(), &buffer
, 1)) == 1;
359 TEST(file_test
, open_buffered_file_error
) {
360 EXPECT_SYSTEM_ERROR(file("nonexistent", file::RDONLY
), ENOENT
,
361 "cannot open file nonexistent");
364 TEST(file_test
, move_ctor
) {
365 file f
= open_file();
366 int fd
= f
.descriptor();
368 file
f2(std::move(f
));
369 EXPECT_EQ(fd
, f2
.descriptor());
370 EXPECT_EQ(-1, f
.descriptor());
373 TEST(file_test
, move_assignment
) {
374 file f
= open_file();
375 int fd
= f
.descriptor();
379 EXPECT_EQ(fd
, f2
.descriptor());
380 EXPECT_EQ(-1, f
.descriptor());
383 TEST(file_test
, move_assignment_closes_file
) {
384 file f
= open_file();
385 file f2
= open_file();
386 int old_fd
= f2
.descriptor();
388 EXPECT_TRUE(isclosed(old_fd
));
391 file
open_buffered_file(int& fd
) {
392 file f
= open_file();
397 TEST(file_test
, move_from_temporary_in_ctor
) {
399 file
f(open_buffered_file(fd
));
400 EXPECT_EQ(fd
, f
.descriptor());
403 TEST(file_test
, move_from_temporary_in_assignment
) {
406 f
= open_buffered_file(fd
);
407 EXPECT_EQ(fd
, f
.descriptor());
410 TEST(file_test
, move_from_temporary_in_assignment_closes_file
) {
412 file f
= open_file();
413 int old_fd
= f
.descriptor();
414 f
= open_buffered_file(fd
);
415 EXPECT_TRUE(isclosed(old_fd
));
418 TEST(file_test
, close_file_in_dtor
) {
421 file f
= open_file();
424 EXPECT_TRUE(isclosed(fd
));
427 TEST(file_test
, close_error_in_dtor
) {
428 std::unique_ptr
<file
> f(new file(open_file()));
432 // The close function must be called inside EXPECT_WRITE,
433 // otherwise the system may recycle closed file descriptor when
434 // redirecting the output in EXPECT_STDERR and the second close
435 // will break output redirection.
436 FMT_POSIX(close(f
->descriptor()));
437 SUPPRESS_ASSERT(f
.reset(nullptr));
439 system_error_message(EBADF
, "cannot close file") + "\n");
442 TEST(file_test
, close
) {
443 file f
= open_file();
444 int fd
= f
.descriptor();
446 EXPECT_EQ(-1, f
.descriptor());
447 EXPECT_TRUE(isclosed(fd
));
450 TEST(file_test
, close_error
) {
451 file f
= open_file();
452 FMT_POSIX(close(f
.descriptor()));
453 EXPECT_SYSTEM_ERROR_NOASSERT(f
.close(), EBADF
, "cannot close file");
454 EXPECT_EQ(-1, f
.descriptor());
457 TEST(file_test
, read
) {
458 file f
= open_file();
459 EXPECT_READ(f
, file_content
);
462 TEST(file_test
, read_error
) {
463 file
f("test-file", file::WRONLY
);
465 // We intentionally read from a file opened in the write-only mode to
467 EXPECT_SYSTEM_ERROR(f
.read(&buf
, 1), EBADF
, "cannot read from file");
470 TEST(file_test
, write
) {
471 file read_end
, write_end
;
472 file::pipe(read_end
, write_end
);
473 write(write_end
, "test");
475 EXPECT_READ(read_end
, "test");
478 TEST(file_test
, write_error
) {
479 file
f("test-file", file::RDONLY
);
480 // We intentionally write to a file opened in the read-only mode to
482 EXPECT_SYSTEM_ERROR(f
.write(" ", 1), EBADF
, "cannot write to file");
485 TEST(file_test
, dup
) {
486 file f
= open_file();
487 file copy
= file::dup(f
.descriptor());
488 EXPECT_NE(f
.descriptor(), copy
.descriptor());
489 EXPECT_EQ(file_content
, read(copy
, std::strlen(file_content
)));
492 # ifndef __COVERITY__
493 TEST(file_test
, dup_error
) {
495 EXPECT_SYSTEM_ERROR_NOASSERT(file::dup(value
), EBADF
,
496 "cannot duplicate file descriptor -1");
500 TEST(file_test
, dup2
) {
501 file f
= open_file();
502 file copy
= open_file();
503 f
.dup2(copy
.descriptor());
504 EXPECT_NE(f
.descriptor(), copy
.descriptor());
505 EXPECT_READ(copy
, file_content
);
508 TEST(file_test
, dup2_error
) {
509 file f
= open_file();
510 EXPECT_SYSTEM_ERROR_NOASSERT(
512 fmt::format("cannot duplicate file descriptor {} to -1", f
.descriptor()));
515 TEST(file_test
, dup2_noexcept
) {
516 file f
= open_file();
517 file copy
= open_file();
519 f
.dup2(copy
.descriptor(), ec
);
520 EXPECT_EQ(ec
.value(), 0);
521 EXPECT_NE(f
.descriptor(), copy
.descriptor());
522 EXPECT_READ(copy
, file_content
);
525 TEST(file_test
, dup2_noexcept_error
) {
526 file f
= open_file();
528 SUPPRESS_ASSERT(f
.dup2(-1, ec
));
529 EXPECT_EQ(EBADF
, ec
.value());
532 TEST(file_test
, pipe
) {
533 file read_end
, write_end
;
534 file::pipe(read_end
, write_end
);
535 EXPECT_NE(-1, read_end
.descriptor());
536 EXPECT_NE(-1, write_end
.descriptor());
537 write(write_end
, "test");
538 EXPECT_READ(read_end
, "test");
541 TEST(file_test
, fdopen
) {
542 file read_end
, write_end
;
543 file::pipe(read_end
, write_end
);
544 int read_fd
= read_end
.descriptor();
545 EXPECT_EQ(read_fd
, FMT_POSIX(fileno(read_end
.fdopen("r").get())));
547 #endif // FMT_USE_FCNTL