blob: dc94e2c8116fff740cadde74fa53fdadff884133 [file] [log] [blame]
William A. Kennington III3c7107f2023-06-13 15:13:50 -07001#include <stdplus/str/buf.hpp>
2#include <stdplus/str/cexpr.hpp>
3
4#include <gtest/gtest.h>
5
6namespace stdplus
7{
8
9static constexpr auto makeIncStr(std::size_t len)
10{
11 stdplus::StrBuf ret;
12 auto ptr = ret.append(len);
13 for (std::size_t i = 0; i < len; i++)
14 {
15 ptr[i] = 'A' + (i % 26);
16 }
17 return ret;
18}
19
20constexpr auto data = cexprSv<[]() { return makeIncStr(sizeof(StrBuf) + 10); }>;
21// constexpr auto data = cexprSv<[]() { return makeIncStr(32); }>;
22
23TEST(StrBuf, BasicInline)
24{
25 StrBuf buf;
26 EXPECT_EQ(buf.size(), 0);
27 auto old_ptr = buf.begin();
28
29 // Ensure that we inline small amounts of data only
30 std::copy(data.begin(), data.begin() + 4, buf.append(4));
31 EXPECT_EQ(buf.begin(), old_ptr);
32 EXPECT_EQ(buf.size(), 4);
33 EXPECT_EQ(std::string_view(data).substr(0, 4), buf);
34
35 // Ensure that the max data size inline doesn't dynamically allocate
36 constexpr std::size_t max_size = sizeof(StrBuf) - sizeof(std::size_t);
37 buf.append(max_size - 4);
38 EXPECT_EQ(buf.begin(), old_ptr);
39 EXPECT_EQ(buf.size(), max_size);
40}
41
42TEST(StrBuf, DynamicAppend)
43{
44 constexpr std::size_t seg = 15;
45
46 StrBuf buf;
47 auto old_ptr = buf.begin();
48 std::copy(data.begin(), data.begin() + seg, buf.append(seg));
49
50 // Ensure that inline -> dynamic is working
51 std::copy(data.begin() + seg, data.end(), buf.append(data.size() - seg));
52 EXPECT_NE(buf.begin(), old_ptr);
53 EXPECT_EQ(data, buf);
54 EXPECT_EQ(data.size(), buf.size());
55
56 // Ensure dynamic allocation is large enough to allow additional
57 // small appends with no reallocation
58 old_ptr = buf.begin();
59 std::copy(data.begin(), data.begin() + seg, buf.append(seg));
60 EXPECT_EQ(buf.begin(), old_ptr);
61 EXPECT_EQ(data.size() + seg, buf.size());
62 EXPECT_EQ(data.substr(0, seg), std::string_view{buf}.substr(data.size()));
63
64 // Ensure new dynamic allocations copy
65 std::copy(data.begin() + seg, data.end(), buf.append(data.size() - seg));
66 EXPECT_NE(buf.begin(), old_ptr);
67 EXPECT_EQ(data.size() << 1, buf.size());
68 EXPECT_EQ(data, std::string_view{buf}.substr(0, data.size()));
69 EXPECT_EQ(data, std::string_view{buf}.substr(data.size()));
70}
71
72TEST(StrBuf, CopiesInline)
73{
74 StrBuf buf1;
75 buf1.append(1)[0] = 'a';
76 StrBuf buf2 = buf1;
77 EXPECT_EQ(buf1, buf2);
78 buf1.append(1)[0] = 'b';
79 StrBuf buf3 = buf1;
80 EXPECT_EQ("ab", buf3);
81 EXPECT_EQ("ab", buf1);
82 EXPECT_EQ("a", buf2);
83 buf3 = buf2;
84 EXPECT_EQ("a", buf3);
85 EXPECT_EQ("ab", buf1);
86 EXPECT_EQ("a", buf2);
87}
88
89TEST(StrBuf, MoveInline)
90{
91 StrBuf buf1;
92 buf1.append(1)[0] = 'a';
93 StrBuf buf2 = std::move(buf1);
94 EXPECT_EQ("a", std::string_view{buf2});
95 buf2.append(1)[0] = 'b';
96 // NOLINTNEXTLINE(clang-analyzer-cplusplus.Move)
97 EXPECT_EQ(0, buf1.size());
98 StrBuf buf3 = buf1;
99 EXPECT_EQ(0, buf3.size());
100 buf3 = std::move(buf2);
101 // NOLINTNEXTLINE(clang-analyzer-cplusplus.Move)
102 EXPECT_EQ(0, buf2.size());
103 EXPECT_EQ("ab", std::string_view{buf3});
104}
105
106TEST(StrBuf, CopyInlToDyn)
107{
108 StrBuf buf1;
109 buf1.append(1)[0] = 'a';
110 StrBuf buf2;
111 buf2.append(sizeof(StrBuf) + 10);
112 buf2 = buf1;
113 EXPECT_EQ("a", buf2);
114}
115
116TEST(StrBuf, MoveInlToDyn)
117{
118 StrBuf buf1;
119 buf1.append(1)[0] = 'a';
120 StrBuf buf2;
121 buf2.append(sizeof(StrBuf) + 10);
122 // NOLINTNEXTLINE(clang-analyzer-cplusplus.Move)
123 buf2 = std::move(buf1);
124 EXPECT_EQ("", buf1);
125 EXPECT_EQ("a", buf2);
126}
127
128TEST(StrBuf, MoveDynToInl)
129{
130 StrBuf buf1;
131 std::copy(data.begin(), data.end(), buf1.append(data.size()));
132 StrBuf buf2;
133 buf2.append(1)[0] = 'a';
134 // NOLINTNEXTLINE(clang-analyzer-cplusplus.Move)
135 buf2 = std::move(buf1);
136 EXPECT_EQ("", buf1);
137 EXPECT_EQ(data, buf2);
138}
139
140TEST(StrBuf, MoveDynToDyn)
141{
142 StrBuf buf1;
143 std::copy(data.begin(), data.end(), buf1.append(data.size()));
144 StrBuf buf2;
145 buf2.append(data.size());
146 // NOLINTNEXTLINE(clang-analyzer-cplusplus.Move)
147 buf2 = std::move(buf1);
148 EXPECT_EQ("", buf1);
149 EXPECT_EQ(data, buf2);
150}
151
152TEST(StrBuf, CopyDynToInl)
153{
154 StrBuf buf1;
155 buf1.append(data.size());
156 buf1.reset();
157 buf1.append(1)[0] = 'a';
158 StrBuf buf2 = buf1;
159 StrBuf buf3;
160 buf3.append(1)[0] = 'b';
161 buf3 = buf1;
162 EXPECT_EQ("a", buf1);
163 EXPECT_EQ("a", buf2);
164 EXPECT_EQ("a", buf3);
165}
166
167TEST(StrBuf, CopyDynToDyn)
168{
169 StrBuf buf1;
170 std::copy(data.begin(), data.end(), buf1.append(data.size()));
171 std::copy(data.begin(), data.end(), buf1.append(data.size()));
172 StrBuf buf2 = buf1;
173 StrBuf buf3;
174 std::copy(data.begin(), data.end(), buf3.append(data.size()));
175 buf3 = buf1;
176 EXPECT_EQ(buf2, buf1);
177 EXPECT_EQ(buf3, buf1);
178 buf3.append(1)[0] = 'a';
179 buf1 = buf3;
180 EXPECT_EQ(buf3, buf1);
181}
182
183} // namespace stdplus