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

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