comparison dep/fmt/test/os-test.cc @ 343:1faa72660932

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