2
0

os-test.cc 13 KB

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