1 /*  Copyright (c) 2018 Michael Hansen
2 
3     Permission is hereby granted, free of charge, to any person obtaining a
4     copy of this software and associated documentation files (the "Software"),
5     to deal in the Software without restriction, including without limitation
6     the rights to use, copy, modify, merge, publish, distribute, sublicense,
7     and/or sell copies of the Software, and to permit persons to whom the
8     Software is furnished to do so, subject to the following conditions:
9 
10     The above copyright notice and this permission notice shall be included in
11     all copies or substantial portions of the Software.
12 
13     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19     DEALINGS IN THE SOFTWARE. */
20 
21 #include "st_string.h"
22 
23 #include <gtest/gtest.h>
24 
25 namespace ST
26 {
27     // Teach GTest how to print an ST::buffer
PrintTo(const ST::char_buffer & str,std::ostream * os)28     static void PrintTo(const ST::char_buffer &str, std::ostream *os)
29     {
30         *os << "ST::char_buffer{\"" << str.data() << "\"}";
31     }
32 
PrintTo(const ST::wchar_buffer & str,std::ostream * os)33     static void PrintTo(const ST::wchar_buffer &str, std::ostream *os)
34     {
35         ST::string u8str = str;
36         *os << "ST::wchar_buffer{\"" << u8str.c_str() << "\"}";
37     }
38 
PrintTo(const ST::utf16_buffer & str,std::ostream * os)39     static void PrintTo(const ST::utf16_buffer &str, std::ostream *os)
40     {
41         ST::string u8str = str;
42         *os << "ST::utf16_buffer{\"" << u8str.c_str() << "\"}";
43     }
44 
PrintTo(const ST::utf32_buffer & str,std::ostream * os)45     static void PrintTo(const ST::utf32_buffer &str, std::ostream *os)
46     {
47         ST::string u8str = str;
48         *os << "ST::utf32_buffer{\"" << u8str.c_str() << "\"}";
49     }
50 }
51 
52 /* Utility for comparing char16_t/char32_t buffers */
53 template <typename char_T>
T_strcmp(const char_T * left,const char_T * right)54 static int T_strcmp(const char_T *left, const char_T *right)
55 {
56     for ( ;; ) {
57         if (*left != *right)
58             return *left - *right;
59         if (*left == 0)
60             return 0;
61 
62         ++left;
63         ++right;
64     }
65 }
66 
TEST(char_buffer,helpers)67 TEST(char_buffer, helpers)
68 {
69     /* Ensure the utilities for testing the module function properly */
70     EXPECT_EQ(0, T_strcmp("abc", "abc"));
71     EXPECT_LT(0, T_strcmp("abc", "aba"));
72     EXPECT_GT(0, T_strcmp("abc", "abe"));
73     EXPECT_LT(0, T_strcmp("abc", "ab"));
74     EXPECT_GT(0, T_strcmp("abc", "abcd"));
75     EXPECT_EQ(0, T_strcmp("", ""));
76     EXPECT_GT(0, T_strcmp("", "a"));
77     EXPECT_LT(0, T_strcmp("a", ""));
78 }
79 
TEST(char_buffer,utility)80 TEST(char_buffer, utility)
81 {
82     // Literal constructors
83     EXPECT_EQ(ST::char_buffer(), ST_CHAR_LITERAL(""));
84     EXPECT_EQ(ST::wchar_buffer(), ST_WCHAR_LITERAL(""));
85     EXPECT_EQ(ST::utf16_buffer(), ST_UTF16_LITERAL(""));
86     EXPECT_EQ(ST::utf32_buffer(), ST_UTF32_LITERAL(""));
87     EXPECT_EQ(ST::char_buffer("abc", 3), ST_CHAR_LITERAL("abc"));
88     EXPECT_EQ(ST::wchar_buffer(L"abc", 3), ST_WCHAR_LITERAL("abc"));
89     EXPECT_EQ(ST::utf16_buffer(u"abc", 3), ST_UTF16_LITERAL("abc"));
90     EXPECT_EQ(ST::utf32_buffer(U"abc", 3), ST_UTF32_LITERAL("abc"));
91 
92     EXPECT_EQ(0U, ST::char_buffer().size());
93     EXPECT_TRUE(ST::char_buffer().empty());
94     EXPECT_EQ(0U, ST::wchar_buffer().size());
95     EXPECT_TRUE(ST::wchar_buffer().empty());
96     EXPECT_EQ(0U, ST::utf16_buffer().size());
97     EXPECT_TRUE(ST::utf16_buffer().empty());
98     EXPECT_EQ(0U, ST::utf32_buffer().size());
99     EXPECT_TRUE(ST::utf32_buffer().empty());
100 }
101 
TEST(char_buffer,stack_construction)102 TEST(char_buffer, stack_construction)
103 {
104     // If these change, this test may need to be updated to match
105     ASSERT_EQ(16, ST_MAX_SSO_LENGTH);
106     ASSERT_EQ(48, ST_MAX_SSO_SIZE);
107 
108     char empty[] = {0};
109     wchar_t emptyw[] = {0};
110     char16_t empty16[] = {0};
111     char32_t empty32[] = {0};
112 
113     // Stack allocated
114     char shortstr[] = "Short";
115     wchar_t shortw[] = L"Short";
116     char16_t short16[] = {'S', 'h', 'o', 'r', 't', 0};
117     char32_t short32[] = {'S', 'h', 'o', 'r', 't', 0};
118 
119     // Heap allocated
120     char longstr[] = "0123456789abcdefghij";
121     wchar_t longw[] = L"0123456789abcdefghij";
122     char16_t long16[] = {'0','1','2','3','4','5','6','7','8','9',
123                          'a','b','c','d','e','f','g','h','i','j',0};
124     char32_t long32[] = {'0','1','2','3','4','5','6','7','8','9',
125                          'a','b','c','d','e','f','g','h','i','j',0};
126 
127     ST::char_buffer cb_empty(empty, 0);
128     EXPECT_EQ(0, T_strcmp(cb_empty.data(), empty));
129     EXPECT_EQ(0U, cb_empty.size());
130     EXPECT_TRUE(cb_empty.empty());
131     ST::wchar_buffer wcb_empty(emptyw, 0);
132     EXPECT_EQ(0, T_strcmp(wcb_empty.data(), emptyw));
133     EXPECT_EQ(0U, wcb_empty.size());
134     EXPECT_TRUE(wcb_empty.empty());
135     ST::utf16_buffer cb16_empty(empty16, 0);
136     EXPECT_EQ(0, T_strcmp(cb16_empty.data(), empty16));
137     EXPECT_EQ(0U, cb16_empty.size());
138     EXPECT_TRUE(cb16_empty.empty());
139     ST::utf32_buffer cb32_empty(empty32, 0);
140     EXPECT_EQ(0, T_strcmp(cb32_empty.data(), empty32));
141     EXPECT_EQ(0U, cb32_empty.size());
142     EXPECT_TRUE(cb32_empty.empty());
143 
144     ST::char_buffer cb_short(shortstr, 5);
145     EXPECT_EQ(0, T_strcmp(cb_short.data(), shortstr));
146     EXPECT_EQ(5U, cb_short.size());
147     EXPECT_FALSE(cb_short.empty());
148     ST::wchar_buffer wcb_short(shortw, 5);
149     EXPECT_EQ(0, T_strcmp(wcb_short.data(), shortw));
150     EXPECT_EQ(5U, wcb_short.size());
151     EXPECT_FALSE(wcb_short.empty());
152     ST::utf16_buffer cb16_short(short16, 5);
153     EXPECT_EQ(0, T_strcmp(cb16_short.data(), short16));
154     EXPECT_EQ(5U, cb16_short.size());
155     EXPECT_FALSE(cb_short.empty());
156     ST::utf32_buffer cb32_short(short32, 5);
157     EXPECT_EQ(0, T_strcmp(cb32_short.data(), short32));
158     EXPECT_EQ(5U, cb32_short.size());
159     EXPECT_FALSE(cb32_short.empty());
160 
161     ST::char_buffer cb_long(longstr, 20);
162     EXPECT_EQ(0, T_strcmp(cb_long.data(), longstr));
163     EXPECT_EQ(20U, cb_long.size());
164     EXPECT_FALSE(cb_long.empty());
165     ST::wchar_buffer wcb_long(longw, 20);
166     EXPECT_EQ(0, T_strcmp(wcb_long.data(), longw));
167     EXPECT_EQ(20U, wcb_long.size());
168     EXPECT_FALSE(wcb_long.empty());
169     ST::utf16_buffer cb16_long(long16, 20);
170     EXPECT_EQ(0, T_strcmp(cb16_long.data(), long16));
171     EXPECT_EQ(20U, cb16_long.size());
172     EXPECT_FALSE(cb_long.empty());
173     ST::utf32_buffer cb32_long(long32, 20);
174     EXPECT_EQ(0, T_strcmp(cb32_long.data(), long32));
175     EXPECT_EQ(20U, cb32_long.size());
176     EXPECT_FALSE(cb32_long.empty());
177 }
178 
179 // Only testing char and wchar_t for simplicity on compilers that
180 // don't support utf-16 and utf-32 literals yet
TEST(char_buffer,copy)181 TEST(char_buffer, copy)
182 {
183     // If these change, this test may need to be updated to match
184     ASSERT_EQ(16, ST_MAX_SSO_LENGTH);
185     ASSERT_EQ(48, ST_MAX_SSO_SIZE);
186 
187     ST::char_buffer cb1("Test", 4);
188     ST::wchar_buffer wcb1(L"Test", 4);
189 
190     ST::char_buffer dest(cb1);
191     EXPECT_EQ(0, T_strcmp(dest.data(), "Test"));
192     EXPECT_EQ(4U, dest.size());
193     ST::wchar_buffer wdest(wcb1);
194     EXPECT_EQ(0, T_strcmp(wdest.data(), L"Test"));
195     EXPECT_EQ(4U, wdest.size());
196 
197     ST::char_buffer cb2("operator=", 9);
198     ST::wchar_buffer wcb2(L"operator=", 9);
199 
200     dest = cb2;
201     EXPECT_EQ(0, T_strcmp(dest.data(), "operator="));
202     EXPECT_EQ(9U, dest.size());
203     wdest = wcb2;
204     EXPECT_EQ(0, T_strcmp(wdest.data(), L"operator="));
205     EXPECT_EQ(9U, wdest.size());
206 
207     ST::char_buffer cb3("0123456789abcdefghij", 20);
208     ST::wchar_buffer wcb3(L"0123456789abcdefghij", 20);
209 
210     ST::char_buffer dest2(cb3);
211     EXPECT_EQ(0, T_strcmp(dest2.data(), "0123456789abcdefghij"));
212     EXPECT_EQ(20U, dest2.size());
213     ST::wchar_buffer wdest2(wcb3);
214     EXPECT_EQ(0, T_strcmp(wdest2.data(), L"0123456789abcdefghij"));
215     EXPECT_EQ(20U, wdest2.size());
216 
217     ST::char_buffer cb4("9876543210zyxwvutsrqponm", 24);
218     ST::wchar_buffer wcb4(L"9876543210zyxwvutsrqponm", 24);
219 
220     dest2 = cb4;
221     EXPECT_EQ(0, T_strcmp(dest2.data(), "9876543210zyxwvutsrqponm"));
222     EXPECT_EQ(24U, dest2.size());
223     wdest2 = wcb4;
224     EXPECT_EQ(0, T_strcmp(wdest2.data(), L"9876543210zyxwvutsrqponm"));
225     EXPECT_EQ(24U, wdest2.size());
226 }
227 
TEST(char_buffer,move)228 TEST(char_buffer, move)
229 {
230     // If these change, this test may need to be updated to match
231     ASSERT_EQ(16, ST_MAX_SSO_LENGTH);
232     ASSERT_EQ(48, ST_MAX_SSO_SIZE);
233 
234     ST::char_buffer cb1("Test", 4);
235     ST::wchar_buffer wcb1(L"Test", 4);
236 
237     ST::char_buffer dest(std::move(cb1));
238     EXPECT_EQ(0, T_strcmp(dest.data(), "Test"));
239     EXPECT_EQ(4U, dest.size());
240     ST::wchar_buffer wdest(std::move(wcb1));
241     EXPECT_EQ(0, T_strcmp(wdest.data(), L"Test"));
242     EXPECT_EQ(4U, wdest.size());
243 
244     ST::char_buffer cb2("operator=", 9);
245     ST::wchar_buffer wcb2(L"operator=", 9);
246 
247     dest = std::move(cb2);
248     EXPECT_EQ(0, T_strcmp(dest.data(), "operator="));
249     EXPECT_EQ(9U, dest.size());
250     wdest = std::move(wcb2);
251     EXPECT_EQ(0, T_strcmp(wdest.data(), L"operator="));
252     EXPECT_EQ(9U, wdest.size());
253 
254     ST::char_buffer cb3("0123456789abcdefghij", 20);
255     ST::wchar_buffer wcb3(L"0123456789abcdefghij", 20);
256 
257     ST::char_buffer dest2(std::move(cb3));
258     EXPECT_EQ(0, T_strcmp(dest2.data(), "0123456789abcdefghij"));
259     EXPECT_EQ(20U, dest2.size());
260     ST::wchar_buffer wdest2(std::move(wcb3));
261     EXPECT_EQ(0, T_strcmp(wdest2.data(), L"0123456789abcdefghij"));
262     EXPECT_EQ(20U, wdest2.size());
263 
264     ST::char_buffer cb4("9876543210zyxwvutsrqponm", 24);
265     ST::wchar_buffer wcb4(L"9876543210zyxwvutsrqponm", 24);
266 
267     dest2 = std::move(cb4);
268     EXPECT_EQ(0, T_strcmp(dest2.data(), "9876543210zyxwvutsrqponm"));
269     EXPECT_EQ(24U, dest2.size());
270     wdest2 = std::move(wcb4);
271     EXPECT_EQ(0, T_strcmp(wdest2.data(), L"9876543210zyxwvutsrqponm"));
272     EXPECT_EQ(24U, wdest2.size());
273 }
274 
275 #if defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ > 5))
276 #   pragma GCC diagnostic push
277 #   pragma GCC diagnostic ignored "-Wself-move"
278 #   if defined(__clang__) && (__clang_major__ > 6)
279 #       pragma GCC diagnostic ignored "-Wself-assign-overloaded"
280 #   endif
281 #endif
282 
TEST(char_buffer,self_assign)283 TEST(char_buffer, self_assign)
284 {
285     // If this changes, this test may need to be updated to match
286     ASSERT_EQ(16, ST_MAX_SSO_LENGTH);
287 
288     ST::char_buffer sbuf;
289     sbuf = sbuf;
290     EXPECT_EQ(0, T_strcmp(sbuf.data(), ""));
291 
292     ST::char_buffer shortbuf("0123456789", 10);
293     sbuf = shortbuf;
294     EXPECT_EQ(0, T_strcmp(sbuf.data(), "0123456789"));
295     sbuf = sbuf;
296     EXPECT_EQ(0, T_strcmp(sbuf.data(), "0123456789"));
297     sbuf = std::move(sbuf);
298     // Content not guaranteed after self-move
299 
300     ST::char_buffer longbuf("0123456789abcdefghij", 20);
301     sbuf = longbuf;
302     EXPECT_EQ(0, T_strcmp(sbuf.data(), "0123456789abcdefghij"));
303     sbuf = sbuf;
304     EXPECT_EQ(0, T_strcmp(sbuf.data(), "0123456789abcdefghij"));
305     sbuf = std::move(sbuf);
306     // Content not guaranteed after self-move
307 }
308 
309 #if defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ > 5))
310 #   pragma GCC diagnostic pop
311 #endif
312 
TEST(char_buffer,compare)313 TEST(char_buffer, compare)
314 {
315     // Same length, chars
316     EXPECT_EQ(ST::char_buffer("abc", 3), ST::char_buffer("abc", 3));
317     EXPECT_NE(ST::char_buffer("abc", 3), ST::char_buffer("abd", 3));
318     EXPECT_NE(ST::char_buffer("abc", 3), ST::char_buffer("abb", 3));
319     EXPECT_NE(ST::char_buffer("abC", 3), ST::char_buffer("abc", 3));
320     EXPECT_NE(ST::char_buffer("Abc", 3), ST::char_buffer("abc", 3));
321     EXPECT_EQ(ST::char_buffer("", 0), ST::char_buffer());
322 
323     // Same length, wchars
324     EXPECT_EQ(ST::wchar_buffer(L"abc", 3), ST::wchar_buffer(L"abc", 3));
325     EXPECT_NE(ST::wchar_buffer(L"abc", 3), ST::wchar_buffer(L"abd", 3));
326     EXPECT_NE(ST::wchar_buffer(L"abc", 3), ST::wchar_buffer(L"abb", 3));
327     EXPECT_NE(ST::wchar_buffer(L"abC", 3), ST::wchar_buffer(L"abc", 3));
328     EXPECT_NE(ST::wchar_buffer(L"Abc", 3), ST::wchar_buffer(L"abc", 3));
329     EXPECT_EQ(ST::wchar_buffer(L"", 0), ST::wchar_buffer());
330 
331     // Mismatched length, chars
332     EXPECT_NE(ST::char_buffer("abc", 3), ST::char_buffer("ab", 2));
333     EXPECT_NE(ST::char_buffer("abc", 3), ST::char_buffer("abcd", 4));
334     EXPECT_NE(ST::char_buffer("abc", 3), ST::char_buffer("", 0));
335     EXPECT_NE(ST::char_buffer(), ST::char_buffer("abc", 3));
336 
337     // Mismatched length, wchars
338     EXPECT_NE(ST::wchar_buffer(L"abc", 3), ST::wchar_buffer(L"ab", 2));
339     EXPECT_NE(ST::wchar_buffer(L"abc", 3), ST::wchar_buffer(L"abcd", 4));
340     EXPECT_NE(ST::wchar_buffer(L"abc", 3), ST::wchar_buffer(L"", 0));
341     EXPECT_NE(ST::wchar_buffer(), ST::wchar_buffer(L"abc", 3));
342 }
343 
TEST(char_buffer,udls)344 TEST(char_buffer, udls)
345 {
346     using namespace ST::literals;
347 
348     // Only need to test the UDL usage -- the rest is covered above
349     EXPECT_EQ(ST_CHAR_LITERAL(""), ""_stbuf);
350     EXPECT_EQ(ST_CHAR_LITERAL("Test"), "Test"_stbuf);
351     EXPECT_EQ(ST_WCHAR_LITERAL("Test"), L"Test"_stbuf);
352     EXPECT_EQ(ST_UTF16_LITERAL("Test"), u"Test"_stbuf);
353     EXPECT_EQ(ST_UTF32_LITERAL("Test"), U"Test"_stbuf);
354 #ifdef ST_HAVE_CXX20_CHAR8_TYPES
355     EXPECT_EQ(ST_CHAR_LITERAL("Test"), u8"Test"_stbuf);
356 #endif
357 }
358