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: GCC-ALWAYS_INLINE-FIXME
11
12// TODO PRINT Investigate see https://reviews.llvm.org/D156585
13// UNSUPPORTED: no-filesystem
14
15// XFAIL: availability-fp_to_chars-missing
16
17// <ostream>
18
19// template<class... Args>
20// void print(ostream& os, format_string<Args...> fmt, Args&&... args);
21
22// [ostream.formatted.print]/3
23// If the function is vprint_unicode and os is a stream that refers to
24// a terminal capable of displaying Unicode which is determined in an
25// implementation-defined manner, writes out to the terminal using the
26// native Unicode API;
27// This is tested in
28// test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
29
30#include <cassert>
31#include <ostream>
32#include <sstream>
33
34#include "assert_macros.h"
35#include "concat_macros.h"
36#include "print_tests.h"
37#include "test_format_string.h"
38#include "test_macros.h"
39
40auto test_file = []<class... Args>(std::string_view expected, test_format_string<char, Args...> fmt, Args&&... args) {
41 std::stringstream sstr;
42 std::print(format: sstr, fmt, std::forward<Args>(args)...);
43
44 std::string out = sstr.str();
45 TEST_REQUIRE(out == expected,
46 TEST_WRITE_CONCATENATED(
47 "\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
48};
49
50auto test_exception = []<class... Args>(std::string_view, std::string_view, Args&&...) {
51 // After P2216 most exceptions thrown by std::format become ill-formed.
52 // Therefore this tests does nothing.
53 // A basic ill-formed test is done in format.verify.cpp
54 // The exceptions are tested by other functions that don't use the basic-format-string as fmt argument.
55};
56// [ostream.formatted.print]/3.2
57// ...
58// After constructing a sentry object, the function initializes an automatic variable via
59// string out = vformat(os.getloc(), fmt, args);
60// This means if both
61// - creating a sentry fails
62// - the formatting fails
63// the first one "wins" and the format_error is not thrown.
64static void test_sentry_failure() {
65 // In order for the creation of a sentry to fail a tied stream's
66 // sync operation should fail.
67 struct sync_failure : public std::basic_streambuf<char> {
68 protected:
69 int virtual sync() { return -1; }
70 };
71 sync_failure buf_tied;
72 std::ostream os_tied(&buf_tied);
73 os_tied.exceptions(except: std::stringstream::failbit | std::stringstream::badbit | std::stringstream::eofbit);
74
75 std::stringstream os;
76 os.tie(tiestr: &os_tied);
77 os.exceptions(except: std::stringstream::failbit | std::stringstream::badbit | std::stringstream::eofbit);
78
79 TEST_THROWS_TYPE(std::ios_base::failure, std::print(os, "valid"));
80 os_tied.clear();
81 TEST_THROWS_TYPE(std::ios_base::failure, std::print(os, "throws exception at run-time {0:{0}}", -10));
82
83 os.exceptions(except: std::stringstream::goodbit);
84 os.setstate(std::stringstream::failbit);
85 std::print(os, "not called when the os.good() is false, so no exception is thrown {0:{0}}", -10);
86}
87
88// [ostream.formatted.print]/3.2
89// any exception thrown by the call to vformat is propagated without
90// regard to the value of os.exceptions() and without turning on
91// ios_base::badbit in the error state of os.
92// Most invalid format strings are checked at compile-time. An invalid
93// value for the width can only be tested run-time.
94static void test_format_exception() {
95 std::stringstream sstr;
96 assert(sstr.good());
97
98 TEST_THROWS_TYPE(std::format_error, std::print(sstr, "no output {0:{0}}", -10));
99 assert(sstr.good());
100 assert(sstr.str().empty());
101
102 sstr.exceptions(except: std::stringstream::goodbit);
103 TEST_THROWS_TYPE(std::format_error, std::print(sstr, "no output {0:{0}}", -10));
104 assert(sstr.good());
105 assert(sstr.str().empty());
106
107 sstr.exceptions(except: std::stringstream::failbit | std::stringstream::badbit | std::stringstream::eofbit);
108 TEST_THROWS_TYPE(std::format_error, std::print(sstr, "no output {0:{0}}", -10));
109 assert(sstr.good());
110 assert(sstr.str().empty());
111}
112
113static void test_write_failure() {
114 // Stream that fails to write a single character.
115 struct overflow_failure : public std::basic_streambuf<char> {
116 protected:
117 int virtual overflow(int) { return std::char_traits<char>::eof(); }
118 };
119 overflow_failure buf;
120 std::ostream os(&buf);
121 os.exceptions(except: std::stringstream::failbit | std::stringstream::badbit | std::stringstream::eofbit);
122
123 TEST_THROWS_TYPE(std::ios_base::failure, std::print(os, "valid"));
124 os.clear();
125 // When the parser would directly write to the output instead of
126 // formatting first it would fail writing the first character 't' of
127 // the string and result in a std::ios_base::failure exception.
128 TEST_THROWS_TYPE(std::format_error, std::print(os, "throws exception at run-time {0:{0}}", -10));
129
130 os.exceptions(except: std::stringstream::goodbit);
131 os.clear();
132 std::print(os, "valid");
133 assert(os.fail());
134}
135
136// Test the formatting does no padding.
137static void test_stream_formatting() {
138 std::stringstream sstr;
139 auto test = [&]<class... Args>(std::string_view expected, test_format_string<char, Args...> fmt, Args&&... args) {
140 sstr.str(s: "");
141 std::print(format: sstr, fmt, std::forward<Args>(args)...);
142
143 std::string out = sstr.str();
144 TEST_REQUIRE(out == expected,
145 TEST_WRITE_CONCATENATED(
146 "\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
147 };
148
149 test("hello", "{}", "hello");
150
151 sstr.width(wide: 10);
152 test("hello", "{}", "hello");
153 assert(sstr.width() == 10);
154
155 sstr.fill(ch: '+');
156
157 sstr.width(wide: 10);
158 test("hello", "{}", "hello");
159 assert(sstr.width() == 10);
160
161 // *** Test embedded NUL character ***
162 using namespace std::literals;
163 sstr.width(wide: 15);
164 test("hello\0world"sv, "hello{}{}", '\0', "world");
165 assert(sstr.width() == 15);
166}
167
168int main(int, char**) {
169 print_tests(check: test_file, check_exception: test_exception);
170
171 test_sentry_failure();
172 test_format_exception();
173 test_write_failure();
174 test_stream_formatting();
175
176 return 0;
177}
178

source code of libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/print.pass.cpp