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: no-wide-characters 12 // UNSUPPORTED: libcpp-has-no-unicode 13 // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME 14 15 // Clang modules do not work with the definiton of _LIBCPP_TESTING_PRINT_WRITE_TO_WINDOWS_CONSOLE_FUNCTION 16 // XFAIL: clang-modules-build 17 18 // XFAIL: availability-fp_to_chars-missing 19 20 // <print> 21 22 // Tests the implementation of 23 // void __print::__vprint_unicode_windows(FILE* __stream, string_view __fmt, 24 // format_args __args, bool __write_nl, 25 // bool __is_terminal); 26 // 27 // In the library when the stdout is redirected to a file it is no 28 // longer considered a terminal and the special terminal handling is no 29 // longer executed. By testing this function we can "force" emulate a 30 // terminal. 31 // Note __write_nl is tested by the public API. 32 33 #include <string_view> 34 #include <cstdio> 35 #include <algorithm> 36 #include <cassert> 37 38 void write_to_console(FILE*, std::wstring_view data); 39 #define _LIBCPP_TESTING_PRINT_WRITE_TO_WINDOWS_CONSOLE_FUNCTION ::write_to_console 40 #include <print> 41 42 #include "test_macros.h" 43 #include "filesystem_test_helper.h" 44 #include "make_string.h" 45 46 TEST_GCC_DIAGNOSTIC_IGNORED("-Wuse-after-free") 47 48 #define SV(S) MAKE_STRING_VIEW(wchar_t, S) 49 50 bool calling = false; 51 std::wstring_view expected = L" world"; 52 53 void write_to_console(FILE*, std::wstring_view data) { 54 assert(calling); 55 assert(data == expected); 56 } 57 58 scoped_test_env env; 59 std::string filename = env.create_file("output.txt"); 60 61 static void test_basics() { 62 FILE* file = std::fopen(filename.c_str(), "wb"); 63 assert(file); 64 65 // Test writing to a "non-terminal" stream does not call WriteConsoleW. 66 std::__print::__vprint_unicode_windows(file, "Hello", std::make_format_args(), false, false); 67 assert(std::ftell(file) == 5); 68 69 // It's not possible to reliably test whether writing to a "terminal" stream 70 // flushes before writing. Testing flushing a closed stream worked on some 71 // platforms, but was unreliable. 72 calling = true; 73 std::__print::__vprint_unicode_windows(file, " world", std::make_format_args(), false, true); 74 } 75 76 // When the output is a file the data is written as-is. 77 // When the output is a "terminal" invalid UTF-8 input is flagged. 78 static void test(std::wstring_view output, std::string_view input) { 79 // *** File *** 80 FILE* file = std::fopen(filename.c_str(), "wb"); 81 assert(file); 82 83 std::__print::__vprint_unicode_windows(file, input, std::make_format_args(), false, false); 84 assert(std::ftell(file) == static_cast<long>(input.size())); 85 std::fclose(file); 86 87 file = std::fopen(filename.c_str(), "rb"); 88 assert(file); 89 90 std::vector<char> buffer(input.size()); 91 size_t read = fread(buffer.data(), 1, buffer.size(), file); 92 assert(read == input.size()); 93 assert(input == std::string_view(buffer.begin(), buffer.end())); 94 std::fclose(file); 95 96 // *** Terminal *** 97 expected = output; 98 std::__print::__vprint_unicode_windows(file, input, std::make_format_args(), false, true); 99 } 100 101 static void test() { 102 // *** Test valid UTF-8 *** 103 #define TEST(S) test(SV(S), S) 104 TEST("hello world"); 105 106 // copied from benchmarks/std_format_spec_string_unicode.bench.cpp 107 TEST("Lorem ipsum dolor sit amet, ne sensibus evertitur aliquando his. Iuvaret fabulas qui ex."); 108 TEST("Lōrem ipsūm dolor sīt æmeÞ, ea vel nostrud feuġǣit, muciūs tēmporiȝusrefērrēnÞur no mel."); 109 TEST("Лорем ипсум долор сит амет, еу диам тамяуам принципес вис, еяуидем цонцептам диспутандо"); 110 TEST("入ト年媛ろ舗学ラロ準募ケカ社金スノ屋検れう策他セヲシ引口ぎ集7独ぱクふ出車ぽでぱ円輪ルノ受打わ。"); 111 TEST("\U0001f636\u200d\U0001f32b\ufe0f"); 112 #undef TEST 113 114 // *** Test invalid utf-8 *** 115 test(SV("\ufffd"), "\xc3"); 116 test(SV("\ufffd("), "\xc3\x28"); 117 118 // surrogate range 119 test(SV("\ufffd"), "\xed\xa0\x80"); // U+D800 120 test(SV("\ufffd"), "\xed\xaf\xbf"); // U+DBFF 121 test(SV("\ufffd"), "\xed\xbf\x80"); // U+DC00 122 test(SV("\ufffd"), "\xed\xbf\xbf"); // U+DFFF 123 124 // beyond valid values 125 test(SV("\ufffd"), "\xf4\x90\x80\x80"); // U+110000 126 test(SV("\ufffd"), "\xf4\xbf\xbf\xbf"); // U+11FFFF 127 128 // Validates http://unicode.org/review/pr-121.html option 3. 129 test(SV("\u0061\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u0062"), "\x61\xf1\x80\x80\xe1\x80\xc2\x62"); 130 } 131 132 int main(int, char**) { 133 test_basics(); 134 test(); 135 } 136