xref: /llvm-project/libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/setbuf.pass.cpp (revision 0547e573c555445e37db5c3bc92ee72274e19b69)
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 // <fstream>
10 
11 // basic_streambuf<charT, traits>* setbuf(char_type* s, streamsize n) override;
12 
13 // In C++23 and later, this test requires support for P2467R1 in the dylib (a3f17ba3febbd546f2342ffc780ac93b694fdc8d)
14 // XFAIL: (!c++03 && !c++11 && !c++14 && !c++17 && !c++20) && using-built-library-before-llvm-18
15 
16 #include <fstream>
17 #include <cstddef>
18 #include <cassert>
19 
20 #include "test_macros.h"
21 
22 template <class CharT>
23 static std::size_t file_size(const char* filename) {
24   FILE* f = std::fopen(filename, "rb");
25   std::fseek(f, 0, SEEK_END);
26   long result = std::ftell(f);
27   std::fclose(f);
28   return result;
29 }
30 
31 // Helper class to expose some protected std::basic_filebuf<CharT> members.
32 template <class CharT>
33 struct filebuf : public std::basic_filebuf<CharT> {
34   CharT* base() { return this->pbase(); }
35   CharT* ptr() { return this->pptr(); }
36 };
37 
38 template <class CharT>
39 static void buffered_request() {
40   filebuf<CharT> buffer;
41 
42   CharT b[10] = {0};
43   assert(buffer.pubsetbuf(b, 10) == &buffer);
44 
45   buffer.open("test.dat", std::ios_base::out);
46   buffer.sputc(CharT('a'));
47   assert(b[0] == 'a');
48 
49   buffer.close();
50   assert(file_size<CharT>("test.dat") == 1);
51 }
52 
53 template <class CharT>
54 static void unbuffered_request_before_open() {
55   filebuf<CharT> buffer;
56 
57   assert(buffer.pubsetbuf(nullptr, 0) == &buffer);
58   assert(buffer.base() == nullptr);
59   assert(buffer.ptr() == nullptr);
60 
61   buffer.open("test.dat", std::ios_base::out);
62   assert(buffer.base() == nullptr);
63   assert(buffer.ptr() == nullptr);
64 
65   buffer.sputc(CharT('a'));
66   assert(buffer.base() == nullptr);
67   assert(buffer.ptr() == nullptr);
68 
69   assert(file_size<CharT>("test.dat") == 1);
70 }
71 
72 template <class CharT>
73 static void unbuffered_request_after_open() {
74   filebuf<CharT> buffer;
75 
76   buffer.open("test.dat", std::ios_base::out);
77 
78   assert(buffer.pubsetbuf(nullptr, 0) == &buffer);
79   assert(buffer.base() == nullptr);
80   assert(buffer.ptr() == nullptr);
81 
82   buffer.sputc(CharT('a'));
83   assert(buffer.base() == nullptr);
84   assert(buffer.ptr() == nullptr);
85 
86   assert(file_size<CharT>("test.dat") == 1);
87 }
88 
89 template <class CharT>
90 static void unbuffered_request_after_open_ate() {
91   filebuf<CharT> buffer;
92 
93   buffer.open("test.dat", std::ios_base::out | std::ios_base::ate);
94 
95   assert(buffer.pubsetbuf(nullptr, 0) == &buffer);
96 
97   buffer.sputc(CharT('a'));
98   assert(file_size<CharT>("test.dat") <= 1);
99   // on libc++ buffering is used by default.
100   LIBCPP_ASSERT(file_size<CharT>("test.dat") == 0);
101 
102   buffer.close();
103   assert(file_size<CharT>("test.dat") == 1);
104 }
105 
106 template <class CharT>
107 static void test() {
108   buffered_request<CharT>();
109 
110   unbuffered_request_before_open<CharT>();
111   unbuffered_request_after_open<CharT>();
112   unbuffered_request_after_open_ate<CharT>();
113 }
114 
115 int main(int, char**) {
116   test<char>();
117 
118 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
119   test<wchar_t>();
120 #endif
121 
122   return 0;
123 }
124