1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 10 // UNSUPPORTED: no-filesystem 11 // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME 12 13 // XFAIL: availability-fp_to_chars-missing 14 15 // The error exception has no system error string. 16 // XFAIL: LIBCXX-ANDROID-FIXME 17 18 // <print> 19 20 // template<class... Args> 21 // void print(FILE* stream, format_string<Args...> fmt, Args&&... args); 22 23 // In the library when the stdout is redirected to a file it is no 24 // longer considered a terminal and the special terminal handling is no 25 // longer executed. There are tests in 26 // libcxx/test/libcxx/input.output/iostream.format/print.fun/ 27 // to validate that behaviour 28 29 #include <algorithm> 30 #include <array> 31 #include <cassert> 32 #include <cstddef> 33 #include <cstdio> 34 #include <fstream> 35 #include <iterator> 36 #include <print> 37 #include <string_view> 38 39 #include "assert_macros.h" 40 #include "concat_macros.h" 41 #include "filesystem_test_helper.h" 42 #include "print_tests.h" 43 #include "test_format_string.h" 44 #include "test_macros.h" 45 46 scoped_test_env env; 47 std::string filename = env.create_file("output.txt"); 48 49 auto test_file = []<class... Args>(std::string_view expected, test_format_string<char, Args...> fmt, Args&&... args) { 50 FILE* file = fopen(filename.c_str(), "wb"); 51 assert(file); 52 53 std::print(file, fmt, std::forward<Args>(args)...); 54 std::fclose(file); 55 56 std::ifstream stream{filename.c_str(), std::ios_base::in | std::ios_base::binary}; 57 std::string out(std::istreambuf_iterator<char>{stream}, {}); 58 TEST_REQUIRE(out == expected, 59 TEST_WRITE_CONCATENATED( 60 "\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n')); 61 }; 62 63 auto test_exception = []<class... Args>(std::string_view, std::string_view, Args&&...) { 64 // After P2216 most exceptions thrown by std::format become ill-formed. 65 // Therefore this tests does nothing. 66 // A basic ill-formed test is done in format.verify.cpp 67 // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument. 68 }; 69 70 // Glibc fails writing to a wide stream. 71 #if defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) 72 static void test_wide_stream() { 73 FILE* file = fopen(filename.c_str(), "wb"); 74 assert(file); 75 76 int mode = std::fwide(file, 1); 77 assert(mode > 0); 78 79 TEST_VALIDATE_EXCEPTION( 80 std::system_error, 81 [&]([[maybe_unused]] const std::system_error& e) { 82 [[maybe_unused]] std::string_view what{"failed to write formatted output"}; 83 TEST_LIBCPP_REQUIRE( 84 e.what() == what, 85 TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); 86 }, 87 std::print(file, "hello")); 88 } 89 #endif // defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) 90 91 static void test_read_only() { 92 FILE* file = fopen(filename.c_str(), "r"); 93 assert(file); 94 95 TEST_VALIDATE_EXCEPTION( 96 std::system_error, 97 [&]([[maybe_unused]] const std::system_error& e) { 98 [[maybe_unused]] std::string_view what{ 99 "failed to write formatted output: " TEST_IF_AIX("Broken pipe", "Operation not permitted")}; 100 TEST_LIBCPP_REQUIRE( 101 e.what() == what, 102 TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); 103 }, 104 std::print(file, "hello")); 105 } 106 107 static void test_new_line() { 108 // Text does newline translation. 109 { 110 FILE* file = fopen(filename.c_str(), "w"); 111 assert(file); 112 113 std::print(file, "\n"); 114 #ifndef _WIN32 115 assert(std::ftell(file) == 1); 116 #else 117 assert(std::ftell(file) == 2); 118 #endif 119 } 120 // Binary no newline translation. 121 { 122 FILE* file = fopen(filename.c_str(), "wb"); 123 assert(file); 124 125 std::print(file, "\n"); 126 assert(std::ftell(file) == 1); 127 } 128 } 129 130 int main(int, char**) { 131 print_tests(test_file, test_exception); 132 133 #if defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) 134 test_wide_stream(); 135 #endif 136 test_read_only(); 137 test_new_line(); 138 139 return 0; 140 } 141