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
46scoped_test_env env;
47std::string filename = env.create_file("output.txt");
48
49auto test_file = []<class... Args>(std::string_view expected, test_format_string<char, Args...> fmt, Args&&... args) {
50 FILE* file = fopen(filename: filename.c_str(), modes: "wb");
51 assert(file);
52
53 std::print(format: file, fmt, std::forward<Args>(args)...);
54 std::fclose(stream: 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
63auto 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)
72static 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
91static void test_read_only() {
92 FILE* file = fopen(filename: filename.c_str(), modes: "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
107static void test_new_line() {
108 // Text does newline translation.
109 {
110 FILE* file = fopen(filename: filename.c_str(), modes: "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: filename.c_str(), modes: "wb");
123 assert(file);
124
125 std::print(file, "\n");
126 assert(std::ftell(file) == 1);
127 }
128}
129
130int main(int, char**) {
131 print_tests(check: test_file, check_exception: 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

source code of libcxx/test/std/input.output/iostream.format/print.fun/print.file.pass.cpp