13f65f718SMark de Wever //===----------------------------------------------------------------------===// 2*6a54dfbfSLouis Dionne // 33f65f718SMark de Wever // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 43f65f718SMark de Wever // See https://llvm.org/LICENSE.txt for license information. 53f65f718SMark de Wever // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 63f65f718SMark de Wever // 73f65f718SMark de Wever //===----------------------------------------------------------------------===// 83f65f718SMark de Wever 93f65f718SMark de Wever // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 103f65f718SMark de Wever // UNSUPPORTED: no-filesystem 113f65f718SMark de Wever // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME 123f65f718SMark de Wever 1360647e6aSMark de Wever // TODO PRINT Enable again 1460647e6aSMark de Wever // https://reviews.llvm.org/D150044 1560647e6aSMark de Wever // https://lab.llvm.org/buildbot/#/builders/237/builds/3578 16805ce9a6SMark de Wever // UNSUPPORTED: asan, hwasan, msan 1760647e6aSMark de Wever 183f65f718SMark de Wever // XFAIL: availability-fp_to_chars-missing 193f65f718SMark de Wever 20bce3b505SRyan Prichard // The error exception has no system error string. 21bce3b505SRyan Prichard // XFAIL: LIBCXX-ANDROID-FIXME 22bce3b505SRyan Prichard 233f65f718SMark de Wever // <print> 243f65f718SMark de Wever 253f65f718SMark de Wever // void vprint_nonunicode(FILE* stream, string_view fmt, format_args args); 263f65f718SMark de Wever 273f65f718SMark de Wever #include <algorithm> 283f65f718SMark de Wever #include <array> 293f65f718SMark de Wever #include <cassert> 303f65f718SMark de Wever #include <cstddef> 313f65f718SMark de Wever #include <cstdio> 323f65f718SMark de Wever #include <fstream> 333f65f718SMark de Wever #include <iterator> 343f65f718SMark de Wever #include <print> 353f65f718SMark de Wever #include <string_view> 363f65f718SMark de Wever 373f65f718SMark de Wever #include "assert_macros.h" 383f65f718SMark de Wever #include "concat_macros.h" 393f65f718SMark de Wever #include "filesystem_test_helper.h" 403f65f718SMark de Wever #include "print_tests.h" 413f65f718SMark de Wever #include "test_macros.h" 423f65f718SMark de Wever 433f65f718SMark de Wever scoped_test_env env; 443f65f718SMark de Wever std::string filename = env.create_file("output.txt"); 453f65f718SMark de Wever 463f65f718SMark de Wever auto test_file = []<class... Args>(std::string_view expected, std::string_view fmt, Args&&... args) { 473f65f718SMark de Wever FILE* file = fopen(filename.c_str(), "wb"); 483f65f718SMark de Wever assert(file); 493f65f718SMark de Wever 503f65f718SMark de Wever std::vprint_nonunicode(file, fmt, std::make_format_args(args...)); 513f65f718SMark de Wever std::fclose(file); 523f65f718SMark de Wever 533f65f718SMark de Wever std::ifstream stream{filename.c_str(), std::ios_base::in | std::ios_base::binary}; 543f65f718SMark de Wever std::string out(std::istreambuf_iterator<char>{stream}, {}); 553f65f718SMark de Wever TEST_REQUIRE(out == expected, 563f65f718SMark de Wever TEST_WRITE_CONCATENATED( 573f65f718SMark de Wever "\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n')); 583f65f718SMark de Wever }; 593f65f718SMark de Wever 603f65f718SMark de Wever auto test_exception = []<class... Args>([[maybe_unused]] std::string_view what, 613f65f718SMark de Wever [[maybe_unused]] std::string_view fmt, 623f65f718SMark de Wever [[maybe_unused]] Args&&... args) { 633f65f718SMark de Wever FILE* file = fopen(filename.c_str(), "wb"); 643f65f718SMark de Wever assert(file); 653f65f718SMark de Wever 663f65f718SMark de Wever TEST_VALIDATE_EXCEPTION( 673f65f718SMark de Wever std::format_error, 683f65f718SMark de Wever [&]([[maybe_unused]] const std::format_error& e) { 693f65f718SMark de Wever TEST_LIBCPP_REQUIRE( 703f65f718SMark de Wever e.what() == what, 713f65f718SMark de Wever TEST_WRITE_CONCATENATED( 723f65f718SMark de Wever "\nFormat string ", fmt, "\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); 733f65f718SMark de Wever }, 743f65f718SMark de Wever std::vprint_nonunicode(file, fmt, std::make_format_args(args...))); 753f65f718SMark de Wever 763f65f718SMark de Wever fclose(file); 773f65f718SMark de Wever }; 783f65f718SMark de Wever 793f65f718SMark de Wever // Glibc fails writing to a wide stream. 803f65f718SMark de Wever #if defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) 813f65f718SMark de Wever static void test_wide_stream() { 823f65f718SMark de Wever FILE* file = fopen(filename.c_str(), "wb"); 833f65f718SMark de Wever assert(file); 843f65f718SMark de Wever 853f65f718SMark de Wever int mode = std::fwide(file, 1); 863f65f718SMark de Wever assert(mode > 0); 873f65f718SMark de Wever 883f65f718SMark de Wever TEST_VALIDATE_EXCEPTION( 893f65f718SMark de Wever std::system_error, 903f65f718SMark de Wever [&]([[maybe_unused]] const std::system_error& e) { 913f65f718SMark de Wever [[maybe_unused]] std::string_view what{"failed to write formatted output"}; 923f65f718SMark de Wever TEST_LIBCPP_REQUIRE( 933f65f718SMark de Wever e.what() == what, 943f65f718SMark de Wever TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); 953f65f718SMark de Wever }, 963f65f718SMark de Wever std::vprint_nonunicode(file, "hello", std::make_format_args())); 973f65f718SMark de Wever } 983f65f718SMark de Wever #endif // defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) 993f65f718SMark de Wever 1003f65f718SMark de Wever static void test_read_only() { 1013f65f718SMark de Wever FILE* file = fopen(filename.c_str(), "r"); 1023f65f718SMark de Wever assert(file); 1033f65f718SMark de Wever 1043f65f718SMark de Wever TEST_VALIDATE_EXCEPTION( 1053f65f718SMark de Wever std::system_error, 1063f65f718SMark de Wever [&]([[maybe_unused]] const std::system_error& e) { 107a3529aa9SStephan T. Lavavej [[maybe_unused]] std::string_view what{ 108a3529aa9SStephan T. Lavavej "failed to write formatted output: " TEST_IF_AIX("Broken pipe", "Operation not permitted")}; 1093f65f718SMark de Wever TEST_LIBCPP_REQUIRE( 1103f65f718SMark de Wever e.what() == what, 1113f65f718SMark de Wever TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); 1123f65f718SMark de Wever }, 1133f65f718SMark de Wever std::vprint_nonunicode(file, "hello", std::make_format_args())); 1143f65f718SMark de Wever } 1153f65f718SMark de Wever 1163f65f718SMark de Wever static void test_new_line() { 1173f65f718SMark de Wever // Text does newline translation. 1183f65f718SMark de Wever { 1193f65f718SMark de Wever FILE* file = fopen(filename.c_str(), "w"); 1203f65f718SMark de Wever assert(file); 1213f65f718SMark de Wever 1223f65f718SMark de Wever std::vprint_nonunicode(file, "\n", std::make_format_args()); 1233f65f718SMark de Wever #ifndef _WIN32 1243f65f718SMark de Wever assert(std::ftell(file) == 1); 1253f65f718SMark de Wever #else 1263f65f718SMark de Wever assert(std::ftell(file) == 2); 1273f65f718SMark de Wever #endif 1283f65f718SMark de Wever } 1293f65f718SMark de Wever // Binary no newline translation. 1303f65f718SMark de Wever { 1313f65f718SMark de Wever FILE* file = fopen(filename.c_str(), "wb"); 1323f65f718SMark de Wever assert(file); 1333f65f718SMark de Wever 1343f65f718SMark de Wever std::vprint_nonunicode(file, "\n", std::make_format_args()); 1353f65f718SMark de Wever assert(std::ftell(file) == 1); 1363f65f718SMark de Wever } 1373f65f718SMark de Wever } 1383f65f718SMark de Wever 1393f65f718SMark de Wever int main(int, char**) { 1403f65f718SMark de Wever print_tests(test_file, test_exception); 1413f65f718SMark de Wever 1423f65f718SMark de Wever #if defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) 1433f65f718SMark de Wever test_wide_stream(); 1443f65f718SMark de Wever #endif 1453f65f718SMark de Wever test_read_only(); 1463f65f718SMark de Wever test_new_line(); 1473f65f718SMark de Wever 1483f65f718SMark de Wever return 0; 1493f65f718SMark de Wever } 150