//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // UNSUPPORTED: no-filesystem // UNSUPPORTED: libcpp-has-no-unicode // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME // TODO PRINT Enable again // https://reviews.llvm.org/D150044 // https://lab.llvm.org/buildbot/#/builders/237/builds/3578 // UNSUPPORTED: asan, hwasan, msan // XFAIL: availability-fp_to_chars-missing // The error exception has no system error string. // XFAIL: LIBCXX-ANDROID-FIXME // // void vprint_unicode(FILE* stream, string_view fmt, format_args args); // In the library when the stdout is redirected to a file it is no // longer considered a terminal and the special terminal handling is no // longer executed. There are tests in // libcxx/test/libcxx/input.output/iostream.format/print.fun/ // to validate that behaviour #include #include #include #include #include #include #include #include #include #include "assert_macros.h" #include "concat_macros.h" #include "filesystem_test_helper.h" #include "print_tests.h" #include "test_macros.h" scoped_test_env env; std::string filename = env.create_file("output.txt"); auto test_file = [](std::string_view expected, std::string_view fmt, Args&&... args) { FILE* file = fopen(filename.c_str(), "wb"); assert(file); std::vprint_unicode(file, fmt, std::make_format_args(args...)); std::fclose(file); std::ifstream stream{filename.c_str(), std::ios_base::in | std::ios_base::binary}; std::string out(std::istreambuf_iterator{stream}, {}); TEST_REQUIRE(out == expected, TEST_WRITE_CONCATENATED( "\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n')); }; auto test_exception = []([[maybe_unused]] std::string_view what, [[maybe_unused]] std::string_view fmt, [[maybe_unused]] Args&&... args) { FILE* file = fopen(filename.c_str(), "wb"); assert(file); TEST_VALIDATE_EXCEPTION( std::format_error, [&]([[maybe_unused]] const std::format_error& e) { TEST_LIBCPP_REQUIRE( e.what() == what, TEST_WRITE_CONCATENATED( "\nFormat string ", fmt, "\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); }, std::vprint_unicode(file, fmt, std::make_format_args(args...))); fclose(file); }; // Glibc fails writing to a wide stream. #if defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) static void test_wide_stream() { FILE* file = fopen(filename.c_str(), "wb"); assert(file); int mode = std::fwide(file, 1); assert(mode > 0); TEST_VALIDATE_EXCEPTION( std::system_error, [&]([[maybe_unused]] const std::system_error& e) { [[maybe_unused]] std::string_view what{"failed to write formatted output"}; TEST_LIBCPP_REQUIRE( e.what() == what, TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); }, std::vprint_unicode(file, "hello", std::make_format_args())); } #endif // defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) static void test_read_only() { FILE* file = fopen(filename.c_str(), "r"); assert(file); TEST_VALIDATE_EXCEPTION( std::system_error, [&]([[maybe_unused]] const std::system_error& e) { [[maybe_unused]] std::string_view what{ "failed to write formatted output: " TEST_IF_AIX("Broken pipe", "Operation not permitted")}; TEST_LIBCPP_REQUIRE( e.what() == what, TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); }, std::vprint_unicode(file, "hello", std::make_format_args())); } static void test_new_line() { // Text does newline translation. { FILE* file = fopen(filename.c_str(), "w"); assert(file); std::vprint_unicode(file, "\n", std::make_format_args()); #ifndef _WIN32 assert(std::ftell(file) == 1); #else assert(std::ftell(file) == 2); #endif } // Binary no newline translation. { FILE* file = fopen(filename.c_str(), "wb"); assert(file); std::vprint_unicode(file, "\n", std::make_format_args()); assert(std::ftell(file) == 1); } } int main(int, char**) { print_tests(test_file, test_exception); #if defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) test_wide_stream(); #endif test_read_only(); test_new_line(); return 0; }