xref: /llvm-project/libcxx/test/std/input.output/syncstream/syncbuf/sputn.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 // streamsize basic_streambuf<charT, traits>::sputc(const char_type* s, streamsize n);
21 //
22 // This test also validates the observable behaviour after move assignment and
23 // construction. This test uses a large buffer so the underlying string is in
24 // long 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   std::basic_string<CharT> expected;
55   for (int i = 0; i < 1024; ++i)
56     expected.push_back(input[i % input.size()]);
57 
58   using SyncBuf = std::basic_syncbuf<CharT, std::char_traits<CharT>, test_allocator<CharT>>;
59   { // Normal
60     std::basic_stringbuf<CharT> buf;
61     test_allocator_statistics stats;
62     test_allocator<CharT> allocator{&stats};
63 
64     {
65       SyncBuf sync_buf{&buf, allocator};
66       std::streamsize ret = sync_buf.sputn(expected.data(), expected.size());
67       assert(ret == 1024);
68 
69       // The synchronization happens upon destruction of sync_buf.
70       assert(buf.str().empty());
71       assert(stats.allocated_size >= 1024);
72     }
73     assert(buf.str() == expected);
74     assert(stats.allocated_size == 0);
75   }
76   { // Move construction
77     std::basic_stringbuf<CharT> buf;
78     test_allocator_statistics stats;
79     test_allocator<CharT> allocator{&stats};
80 
81     {
82       SyncBuf sync_buf{&buf, allocator};
83       std::streamsize ret = sync_buf.sputn(expected.data(), expected.size());
84       assert(ret == 1024);
85       {
86         SyncBuf new_sync_buf{std::move(sync_buf)};
87         ret = new_sync_buf.sputn(expected.data(), expected.size());
88         assert(ret == 1024);
89 
90         // The synchronization happens upon destruction of new_sync_buf.
91         assert(buf.str().empty());
92         assert(stats.allocated_size >= 2048);
93       }
94       assert(buf.str() == expected + expected);
95       assert(stats.allocated_size == 0);
96     }
97     assert(buf.str() == expected + expected);
98     assert(stats.allocated_size == 0);
99   }
100   { // Move assignment non-propagating allocator
101     std::basic_stringbuf<CharT> buf;
102     test_allocator_statistics stats;
103     test_allocator<CharT> allocator{&stats};
104     static_assert(!std::allocator_traits<test_allocator<CharT>>::propagate_on_container_move_assignment::value);
105 
106     {
107       SyncBuf sync_buf{&buf, allocator};
108       std::streamsize ret = sync_buf.sputn(expected.data(), expected.size());
109       assert(ret == 1024);
110       {
111         SyncBuf new_sync_buf;
112         test_allocator<CharT> a = new_sync_buf.get_allocator();
113         new_sync_buf            = std::move(sync_buf);
114         assert(new_sync_buf.get_allocator() == a);
115 
116         ret = new_sync_buf.sputn(expected.data(), expected.size());
117         assert(ret == 1024);
118 
119         // The synchronization happens upon destruction of new_sync_buf.
120         assert(buf.str().empty());
121       }
122       assert(buf.str() == expected + expected);
123     }
124     assert(buf.str() == expected + expected);
125   }
126 }
127 
main(int,char **)128 int main(int, char**) {
129   test<char>();
130 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
131   test<wchar_t>();
132 #endif
133   return 0;
134 }
135