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 println(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 <fstream> 36 #include <iterator> 37 #include <print> 38 #include <string_view> 39 40 #include "assert_macros.h" 41 #include "concat_macros.h" 42 #include "filesystem_test_helper.h" 43 #include "print_tests.h" 44 #include "test_format_string.h" 45 #include "test_macros.h" 46 47 scoped_test_env env; 48 std::string filename = env.create_file("output.txt"); 49 50 auto test_file = []<class... Args>(std::string_view e, test_format_string<char, Args...> fmt, Args&&... args) { 51 std::string expected = std::string{e} + '\n'; 52 53 FILE* file = fopen(filename.c_str(), "wb"); 54 assert(file); 55 56 std::println(file, fmt, std::forward<Args>(args)...); 57 std::fclose(file); 58 59 std::ifstream stream{filename.c_str(), std::ios_base::in | std::ios_base::binary}; 60 std::string out(std::istreambuf_iterator<char>{stream}, {}); 61 TEST_REQUIRE(out == expected, 62 TEST_WRITE_CONCATENATED( 63 "\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n')); 64 }; 65 66 auto test_exception = []<class... Args>(std::string_view, std::string_view, Args&&...) { 67 // After P2216 most exceptions thrown by std::format become ill-formed. 68 // Therefore this tests does nothing. 69 // A basic ill-formed test is done in format.verify.cpp 70 // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument. 71 }; 72 73 // Glibc fails writing to a wide stream. 74 #if defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) 75 static void test_wide_stream() { 76 FILE* file = fopen(filename.c_str(), "wb"); 77 assert(file); 78 79 int mode = std::fwide(file, 1); 80 assert(mode > 0); 81 82 TEST_VALIDATE_EXCEPTION( 83 std::system_error, 84 [&]([[maybe_unused]] const std::system_error& e) { 85 [[maybe_unused]] std::string_view what{"failed to write formatted output"}; 86 TEST_LIBCPP_REQUIRE( 87 e.what() == what, 88 TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); 89 }, 90 std::println(file, "hello")); 91 } 92 #endif // defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) 93 94 static void test_read_only() { 95 FILE* file = fopen(filename.c_str(), "r"); 96 assert(file); 97 98 TEST_VALIDATE_EXCEPTION( 99 std::system_error, 100 [&]([[maybe_unused]] const std::system_error& e) { 101 [[maybe_unused]] std::string_view what{ 102 "failed to write formatted output: " TEST_IF_AIX("Broken pipe", "Operation not permitted")}; 103 TEST_LIBCPP_REQUIRE( 104 e.what() == what, 105 TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); 106 }, 107 std::println(file, "hello")); 108 } 109 110 static void test_new_line() { 111 // Text does newline translation. 112 { 113 FILE* file = fopen(filename.c_str(), "w"); 114 assert(file); 115 116 std::println(file, ""); 117 #ifndef _WIN32 118 assert(std::ftell(file) == 1); 119 #else 120 assert(std::ftell(file) == 2); 121 #endif 122 } 123 // Binary no newline translation. 124 { 125 FILE* file = fopen(filename.c_str(), "wb"); 126 assert(file); 127 128 std::println(file, ""); 129 assert(std::ftell(file) == 1); 130 } 131 } 132 133 static void test_println_blank_line() { 134 // Text does newline translation. 135 { 136 FILE* file = fopen(filename.c_str(), "w"); 137 assert(file); 138 139 std::println(file); 140 #ifndef _WIN32 141 assert(std::ftell(file) == 1); 142 #else 143 assert(std::ftell(file) == 2); 144 #endif 145 } 146 // Binary no newline translation. 147 { 148 FILE* file = fopen(filename.c_str(), "wb"); 149 assert(file); 150 151 std::println(file); 152 assert(std::ftell(file) == 1); 153 } 154 } 155 156 int main(int, char**) { 157 print_tests(test_file, test_exception); 158 159 #if defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) 160 test_wide_stream(); 161 #endif 162 test_read_only(); 163 test_new_line(); 164 test_println_blank_line(); 165 166 return 0; 167 } 168