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