xref: /llvm-project/libcxx/test/std/input.output/iostream.format/print.fun/vprint_unicode.file.pass.cpp (revision 6a54dfbfe534276d644d7f9c027f0deeb748dd53)
13f65f718SMark de Wever //===----------------------------------------------------------------------===//
2*6a54dfbfSLouis Dionne //
33f65f718SMark de Wever // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43f65f718SMark de Wever // See https://llvm.org/LICENSE.txt for license information.
53f65f718SMark de Wever // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63f65f718SMark de Wever //
73f65f718SMark de Wever //===----------------------------------------------------------------------===//
83f65f718SMark de Wever 
93f65f718SMark de Wever // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
103f65f718SMark de Wever // UNSUPPORTED: no-filesystem
113f65f718SMark de Wever // UNSUPPORTED: libcpp-has-no-unicode
123f65f718SMark de Wever // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
133f65f718SMark de Wever 
1460647e6aSMark de Wever // TODO PRINT Enable again
1560647e6aSMark de Wever // https://reviews.llvm.org/D150044
1660647e6aSMark de Wever // https://lab.llvm.org/buildbot/#/builders/237/builds/3578
17805ce9a6SMark de Wever // UNSUPPORTED: asan, hwasan, msan
1860647e6aSMark de Wever 
193f65f718SMark de Wever // XFAIL: availability-fp_to_chars-missing
203f65f718SMark de Wever 
21bce3b505SRyan Prichard // The error exception has no system error string.
22bce3b505SRyan Prichard // XFAIL: LIBCXX-ANDROID-FIXME
23bce3b505SRyan Prichard 
243f65f718SMark de Wever // <print>
253f65f718SMark de Wever 
263f65f718SMark de Wever // void vprint_unicode(FILE* stream, string_view fmt, format_args args);
273f65f718SMark de Wever 
283f65f718SMark de Wever // In the library when the stdout is redirected to a file it is no
293f65f718SMark de Wever // longer considered a terminal and the special terminal handling is no
303f65f718SMark de Wever // longer executed. There are tests in
313f65f718SMark de Wever //   libcxx/test/libcxx/input.output/iostream.format/print.fun/
323f65f718SMark de Wever // to validate that behaviour
333f65f718SMark de Wever 
343f65f718SMark de Wever #include <algorithm>
353f65f718SMark de Wever #include <array>
363f65f718SMark de Wever #include <cassert>
373f65f718SMark de Wever #include <cstddef>
383f65f718SMark de Wever #include <cstdio>
393f65f718SMark de Wever #include <fstream>
403f65f718SMark de Wever #include <iterator>
413f65f718SMark de Wever #include <print>
423f65f718SMark de Wever #include <string_view>
433f65f718SMark de Wever 
443f65f718SMark de Wever #include "assert_macros.h"
453f65f718SMark de Wever #include "concat_macros.h"
463f65f718SMark de Wever #include "filesystem_test_helper.h"
473f65f718SMark de Wever #include "print_tests.h"
483f65f718SMark de Wever #include "test_macros.h"
493f65f718SMark de Wever 
503f65f718SMark de Wever scoped_test_env env;
513f65f718SMark de Wever std::string filename = env.create_file("output.txt");
523f65f718SMark de Wever 
533f65f718SMark de Wever auto test_file = []<class... Args>(std::string_view expected, std::string_view fmt, Args&&... args) {
543f65f718SMark de Wever   FILE* file = fopen(filename.c_str(), "wb");
553f65f718SMark de Wever   assert(file);
563f65f718SMark de Wever 
573f65f718SMark de Wever   std::vprint_unicode(file, fmt, std::make_format_args(args...));
583f65f718SMark de Wever   std::fclose(file);
593f65f718SMark de Wever 
603f65f718SMark de Wever   std::ifstream stream{filename.c_str(), std::ios_base::in | std::ios_base::binary};
613f65f718SMark de Wever   std::string out(std::istreambuf_iterator<char>{stream}, {});
623f65f718SMark de Wever   TEST_REQUIRE(out == expected,
633f65f718SMark de Wever                TEST_WRITE_CONCATENATED(
643f65f718SMark de Wever                    "\nFormat string   ", fmt, "\nExpected output ", expected, "\nActual output   ", out, '\n'));
653f65f718SMark de Wever };
663f65f718SMark de Wever 
673f65f718SMark de Wever auto test_exception = []<class... Args>([[maybe_unused]] std::string_view what,
683f65f718SMark de Wever                                         [[maybe_unused]] std::string_view fmt,
693f65f718SMark de Wever                                         [[maybe_unused]] Args&&... args) {
703f65f718SMark de Wever   FILE* file = fopen(filename.c_str(), "wb");
713f65f718SMark de Wever   assert(file);
723f65f718SMark de Wever 
733f65f718SMark de Wever   TEST_VALIDATE_EXCEPTION(
743f65f718SMark de Wever       std::format_error,
753f65f718SMark de Wever       [&]([[maybe_unused]] const std::format_error& e) {
763f65f718SMark de Wever         TEST_LIBCPP_REQUIRE(
773f65f718SMark de Wever             e.what() == what,
783f65f718SMark de Wever             TEST_WRITE_CONCATENATED(
793f65f718SMark de Wever                 "\nFormat string   ", fmt, "\nExpected exception ", what, "\nActual exception   ", e.what(), '\n'));
803f65f718SMark de Wever       },
813f65f718SMark de Wever       std::vprint_unicode(file, fmt, std::make_format_args(args...)));
823f65f718SMark de Wever 
833f65f718SMark de Wever   fclose(file);
843f65f718SMark de Wever };
853f65f718SMark de Wever 
863f65f718SMark de Wever // Glibc fails writing to a wide stream.
873f65f718SMark de Wever #if defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS)
883f65f718SMark de Wever static void test_wide_stream() {
893f65f718SMark de Wever   FILE* file = fopen(filename.c_str(), "wb");
903f65f718SMark de Wever   assert(file);
913f65f718SMark de Wever 
923f65f718SMark de Wever   int mode = std::fwide(file, 1);
933f65f718SMark de Wever   assert(mode > 0);
943f65f718SMark de Wever 
953f65f718SMark de Wever   TEST_VALIDATE_EXCEPTION(
963f65f718SMark de Wever       std::system_error,
973f65f718SMark de Wever       [&]([[maybe_unused]] const std::system_error& e) {
983f65f718SMark de Wever         [[maybe_unused]] std::string_view what{"failed to write formatted output"};
993f65f718SMark de Wever         TEST_LIBCPP_REQUIRE(
1003f65f718SMark de Wever             e.what() == what,
1013f65f718SMark de Wever             TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception   ", e.what(), '\n'));
1023f65f718SMark de Wever       },
1033f65f718SMark de Wever       std::vprint_unicode(file, "hello", std::make_format_args()));
1043f65f718SMark de Wever }
1053f65f718SMark de Wever #endif // defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS)
1063f65f718SMark de Wever 
1073f65f718SMark de Wever static void test_read_only() {
1083f65f718SMark de Wever   FILE* file = fopen(filename.c_str(), "r");
1093f65f718SMark de Wever   assert(file);
1103f65f718SMark de Wever 
1113f65f718SMark de Wever   TEST_VALIDATE_EXCEPTION(
1123f65f718SMark de Wever       std::system_error,
1133f65f718SMark de Wever       [&]([[maybe_unused]] const std::system_error& e) {
114a3529aa9SStephan T. Lavavej         [[maybe_unused]] std::string_view what{
115a3529aa9SStephan T. Lavavej             "failed to write formatted output: " TEST_IF_AIX("Broken pipe", "Operation not permitted")};
1163f65f718SMark de Wever         TEST_LIBCPP_REQUIRE(
1173f65f718SMark de Wever             e.what() == what,
1183f65f718SMark de Wever             TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception   ", e.what(), '\n'));
1193f65f718SMark de Wever       },
1203f65f718SMark de Wever       std::vprint_unicode(file, "hello", std::make_format_args()));
1213f65f718SMark de Wever }
1223f65f718SMark de Wever 
1233f65f718SMark de Wever static void test_new_line() {
1243f65f718SMark de Wever   // Text does newline translation.
1253f65f718SMark de Wever   {
1263f65f718SMark de Wever     FILE* file = fopen(filename.c_str(), "w");
1273f65f718SMark de Wever     assert(file);
1283f65f718SMark de Wever 
1293f65f718SMark de Wever     std::vprint_unicode(file, "\n", std::make_format_args());
1303f65f718SMark de Wever #ifndef _WIN32
1313f65f718SMark de Wever     assert(std::ftell(file) == 1);
1323f65f718SMark de Wever #else
1333f65f718SMark de Wever     assert(std::ftell(file) == 2);
1343f65f718SMark de Wever #endif
1353f65f718SMark de Wever   }
1363f65f718SMark de Wever   // Binary no newline translation.
1373f65f718SMark de Wever   {
1383f65f718SMark de Wever     FILE* file = fopen(filename.c_str(), "wb");
1393f65f718SMark de Wever     assert(file);
1403f65f718SMark de Wever 
1413f65f718SMark de Wever     std::vprint_unicode(file, "\n", std::make_format_args());
1423f65f718SMark de Wever     assert(std::ftell(file) == 1);
1433f65f718SMark de Wever   }
1443f65f718SMark de Wever }
1453f65f718SMark de Wever 
1463f65f718SMark de Wever int main(int, char**) {
1473f65f718SMark de Wever   print_tests(test_file, test_exception);
1483f65f718SMark de Wever 
1493f65f718SMark de Wever #if defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS)
1503f65f718SMark de Wever   test_wide_stream();
1513f65f718SMark de Wever #endif
1523f65f718SMark de Wever   test_read_only();
1533f65f718SMark de Wever   test_new_line();
1543f65f718SMark de Wever 
1553f65f718SMark de Wever   return 0;
1563f65f718SMark de Wever }
157