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