xref: /llvm-project/libcxx/test/std/input.output/iostream.format/print.fun/println.file.pass.cpp (revision 6a54dfbfe534276d644d7f9c027f0deeb748dd53)
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