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"
21 using fmt::buffered_file
;
22 using testing::HasSubstr
;
23 using wstring_view
= fmt::basic_string_view
<wchar_t>;
29 TEST(util_test
, utf16_to_utf8
) {
30 auto s
= std::string("ёжик");
31 fmt::detail::utf16_to_utf8
u(L
"\x0451\x0436\x0438\x043A");
32 EXPECT_EQ(s
, u
.str());
33 EXPECT_EQ(s
.size(), u
.size());
36 TEST(util_test
, utf16_to_utf8_empty_string
) {
38 fmt::detail::utf16_to_utf8
u(L
"");
39 EXPECT_EQ(s
, u
.str());
40 EXPECT_EQ(s
.size(), u
.size());
43 template <typename Converter
, typename Char
>
44 void check_utf_conversion_error(
46 fmt::basic_string_view
<Char
> str
= fmt::basic_string_view
<Char
>(0, 1)) {
47 fmt::memory_buffer out
;
48 fmt::detail::format_windows_error(out
, ERROR_INVALID_PARAMETER
, message
);
49 auto error
= std::system_error(std::error_code());
52 } catch (const std::system_error
& e
) {
55 EXPECT_EQ(ERROR_INVALID_PARAMETER
, error
.code().value());
56 EXPECT_THAT(error
.what(), HasSubstr(fmt::to_string(out
)));
59 TEST(util_test
, utf16_to_utf8_error
) {
60 check_utf_conversion_error
<fmt::detail::utf16_to_utf8
, wchar_t>(
61 "cannot convert string from UTF-16 to UTF-8");
64 TEST(util_test
, utf16_to_utf8_convert
) {
65 fmt::detail::utf16_to_utf8 u
;
66 EXPECT_EQ(ERROR_INVALID_PARAMETER
, u
.convert(wstring_view(0, 1)));
67 EXPECT_EQ(ERROR_INVALID_PARAMETER
,
68 u
.convert(wstring_view(L
"foo", INT_MAX
+ 1u)));
71 TEST(os_test
, format_std_error_code
) {
72 EXPECT_EQ("generic:42",
73 fmt::format(FMT_STRING("{0}"),
74 std::error_code(42, std::generic_category())));
75 EXPECT_EQ("system:42",
76 fmt::format(FMT_STRING("{0}"),
77 std::error_code(42, fmt::system_category())));
78 EXPECT_EQ("system:-42",
79 fmt::format(FMT_STRING("{0}"),
80 std::error_code(-42, fmt::system_category())));
83 TEST(os_test
, format_windows_error
) {
85 auto result
= FormatMessageW(
86 FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
|
87 FORMAT_MESSAGE_IGNORE_INSERTS
,
88 0, ERROR_FILE_EXISTS
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
89 reinterpret_cast<LPWSTR
>(&message
), 0, 0);
90 fmt::detail::utf16_to_utf8
utf8_message(wstring_view(message
, result
- 2));
92 fmt::memory_buffer actual_message
;
93 fmt::detail::format_windows_error(actual_message
, ERROR_FILE_EXISTS
, "test");
94 EXPECT_EQ(fmt::format("test: {}", utf8_message
.str()),
95 fmt::to_string(actual_message
));
96 actual_message
.resize(0);
99 TEST(os_test
, format_long_windows_error
) {
101 // this error code is not available on all Windows platforms and
102 // Windows SDKs, so do not fail the test if the error string cannot
104 int provisioning_not_allowed
= 0x80284013L
; // TBS_E_PROVISIONING_NOT_ALLOWED
105 auto result
= FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
106 FORMAT_MESSAGE_FROM_SYSTEM
|
107 FORMAT_MESSAGE_IGNORE_INSERTS
,
108 0, static_cast<DWORD
>(provisioning_not_allowed
),
109 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
110 reinterpret_cast<LPWSTR
>(&message
), 0, 0);
115 fmt::detail::utf16_to_utf8
utf8_message(wstring_view(message
, result
- 2));
117 fmt::memory_buffer actual_message
;
118 fmt::detail::format_windows_error(actual_message
, provisioning_not_allowed
,
120 EXPECT_EQ(fmt::format("test: {}", utf8_message
.str()),
121 fmt::to_string(actual_message
));
124 TEST(os_test
, windows_error
) {
125 auto error
= std::system_error(std::error_code());
127 throw fmt::windows_error(ERROR_FILE_EXISTS
, "test {}", "error");
128 } catch (const std::system_error
& e
) {
131 fmt::memory_buffer message
;
132 fmt::detail::format_windows_error(message
, ERROR_FILE_EXISTS
, "test error");
133 EXPECT_THAT(error
.what(), HasSubstr(to_string(message
)));
134 EXPECT_EQ(ERROR_FILE_EXISTS
, error
.code().value());
137 TEST(os_test
, report_windows_error
) {
138 fmt::memory_buffer out
;
139 fmt::detail::format_windows_error(out
, ERROR_FILE_EXISTS
, "test error");
142 fmt::report_windows_error(ERROR_FILE_EXISTS
, "test error"),
143 fmt::to_string(out
));
152 bool isclosed(int fd
) {
154 auto result
= std::streamsize();
155 SUPPRESS_ASSERT(result
= FMT_POSIX(read(fd
, &buffer
, 1)));
156 return result
== -1 && errno
== EBADF
;
159 // Opens a file for reading.
161 file read_end
, write_end
;
162 file::pipe(read_end
, write_end
);
163 write_end
.write(file_content
, std::strlen(file_content
));
168 // Attempts to write a string to a file.
169 void write(file
& f
, fmt::string_view s
) {
170 size_t num_chars_left
= s
.size();
171 const char* ptr
= s
.data();
173 size_t count
= f
.write(ptr
, num_chars_left
);
175 // We can't write more than size_t bytes since num_chars_left
177 num_chars_left
-= count
;
178 } while (num_chars_left
!= 0);
181 TEST(buffered_file_test
, default_ctor
) {
182 auto f
= buffered_file();
183 EXPECT_TRUE(f
.get() == nullptr);
186 TEST(buffered_file_test
, move_ctor
) {
187 buffered_file bf
= open_buffered_file();
189 EXPECT_TRUE(fp
!= nullptr);
190 buffered_file
bf2(std::move(bf
));
191 EXPECT_EQ(fp
, bf2
.get());
192 EXPECT_TRUE(bf
.get() == nullptr);
195 TEST(buffered_file_test
, move_assignment
) {
196 buffered_file bf
= open_buffered_file();
198 EXPECT_TRUE(fp
!= nullptr);
201 EXPECT_EQ(fp
, bf2
.get());
202 EXPECT_TRUE(bf
.get() == nullptr);
205 TEST(buffered_file_test
, move_assignment_closes_file
) {
206 buffered_file bf
= open_buffered_file();
207 buffered_file bf2
= open_buffered_file();
208 int old_fd
= bf2
.fileno();
210 EXPECT_TRUE(isclosed(old_fd
));
213 TEST(buffered_file_test
, move_from_temporary_in_ctor
) {
215 buffered_file f
= open_buffered_file(&fp
);
216 EXPECT_EQ(fp
, f
.get());
219 TEST(buffered_file_test
, move_from_temporary_in_assignment
) {
221 auto f
= buffered_file();
222 f
= open_buffered_file(&fp
);
223 EXPECT_EQ(fp
, f
.get());
226 TEST(buffered_file_test
, move_from_temporary_in_assignment_closes_file
) {
227 buffered_file f
= open_buffered_file();
228 int old_fd
= f
.fileno();
229 f
= open_buffered_file();
230 EXPECT_TRUE(isclosed(old_fd
));
233 TEST(buffered_file_test
, close_file_in_dtor
) {
236 buffered_file f
= open_buffered_file();
239 EXPECT_TRUE(isclosed(fd
));
242 TEST(buffered_file_test
, close_error_in_dtor
) {
244 std::unique_ptr
<buffered_file
>(new buffered_file(open_buffered_file()));
248 // The close function must be called inside EXPECT_WRITE,
249 // otherwise the system may recycle closed file descriptor when
250 // redirecting the output in EXPECT_STDERR and the second close
251 // will break output redirection.
252 FMT_POSIX(close(f
->fileno()));
253 SUPPRESS_ASSERT(f
.reset(nullptr));
255 system_error_message(EBADF
, "cannot close file") + "\n");
258 TEST(buffered_file_test
, close
) {
259 buffered_file f
= open_buffered_file();
262 EXPECT_TRUE(f
.get() == nullptr);
263 EXPECT_TRUE(isclosed(fd
));
266 TEST(buffered_file_test
, close_error
) {
267 buffered_file f
= open_buffered_file();
268 FMT_POSIX(close(f
.fileno()));
269 EXPECT_SYSTEM_ERROR_NOASSERT(f
.close(), EBADF
, "cannot close file");
270 EXPECT_TRUE(f
.get() == nullptr);
273 TEST(buffered_file_test
, fileno
) {
274 auto f
= open_buffered_file();
275 EXPECT_TRUE(f
.fileno() != -1);
276 file copy
= file::dup(f
.fileno());
277 EXPECT_READ(copy
, file_content
);
280 TEST(ostream_test
, move
) {
281 fmt::ostream out
= fmt::output_file("test-file");
282 fmt::ostream
moved(std::move(out
));
283 moved
.print("hello");
286 TEST(ostream_test
, move_while_holding_data
) {
288 fmt::ostream out
= fmt::output_file("test-file");
289 out
.print("Hello, ");
290 fmt::ostream
moved(std::move(out
));
291 moved
.print("world!\n");
294 file
in("test-file", file::RDONLY
);
295 EXPECT_READ(in
, "Hello, world!\n");
299 TEST(ostream_test
, print
) {
300 fmt::ostream out
= fmt::output_file("test-file");
301 out
.print("The answer is {}.\n",
302 fmt::join(std::initializer_list
<int>{42}, ", "));
304 file
in("test-file", file::RDONLY
);
305 EXPECT_READ(in
, "The answer is 42.\n");
308 TEST(ostream_test
, buffer_boundary
) {
309 auto str
= std::string(4096, 'x');
310 fmt::ostream out
= fmt::output_file("test-file");
311 out
.print("{}", str
);
312 out
.print("{}", str
);
314 file
in("test-file", file::RDONLY
);
315 EXPECT_READ(in
, str
+ str
);
318 TEST(ostream_test
, buffer_size
) {
319 fmt::ostream out
= fmt::output_file("test-file", fmt::buffer_size
= 1);
320 out
.print("{}", "foo");
322 file
in("test-file", file::RDONLY
);
323 EXPECT_READ(in
, "foo");
326 TEST(ostream_test
, truncate
) {
328 fmt::ostream out
= fmt::output_file("test-file");
329 out
.print("0123456789");
332 fmt::ostream out
= fmt::output_file("test-file");
335 file
in("test-file", file::RDONLY
);
336 EXPECT_EQ("foo", read(in
, 4));
339 TEST(file_test
, default_ctor
) {
341 EXPECT_EQ(-1, f
.descriptor());
344 TEST(file_test
, open_buffered_file_in_ctor
) {
345 FILE* fp
= safe_fopen("test-file", "w");
346 std::fputs(file_content
, fp
);
348 file
f("test-file", file::RDONLY
);
349 // Check if the file is open by reading one character from it.
351 bool isopen
= FMT_POSIX(read(f
.descriptor(), &buffer
, 1)) == 1;
355 TEST(file_test
, open_buffered_file_error
) {
356 EXPECT_SYSTEM_ERROR(file("nonexistent", file::RDONLY
), ENOENT
,
357 "cannot open file nonexistent");
360 TEST(file_test
, move_ctor
) {
361 file f
= open_file();
362 int fd
= f
.descriptor();
364 file
f2(std::move(f
));
365 EXPECT_EQ(fd
, f2
.descriptor());
366 EXPECT_EQ(-1, f
.descriptor());
369 TEST(file_test
, move_assignment
) {
370 file f
= open_file();
371 int fd
= f
.descriptor();
375 EXPECT_EQ(fd
, f2
.descriptor());
376 EXPECT_EQ(-1, f
.descriptor());
379 TEST(file_test
, move_assignment_closes_file
) {
380 file f
= open_file();
381 file f2
= open_file();
382 int old_fd
= f2
.descriptor();
384 EXPECT_TRUE(isclosed(old_fd
));
387 file
open_buffered_file(int& fd
) {
388 file f
= open_file();
393 TEST(file_test
, move_from_temporary_in_ctor
) {
395 file
f(open_buffered_file(fd
));
396 EXPECT_EQ(fd
, f
.descriptor());
399 TEST(file_test
, move_from_temporary_in_assignment
) {
402 f
= open_buffered_file(fd
);
403 EXPECT_EQ(fd
, f
.descriptor());
406 TEST(file_test
, move_from_temporary_in_assignment_closes_file
) {
408 file f
= open_file();
409 int old_fd
= f
.descriptor();
410 f
= open_buffered_file(fd
);
411 EXPECT_TRUE(isclosed(old_fd
));
414 TEST(file_test
, close_file_in_dtor
) {
417 file f
= open_file();
420 EXPECT_TRUE(isclosed(fd
));
423 TEST(file_test
, close_error_in_dtor
) {
424 std::unique_ptr
<file
> f(new file(open_file()));
428 // The close function must be called inside EXPECT_WRITE,
429 // otherwise the system may recycle closed file descriptor when
430 // redirecting the output in EXPECT_STDERR and the second close
431 // will break output redirection.
432 FMT_POSIX(close(f
->descriptor()));
433 SUPPRESS_ASSERT(f
.reset(nullptr));
435 system_error_message(EBADF
, "cannot close file") + "\n");
438 TEST(file_test
, close
) {
439 file f
= open_file();
440 int fd
= f
.descriptor();
442 EXPECT_EQ(-1, f
.descriptor());
443 EXPECT_TRUE(isclosed(fd
));
446 TEST(file_test
, close_error
) {
447 file f
= open_file();
448 FMT_POSIX(close(f
.descriptor()));
449 EXPECT_SYSTEM_ERROR_NOASSERT(f
.close(), EBADF
, "cannot close file");
450 EXPECT_EQ(-1, f
.descriptor());
453 TEST(file_test
, read
) {
454 file f
= open_file();
455 EXPECT_READ(f
, file_content
);
458 TEST(file_test
, read_error
) {
459 file
f("test-file", file::WRONLY
);
461 // We intentionally read from a file opened in the write-only mode to
463 EXPECT_SYSTEM_ERROR(f
.read(&buf
, 1), EBADF
, "cannot read from file");
466 TEST(file_test
, write
) {
467 file read_end
, write_end
;
468 file::pipe(read_end
, write_end
);
469 write(write_end
, "test");
471 EXPECT_READ(read_end
, "test");
474 TEST(file_test
, write_error
) {
475 file
f("test-file", file::RDONLY
);
476 // We intentionally write to a file opened in the read-only mode to
478 EXPECT_SYSTEM_ERROR(f
.write(" ", 1), EBADF
, "cannot write to file");
481 TEST(file_test
, dup
) {
482 file f
= open_file();
483 file copy
= file::dup(f
.descriptor());
484 EXPECT_NE(f
.descriptor(), copy
.descriptor());
485 EXPECT_EQ(file_content
, read(copy
, std::strlen(file_content
)));
488 # ifndef __COVERITY__
489 TEST(file_test
, dup_error
) {
491 EXPECT_SYSTEM_ERROR_NOASSERT(file::dup(value
), EBADF
,
492 "cannot duplicate file descriptor -1");
496 TEST(file_test
, dup2
) {
497 file f
= open_file();
498 file copy
= open_file();
499 f
.dup2(copy
.descriptor());
500 EXPECT_NE(f
.descriptor(), copy
.descriptor());
501 EXPECT_READ(copy
, file_content
);
504 TEST(file_test
, dup2_error
) {
505 file f
= open_file();
506 EXPECT_SYSTEM_ERROR_NOASSERT(
508 fmt::format("cannot duplicate file descriptor {} to -1", f
.descriptor()));
511 TEST(file_test
, dup2_noexcept
) {
512 file f
= open_file();
513 file copy
= open_file();
515 f
.dup2(copy
.descriptor(), ec
);
516 EXPECT_EQ(ec
.value(), 0);
517 EXPECT_NE(f
.descriptor(), copy
.descriptor());
518 EXPECT_READ(copy
, file_content
);
521 TEST(file_test
, dup2_noexcept_error
) {
522 file f
= open_file();
524 SUPPRESS_ASSERT(f
.dup2(-1, ec
));
525 EXPECT_EQ(EBADF
, ec
.value());
528 TEST(file_test
, pipe
) {
529 file read_end
, write_end
;
530 file::pipe(read_end
, write_end
);
531 EXPECT_NE(-1, read_end
.descriptor());
532 EXPECT_NE(-1, write_end
.descriptor());
533 write(write_end
, "test");
534 EXPECT_READ(read_end
, "test");
537 TEST(file_test
, fdopen
) {
538 file read_end
, write_end
;
539 file::pipe(read_end
, write_end
);
540 int read_fd
= read_end
.descriptor();
541 EXPECT_EQ(read_fd
, FMT_POSIX(fileno(read_end
.fdopen("r").get())));
545 TEST(locale_test
, strtod
) {
547 const char *start
= "4.2", *ptr
= start
;
548 EXPECT_EQ(4.2, loc
.strtod(ptr
));
549 EXPECT_EQ(start
+ 3, ptr
);
552 #endif // FMT_USE_FCNTL