os-test.cc 15 KB

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