1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // Unit tests for all join.h functions
16
17 #include "absl/strings/str_join.h"
18
19 #include <cstddef>
20 #include <cstdint>
21 #include <cstdio>
22 #include <functional>
23 #include <initializer_list>
24 #include <map>
25 #include <memory>
26 #include <ostream>
27 #include <tuple>
28 #include <type_traits>
29 #include <vector>
30
31 #include "gtest/gtest.h"
32 #include "absl/base/macros.h"
33 #include "absl/memory/memory.h"
34 #include "absl/strings/str_cat.h"
35 #include "absl/strings/str_split.h"
36
37 namespace {
38
TEST(StrJoin,APIExamples)39 TEST(StrJoin, APIExamples) {
40 {
41 // Collection of strings
42 std::vector<std::string> v = {"foo", "bar", "baz"};
43 EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-"));
44 }
45
46 {
47 // Collection of absl::string_view
48 std::vector<absl::string_view> v = {"foo", "bar", "baz"};
49 EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-"));
50 }
51
52 {
53 // Collection of const char*
54 std::vector<const char*> v = {"foo", "bar", "baz"};
55 EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-"));
56 }
57
58 {
59 // Collection of non-const char*
60 std::string a = "foo", b = "bar", c = "baz";
61 std::vector<char*> v = {&a[0], &b[0], &c[0]};
62 EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-"));
63 }
64
65 {
66 // Collection of ints
67 std::vector<int> v = {1, 2, 3, -4};
68 EXPECT_EQ("1-2-3--4", absl::StrJoin(v, "-"));
69 }
70
71 {
72 // Literals passed as a std::initializer_list
73 std::string s = absl::StrJoin({"a", "b", "c"}, "-");
74 EXPECT_EQ("a-b-c", s);
75 }
76 {
77 // Join a std::tuple<T...>.
78 std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-");
79 EXPECT_EQ("123-abc-0.456", s);
80 }
81
82 {
83 // Collection of unique_ptrs
84 std::vector<std::unique_ptr<int>> v;
85 v.emplace_back(new int(1));
86 v.emplace_back(new int(2));
87 v.emplace_back(new int(3));
88 EXPECT_EQ("1-2-3", absl::StrJoin(v, "-"));
89 }
90
91 {
92 // Array of ints
93 const int a[] = {1, 2, 3, -4};
94 EXPECT_EQ("1-2-3--4", absl::StrJoin(a, a + ABSL_ARRAYSIZE(a), "-"));
95 }
96
97 {
98 // Collection of pointers
99 int x = 1, y = 2, z = 3;
100 std::vector<int*> v = {&x, &y, &z};
101 EXPECT_EQ("1-2-3", absl::StrJoin(v, "-"));
102 }
103
104 {
105 // Collection of pointers to pointers
106 int x = 1, y = 2, z = 3;
107 int *px = &x, *py = &y, *pz = &z;
108 std::vector<int**> v = {&px, &py, &pz};
109 EXPECT_EQ("1-2-3", absl::StrJoin(v, "-"));
110 }
111
112 {
113 // Collection of pointers to std::string
114 std::string a("a"), b("b");
115 std::vector<std::string*> v = {&a, &b};
116 EXPECT_EQ("a-b", absl::StrJoin(v, "-"));
117 }
118
119 {
120 // A std::map, which is a collection of std::pair<>s.
121 std::map<std::string, int> m = {{"a", 1}, {"b", 2}, {"c", 3}};
122 EXPECT_EQ("a=1,b=2,c=3", absl::StrJoin(m, ",", absl::PairFormatter("=")));
123 }
124
125 {
126 // Shows absl::StrSplit and absl::StrJoin working together. This example is
127 // equivalent to s/=/-/g.
128 const std::string s = "a=b=c=d";
129 EXPECT_EQ("a-b-c-d", absl::StrJoin(absl::StrSplit(s, "="), "-"));
130 }
131
132 //
133 // A few examples of edge cases
134 //
135
136 {
137 // Empty range yields an empty string.
138 std::vector<std::string> v;
139 EXPECT_EQ("", absl::StrJoin(v, "-"));
140 }
141
142 {
143 // A range of 1 element gives a string with that element but no
144 // separator.
145 std::vector<std::string> v = {"foo"};
146 EXPECT_EQ("foo", absl::StrJoin(v, "-"));
147 }
148
149 {
150 // A range with a single empty string element
151 std::vector<std::string> v = {""};
152 EXPECT_EQ("", absl::StrJoin(v, "-"));
153 }
154
155 {
156 // A range with 2 elements, one of which is an empty string
157 std::vector<std::string> v = {"a", ""};
158 EXPECT_EQ("a-", absl::StrJoin(v, "-"));
159 }
160
161 {
162 // A range with 2 empty elements.
163 std::vector<std::string> v = {"", ""};
164 EXPECT_EQ("-", absl::StrJoin(v, "-"));
165 }
166
167 {
168 // A std::vector of bool.
169 std::vector<bool> v = {true, false, true};
170 EXPECT_EQ("1-0-1", absl::StrJoin(v, "-"));
171 }
172 }
173
TEST(StrJoin,CustomFormatter)174 TEST(StrJoin, CustomFormatter) {
175 std::vector<std::string> v{"One", "Two", "Three"};
176 {
177 std::string joined =
178 absl::StrJoin(v, "", [](std::string* out, const std::string& in) {
179 absl::StrAppend(out, "(", in, ")");
180 });
181 EXPECT_EQ("(One)(Two)(Three)", joined);
182 }
183 {
184 class ImmovableFormatter {
185 public:
186 void operator()(std::string* out, const std::string& in) {
187 absl::StrAppend(out, "(", in, ")");
188 }
189 ImmovableFormatter() {}
190 ImmovableFormatter(const ImmovableFormatter&) = delete;
191 };
192 EXPECT_EQ("(One)(Two)(Three)", absl::StrJoin(v, "", ImmovableFormatter()));
193 }
194 {
195 class OverloadedFormatter {
196 public:
197 void operator()(std::string* out, const std::string& in) {
198 absl::StrAppend(out, "(", in, ")");
199 }
200 void operator()(std::string* out, const std::string& in) const {
201 absl::StrAppend(out, "[", in, "]");
202 }
203 };
204 EXPECT_EQ("(One)(Two)(Three)", absl::StrJoin(v, "", OverloadedFormatter()));
205 const OverloadedFormatter fmt = {};
206 EXPECT_EQ("[One][Two][Three]", absl::StrJoin(v, "", fmt));
207 }
208 }
209
210 //
211 // Tests the Formatters
212 //
213
TEST(AlphaNumFormatter,FormatterAPI)214 TEST(AlphaNumFormatter, FormatterAPI) {
215 // Not an exhaustive test. See strings/strcat_test.h for the exhaustive test
216 // of what AlphaNum can convert.
217 auto f = absl::AlphaNumFormatter();
218 std::string s;
219 f(&s, "Testing: ");
220 f(&s, static_cast<int>(1));
221 f(&s, static_cast<int16_t>(2));
222 f(&s, static_cast<int64_t>(3));
223 f(&s, static_cast<float>(4));
224 f(&s, static_cast<double>(5));
225 f(&s, static_cast<unsigned>(6));
226 f(&s, static_cast<size_t>(7));
227 f(&s, absl::string_view(" OK"));
228 EXPECT_EQ("Testing: 1234567 OK", s);
229 }
230
231 // Make sure people who are mistakenly using std::vector<bool> even though
232 // they're not memory-constrained can use absl::AlphaNumFormatter().
TEST(AlphaNumFormatter,VectorOfBool)233 TEST(AlphaNumFormatter, VectorOfBool) {
234 auto f = absl::AlphaNumFormatter();
235 std::string s;
236 std::vector<bool> v = {true, false, true};
237 f(&s, *v.cbegin());
238 f(&s, *v.begin());
239 f(&s, v[1]);
240 EXPECT_EQ("110", s);
241 }
242
TEST(AlphaNumFormatter,AlphaNum)243 TEST(AlphaNumFormatter, AlphaNum) {
244 auto f = absl::AlphaNumFormatter();
245 std::string s;
246 f(&s, absl::AlphaNum("hello"));
247 EXPECT_EQ("hello", s);
248 }
249
250 struct StreamableType {
251 std::string contents;
252 };
operator <<(std::ostream & os,const StreamableType & t)253 inline std::ostream& operator<<(std::ostream& os, const StreamableType& t) {
254 os << "Streamable:" << t.contents;
255 return os;
256 }
257
TEST(StreamFormatter,FormatterAPI)258 TEST(StreamFormatter, FormatterAPI) {
259 auto f = absl::StreamFormatter();
260 std::string s;
261 f(&s, "Testing: ");
262 f(&s, static_cast<int>(1));
263 f(&s, static_cast<int16_t>(2));
264 f(&s, static_cast<int64_t>(3));
265 f(&s, static_cast<float>(4));
266 f(&s, static_cast<double>(5));
267 f(&s, static_cast<unsigned>(6));
268 f(&s, static_cast<size_t>(7));
269 f(&s, absl::string_view(" OK "));
270 StreamableType streamable = {"object"};
271 f(&s, streamable);
272 EXPECT_EQ("Testing: 1234567 OK Streamable:object", s);
273 }
274
275 // A dummy formatter that wraps each element in parens. Used in some tests
276 // below.
277 struct TestingParenFormatter {
278 template <typename T>
operator ()__anon84ed98f50111::TestingParenFormatter279 void operator()(std::string* s, const T& t) {
280 absl::StrAppend(s, "(", t, ")");
281 }
282 };
283
TEST(PairFormatter,FormatterAPI)284 TEST(PairFormatter, FormatterAPI) {
285 {
286 // Tests default PairFormatter(sep) that uses AlphaNumFormatter for the
287 // 'first' and 'second' members.
288 const auto f = absl::PairFormatter("=");
289 std::string s;
290 f(&s, std::make_pair("a", "b"));
291 f(&s, std::make_pair(1, 2));
292 EXPECT_EQ("a=b1=2", s);
293 }
294
295 {
296 // Tests using a custom formatter for the 'first' and 'second' members.
297 auto f = absl::PairFormatter(TestingParenFormatter(), "=",
298 TestingParenFormatter());
299 std::string s;
300 f(&s, std::make_pair("a", "b"));
301 f(&s, std::make_pair(1, 2));
302 EXPECT_EQ("(a)=(b)(1)=(2)", s);
303 }
304 }
305
TEST(DereferenceFormatter,FormatterAPI)306 TEST(DereferenceFormatter, FormatterAPI) {
307 {
308 // Tests wrapping the default AlphaNumFormatter.
309 const absl::strings_internal::DereferenceFormatterImpl<
310 absl::strings_internal::AlphaNumFormatterImpl>
311 f;
312 int x = 1, y = 2, z = 3;
313 std::string s;
314 f(&s, &x);
315 f(&s, &y);
316 f(&s, &z);
317 EXPECT_EQ("123", s);
318 }
319
320 {
321 // Tests wrapping std::string's default formatter.
322 absl::strings_internal::DereferenceFormatterImpl<
323 absl::strings_internal::DefaultFormatter<std::string>::Type>
324 f;
325
326 std::string x = "x";
327 std::string y = "y";
328 std::string z = "z";
329 std::string s;
330 f(&s, &x);
331 f(&s, &y);
332 f(&s, &z);
333 EXPECT_EQ(s, "xyz");
334 }
335
336 {
337 // Tests wrapping a custom formatter.
338 auto f = absl::DereferenceFormatter(TestingParenFormatter());
339 int x = 1, y = 2, z = 3;
340 std::string s;
341 f(&s, &x);
342 f(&s, &y);
343 f(&s, &z);
344 EXPECT_EQ("(1)(2)(3)", s);
345 }
346
347 {
348 absl::strings_internal::DereferenceFormatterImpl<
349 absl::strings_internal::AlphaNumFormatterImpl>
350 f;
351 auto x = std::unique_ptr<int>(new int(1));
352 auto y = std::unique_ptr<int>(new int(2));
353 auto z = std::unique_ptr<int>(new int(3));
354 std::string s;
355 f(&s, x);
356 f(&s, y);
357 f(&s, z);
358 EXPECT_EQ("123", s);
359 }
360 }
361
362 //
363 // Tests the interfaces for the 4 public Join function overloads. The semantics
364 // of the algorithm is covered in the above APIExamples test.
365 //
TEST(StrJoin,PublicAPIOverloads)366 TEST(StrJoin, PublicAPIOverloads) {
367 std::vector<std::string> v = {"a", "b", "c"};
368
369 // Iterators + formatter
370 EXPECT_EQ("a-b-c",
371 absl::StrJoin(v.begin(), v.end(), "-", absl::AlphaNumFormatter()));
372 // Range + formatter
373 EXPECT_EQ("a-b-c", absl::StrJoin(v, "-", absl::AlphaNumFormatter()));
374 // Iterators, no formatter
375 EXPECT_EQ("a-b-c", absl::StrJoin(v.begin(), v.end(), "-"));
376 // Range, no formatter
377 EXPECT_EQ("a-b-c", absl::StrJoin(v, "-"));
378 }
379
TEST(StrJoin,Array)380 TEST(StrJoin, Array) {
381 const absl::string_view a[] = {"a", "b", "c"};
382 EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
383 }
384
TEST(StrJoin,InitializerList)385 TEST(StrJoin, InitializerList) {
386 { EXPECT_EQ("a-b-c", absl::StrJoin({"a", "b", "c"}, "-")); }
387
388 {
389 auto a = {"a", "b", "c"};
390 EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
391 }
392
393 {
394 std::initializer_list<const char*> a = {"a", "b", "c"};
395 EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
396 }
397
398 {
399 std::initializer_list<std::string> a = {"a", "b", "c"};
400 EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
401 }
402
403 {
404 std::initializer_list<absl::string_view> a = {"a", "b", "c"};
405 EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
406 }
407
408 {
409 // Tests initializer_list with a non-default formatter
410 auto a = {"a", "b", "c"};
411 TestingParenFormatter f;
412 EXPECT_EQ("(a)-(b)-(c)", absl::StrJoin(a, "-", f));
413 }
414
415 {
416 // initializer_list of ints
417 EXPECT_EQ("1-2-3", absl::StrJoin({1, 2, 3}, "-"));
418 }
419
420 {
421 // Tests initializer_list of ints with a non-default formatter
422 auto a = {1, 2, 3};
423 TestingParenFormatter f;
424 EXPECT_EQ("(1)-(2)-(3)", absl::StrJoin(a, "-", f));
425 }
426 }
427
TEST(StrJoin,Tuple)428 TEST(StrJoin, Tuple) {
429 EXPECT_EQ("", absl::StrJoin(std::make_tuple(), "-"));
430 EXPECT_EQ("hello", absl::StrJoin(std::make_tuple("hello"), "-"));
431
432 int x(10);
433 std::string y("hello");
434 double z(3.14);
435 EXPECT_EQ("10-hello-3.14", absl::StrJoin(std::make_tuple(x, y, z), "-"));
436
437 // Faster! Faster!!
438 EXPECT_EQ("10-hello-3.14",
439 absl::StrJoin(std::make_tuple(x, std::cref(y), z), "-"));
440
441 struct TestFormatter {
442 char buffer[128];
443 void operator()(std::string* out, int v) {
444 snprintf(buffer, sizeof(buffer), "%#.8x", v);
445 out->append(buffer);
446 }
447 void operator()(std::string* out, double v) {
448 snprintf(buffer, sizeof(buffer), "%#.0f", v);
449 out->append(buffer);
450 }
451 void operator()(std::string* out, const std::string& v) {
452 snprintf(buffer, sizeof(buffer), "%.4s", v.c_str());
453 out->append(buffer);
454 }
455 };
456 EXPECT_EQ("0x0000000a-hell-3.",
457 absl::StrJoin(std::make_tuple(x, y, z), "-", TestFormatter()));
458 EXPECT_EQ(
459 "0x0000000a-hell-3.",
460 absl::StrJoin(std::make_tuple(x, std::cref(y), z), "-", TestFormatter()));
461 EXPECT_EQ("0x0000000a-hell-3.",
462 absl::StrJoin(std::make_tuple(&x, &y, &z), "-",
463 absl::DereferenceFormatter(TestFormatter())));
464 EXPECT_EQ("0x0000000a-hell-3.",
465 absl::StrJoin(std::make_tuple(absl::make_unique<int>(x),
466 absl::make_unique<std::string>(y),
467 absl::make_unique<double>(z)),
468 "-", absl::DereferenceFormatter(TestFormatter())));
469 EXPECT_EQ("0x0000000a-hell-3.",
470 absl::StrJoin(std::make_tuple(absl::make_unique<int>(x), &y, &z),
471 "-", absl::DereferenceFormatter(TestFormatter())));
472 }
473
474 } // namespace
475