xref: /llvm-project/libcxx/test/std/input.output/syncstream/syncbuf/sputc.pass.cpp (revision f5832bab6f5024cabe32a9f668b7f44e6b7cfef5)
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
10 // UNSUPPORTED: no-localization
11 // UNSUPPORTED: libcpp-has-no-experimental-syncstream
12 
13 // <syncstream>
14 
15 // template <class charT, class traits, class Allocator>
16 // class basic_syncbuf;
17 
18 // Tests the inherited function using a custom allocator.
19 //
20 // int_type basic_streambuf<charT, traits>::sputc(char_type c);
21 //
22 // This test also validates the observable behaviour after move assignment and
23 // construction. This test uses a small so the underlying string is in short
24 // mode.
25 
26 #include <array>
27 #include <syncstream>
28 #include <cassert>
29 #include <sstream>
30 
31 #include "test_macros.h"
32 #include "test_allocator.h"
33 
34 template <class CharT>
test()35 void test() {
36   std::array< CharT, 17> input{
37       CharT('a'),
38       CharT('1'),
39       CharT('+'),
40       CharT('A'),
41       CharT('g'),
42       CharT('0'),
43       CharT('@'),
44       CharT('Z'),
45       CharT('q'),
46       CharT('8'),
47       CharT('#'),
48       CharT('D'),
49       CharT('t'),
50       CharT('9'),
51       CharT('$'),
52       CharT('A'),
53       CharT(' ')};
54   using SyncBuf = std::basic_syncbuf<CharT, std::char_traits<CharT>, test_allocator<CharT>>;
55 
56   { // Normal
57     std::basic_string<CharT> expected;
58     std::basic_stringbuf<CharT> buf;
59     test_allocator_statistics stats;
60     test_allocator<CharT> allocator{&stats};
61 
62     {
63       SyncBuf sync_buf{&buf, allocator};
64       for (int i = 0; i < 1024; ++i) {
65         CharT c = input[i % input.size()];
66         expected.push_back(c);
67         typename SyncBuf::int_type ret = sync_buf.sputc(c);
68         assert(ret == typename SyncBuf::int_type(c));
69       }
70       // The synchronization happens upon destruction of sync_buf.
71       assert(buf.str().empty());
72       assert(stats.allocated_size >= 1024);
73     }
74     assert(buf.str() == expected);
75     assert(stats.allocated_size == 0);
76   }
77   { // Move construction
78     std::basic_stringbuf<CharT> buf;
79     test_allocator_statistics stats;
80     test_allocator<CharT> allocator{&stats};
81 
82     {
83       SyncBuf sync_buf{&buf, allocator};
84       CharT c                        = CharT('4');
85       typename SyncBuf::int_type ret = sync_buf.sputc(c);
86       assert(ret == typename SyncBuf::int_type(c));
87 
88       {
89         c = CharT('2');
90 
91         SyncBuf new_sync_buf{std::move(sync_buf)};
92         ret = new_sync_buf.sputc(c);
93         assert(ret == typename SyncBuf::int_type(c));
94 
95         // The synchronization happens upon destruction of new_sync_buf.
96         assert(buf.str().empty());
97         assert(stats.allocated_size >= 2);
98       }
99       assert(buf.str().size() == 2);
100       assert(buf.str()[0] == CharT('4'));
101       assert(buf.str()[1] == CharT('2'));
102       assert(stats.allocated_size == 0);
103     }
104     assert(buf.str().size() == 2);
105     assert(buf.str()[0] == CharT('4'));
106     assert(buf.str()[1] == CharT('2'));
107     assert(stats.allocated_size == 0);
108   }
109   { // Move assignment non-propagating allocator
110     std::basic_stringbuf<CharT> buf;
111     test_allocator_statistics stats;
112     test_allocator<CharT> allocator{&stats};
113     static_assert(!std::allocator_traits<test_allocator<CharT>>::propagate_on_container_move_assignment::value);
114 
115     {
116       SyncBuf sync_buf{&buf, allocator};
117       CharT c                        = CharT('4');
118       typename SyncBuf::int_type ret = sync_buf.sputc(c);
119       assert(ret == typename SyncBuf::int_type(c));
120 
121       {
122         c = CharT('2');
123 
124         SyncBuf new_sync_buf;
125         test_allocator<CharT> a = new_sync_buf.get_allocator();
126         new_sync_buf            = std::move(sync_buf);
127         assert(new_sync_buf.get_allocator() == a);
128 
129         ret = new_sync_buf.sputc(c);
130         assert(ret == typename SyncBuf::int_type(c));
131 
132         // The synchronization happens upon destruction of new_sync_buf.
133         assert(buf.str().empty());
134       }
135       assert(buf.str().size() == 2);
136       assert(buf.str()[0] == CharT('4'));
137       assert(buf.str()[1] == CharT('2'));
138     }
139     assert(buf.str().size() == 2);
140     assert(buf.str()[0] == CharT('4'));
141     assert(buf.str()[1] == CharT('2'));
142   }
143 }
144 
main(int,char **)145 int main(int, char**) {
146   test<char>();
147 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
148   test<wchar_t>();
149 #endif
150   return 0;
151 }
152