123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474 |
- // Copyright 2017 The Abseil Authors.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // https://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- // Unit tests for all join.h functions
- #include "absl/strings/str_join.h"
- #include <cstddef>
- #include <cstdint>
- #include <cstdio>
- #include <functional>
- #include <initializer_list>
- #include <map>
- #include <memory>
- #include <ostream>
- #include <tuple>
- #include <type_traits>
- #include <vector>
- #include "gtest/gtest.h"
- #include "absl/base/macros.h"
- #include "absl/memory/memory.h"
- #include "absl/strings/str_cat.h"
- #include "absl/strings/str_split.h"
- namespace {
- TEST(StrJoin, APIExamples) {
- {
- // Collection of strings
- std::vector<std::string> v = {"foo", "bar", "baz"};
- EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-"));
- }
- {
- // Collection of absl::string_view
- std::vector<absl::string_view> v = {"foo", "bar", "baz"};
- EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-"));
- }
- {
- // Collection of const char*
- std::vector<const char*> v = {"foo", "bar", "baz"};
- EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-"));
- }
- {
- // Collection of non-const char*
- std::string a = "foo", b = "bar", c = "baz";
- std::vector<char*> v = {&a[0], &b[0], &c[0]};
- EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-"));
- }
- {
- // Collection of ints
- std::vector<int> v = {1, 2, 3, -4};
- EXPECT_EQ("1-2-3--4", absl::StrJoin(v, "-"));
- }
- {
- // Literals passed as a std::initializer_list
- std::string s = absl::StrJoin({"a", "b", "c"}, "-");
- EXPECT_EQ("a-b-c", s);
- }
- {
- // Join a std::tuple<T...>.
- std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-");
- EXPECT_EQ("123-abc-0.456", s);
- }
- {
- // Collection of unique_ptrs
- std::vector<std::unique_ptr<int>> v;
- v.emplace_back(new int(1));
- v.emplace_back(new int(2));
- v.emplace_back(new int(3));
- EXPECT_EQ("1-2-3", absl::StrJoin(v, "-"));
- }
- {
- // Array of ints
- const int a[] = {1, 2, 3, -4};
- EXPECT_EQ("1-2-3--4", absl::StrJoin(a, a + ABSL_ARRAYSIZE(a), "-"));
- }
- {
- // Collection of pointers
- int x = 1, y = 2, z = 3;
- std::vector<int*> v = {&x, &y, &z};
- EXPECT_EQ("1-2-3", absl::StrJoin(v, "-"));
- }
- {
- // Collection of pointers to pointers
- int x = 1, y = 2, z = 3;
- int *px = &x, *py = &y, *pz = &z;
- std::vector<int**> v = {&px, &py, &pz};
- EXPECT_EQ("1-2-3", absl::StrJoin(v, "-"));
- }
- {
- // Collection of pointers to std::string
- std::string a("a"), b("b");
- std::vector<std::string*> v = {&a, &b};
- EXPECT_EQ("a-b", absl::StrJoin(v, "-"));
- }
- {
- // A std::map, which is a collection of std::pair<>s.
- std::map<std::string, int> m = {{"a", 1}, {"b", 2}, {"c", 3}};
- EXPECT_EQ("a=1,b=2,c=3", absl::StrJoin(m, ",", absl::PairFormatter("=")));
- }
- {
- // Shows absl::StrSplit and absl::StrJoin working together. This example is
- // equivalent to s/=/-/g.
- const std::string s = "a=b=c=d";
- EXPECT_EQ("a-b-c-d", absl::StrJoin(absl::StrSplit(s, "="), "-"));
- }
- //
- // A few examples of edge cases
- //
- {
- // Empty range yields an empty string.
- std::vector<std::string> v;
- EXPECT_EQ("", absl::StrJoin(v, "-"));
- }
- {
- // A range of 1 element gives a string with that element but no
- // separator.
- std::vector<std::string> v = {"foo"};
- EXPECT_EQ("foo", absl::StrJoin(v, "-"));
- }
- {
- // A range with a single empty string element
- std::vector<std::string> v = {""};
- EXPECT_EQ("", absl::StrJoin(v, "-"));
- }
- {
- // A range with 2 elements, one of which is an empty string
- std::vector<std::string> v = {"a", ""};
- EXPECT_EQ("a-", absl::StrJoin(v, "-"));
- }
- {
- // A range with 2 empty elements.
- std::vector<std::string> v = {"", ""};
- EXPECT_EQ("-", absl::StrJoin(v, "-"));
- }
- {
- // A std::vector of bool.
- std::vector<bool> v = {true, false, true};
- EXPECT_EQ("1-0-1", absl::StrJoin(v, "-"));
- }
- }
- TEST(StrJoin, CustomFormatter) {
- std::vector<std::string> v{"One", "Two", "Three"};
- {
- std::string joined =
- absl::StrJoin(v, "", [](std::string* out, const std::string& in) {
- absl::StrAppend(out, "(", in, ")");
- });
- EXPECT_EQ("(One)(Two)(Three)", joined);
- }
- {
- class ImmovableFormatter {
- public:
- void operator()(std::string* out, const std::string& in) {
- absl::StrAppend(out, "(", in, ")");
- }
- ImmovableFormatter() {}
- ImmovableFormatter(const ImmovableFormatter&) = delete;
- };
- EXPECT_EQ("(One)(Two)(Three)", absl::StrJoin(v, "", ImmovableFormatter()));
- }
- {
- class OverloadedFormatter {
- public:
- void operator()(std::string* out, const std::string& in) {
- absl::StrAppend(out, "(", in, ")");
- }
- void operator()(std::string* out, const std::string& in) const {
- absl::StrAppend(out, "[", in, "]");
- }
- };
- EXPECT_EQ("(One)(Two)(Three)", absl::StrJoin(v, "", OverloadedFormatter()));
- const OverloadedFormatter fmt = {};
- EXPECT_EQ("[One][Two][Three]", absl::StrJoin(v, "", fmt));
- }
- }
- //
- // Tests the Formatters
- //
- TEST(AlphaNumFormatter, FormatterAPI) {
- // Not an exhaustive test. See strings/strcat_test.h for the exhaustive test
- // of what AlphaNum can convert.
- auto f = absl::AlphaNumFormatter();
- std::string s;
- f(&s, "Testing: ");
- f(&s, static_cast<int>(1));
- f(&s, static_cast<int16_t>(2));
- f(&s, static_cast<int64_t>(3));
- f(&s, static_cast<float>(4));
- f(&s, static_cast<double>(5));
- f(&s, static_cast<unsigned>(6));
- f(&s, static_cast<size_t>(7));
- f(&s, absl::string_view(" OK"));
- EXPECT_EQ("Testing: 1234567 OK", s);
- }
- // Make sure people who are mistakenly using std::vector<bool> even though
- // they're not memory-constrained can use absl::AlphaNumFormatter().
- TEST(AlphaNumFormatter, VectorOfBool) {
- auto f = absl::AlphaNumFormatter();
- std::string s;
- std::vector<bool> v = {true, false, true};
- f(&s, *v.cbegin());
- f(&s, *v.begin());
- f(&s, v[1]);
- EXPECT_EQ("110", s);
- }
- TEST(AlphaNumFormatter, AlphaNum) {
- auto f = absl::AlphaNumFormatter();
- std::string s;
- f(&s, absl::AlphaNum("hello"));
- EXPECT_EQ("hello", s);
- }
- struct StreamableType {
- std::string contents;
- };
- inline std::ostream& operator<<(std::ostream& os, const StreamableType& t) {
- os << "Streamable:" << t.contents;
- return os;
- }
- TEST(StreamFormatter, FormatterAPI) {
- auto f = absl::StreamFormatter();
- std::string s;
- f(&s, "Testing: ");
- f(&s, static_cast<int>(1));
- f(&s, static_cast<int16_t>(2));
- f(&s, static_cast<int64_t>(3));
- f(&s, static_cast<float>(4));
- f(&s, static_cast<double>(5));
- f(&s, static_cast<unsigned>(6));
- f(&s, static_cast<size_t>(7));
- f(&s, absl::string_view(" OK "));
- StreamableType streamable = {"object"};
- f(&s, streamable);
- EXPECT_EQ("Testing: 1234567 OK Streamable:object", s);
- }
- // A dummy formatter that wraps each element in parens. Used in some tests
- // below.
- struct TestingParenFormatter {
- template <typename T>
- void operator()(std::string* s, const T& t) {
- absl::StrAppend(s, "(", t, ")");
- }
- };
- TEST(PairFormatter, FormatterAPI) {
- {
- // Tests default PairFormatter(sep) that uses AlphaNumFormatter for the
- // 'first' and 'second' members.
- const auto f = absl::PairFormatter("=");
- std::string s;
- f(&s, std::make_pair("a", "b"));
- f(&s, std::make_pair(1, 2));
- EXPECT_EQ("a=b1=2", s);
- }
- {
- // Tests using a custom formatter for the 'first' and 'second' members.
- auto f = absl::PairFormatter(TestingParenFormatter(), "=",
- TestingParenFormatter());
- std::string s;
- f(&s, std::make_pair("a", "b"));
- f(&s, std::make_pair(1, 2));
- EXPECT_EQ("(a)=(b)(1)=(2)", s);
- }
- }
- TEST(DereferenceFormatter, FormatterAPI) {
- {
- // Tests wrapping the default AlphaNumFormatter.
- const absl::strings_internal::DereferenceFormatterImpl<
- absl::strings_internal::AlphaNumFormatterImpl>
- f;
- int x = 1, y = 2, z = 3;
- std::string s;
- f(&s, &x);
- f(&s, &y);
- f(&s, &z);
- EXPECT_EQ("123", s);
- }
- {
- // Tests wrapping std::string's default formatter.
- absl::strings_internal::DereferenceFormatterImpl<
- absl::strings_internal::DefaultFormatter<std::string>::Type>
- f;
- std::string x = "x";
- std::string y = "y";
- std::string z = "z";
- std::string s;
- f(&s, &x);
- f(&s, &y);
- f(&s, &z);
- EXPECT_EQ(s, "xyz");
- }
- {
- // Tests wrapping a custom formatter.
- auto f = absl::DereferenceFormatter(TestingParenFormatter());
- int x = 1, y = 2, z = 3;
- std::string s;
- f(&s, &x);
- f(&s, &y);
- f(&s, &z);
- EXPECT_EQ("(1)(2)(3)", s);
- }
- {
- absl::strings_internal::DereferenceFormatterImpl<
- absl::strings_internal::AlphaNumFormatterImpl>
- f;
- auto x = std::unique_ptr<int>(new int(1));
- auto y = std::unique_ptr<int>(new int(2));
- auto z = std::unique_ptr<int>(new int(3));
- std::string s;
- f(&s, x);
- f(&s, y);
- f(&s, z);
- EXPECT_EQ("123", s);
- }
- }
- //
- // Tests the interfaces for the 4 public Join function overloads. The semantics
- // of the algorithm is covered in the above APIExamples test.
- //
- TEST(StrJoin, PublicAPIOverloads) {
- std::vector<std::string> v = {"a", "b", "c"};
- // Iterators + formatter
- EXPECT_EQ("a-b-c",
- absl::StrJoin(v.begin(), v.end(), "-", absl::AlphaNumFormatter()));
- // Range + formatter
- EXPECT_EQ("a-b-c", absl::StrJoin(v, "-", absl::AlphaNumFormatter()));
- // Iterators, no formatter
- EXPECT_EQ("a-b-c", absl::StrJoin(v.begin(), v.end(), "-"));
- // Range, no formatter
- EXPECT_EQ("a-b-c", absl::StrJoin(v, "-"));
- }
- TEST(StrJoin, Array) {
- const absl::string_view a[] = {"a", "b", "c"};
- EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
- }
- TEST(StrJoin, InitializerList) {
- { EXPECT_EQ("a-b-c", absl::StrJoin({"a", "b", "c"}, "-")); }
- {
- auto a = {"a", "b", "c"};
- EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
- }
- {
- std::initializer_list<const char*> a = {"a", "b", "c"};
- EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
- }
- {
- std::initializer_list<std::string> a = {"a", "b", "c"};
- EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
- }
- {
- std::initializer_list<absl::string_view> a = {"a", "b", "c"};
- EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
- }
- {
- // Tests initializer_list with a non-default formatter
- auto a = {"a", "b", "c"};
- TestingParenFormatter f;
- EXPECT_EQ("(a)-(b)-(c)", absl::StrJoin(a, "-", f));
- }
- {
- // initializer_list of ints
- EXPECT_EQ("1-2-3", absl::StrJoin({1, 2, 3}, "-"));
- }
- {
- // Tests initializer_list of ints with a non-default formatter
- auto a = {1, 2, 3};
- TestingParenFormatter f;
- EXPECT_EQ("(1)-(2)-(3)", absl::StrJoin(a, "-", f));
- }
- }
- TEST(StrJoin, Tuple) {
- EXPECT_EQ("", absl::StrJoin(std::make_tuple(), "-"));
- EXPECT_EQ("hello", absl::StrJoin(std::make_tuple("hello"), "-"));
- int x(10);
- std::string y("hello");
- double z(3.14);
- EXPECT_EQ("10-hello-3.14", absl::StrJoin(std::make_tuple(x, y, z), "-"));
- // Faster! Faster!!
- EXPECT_EQ("10-hello-3.14",
- absl::StrJoin(std::make_tuple(x, std::cref(y), z), "-"));
- struct TestFormatter {
- char buffer[128];
- void operator()(std::string* out, int v) {
- snprintf(buffer, sizeof(buffer), "%#.8x", v);
- out->append(buffer);
- }
- void operator()(std::string* out, double v) {
- snprintf(buffer, sizeof(buffer), "%#.0f", v);
- out->append(buffer);
- }
- void operator()(std::string* out, const std::string& v) {
- snprintf(buffer, sizeof(buffer), "%.4s", v.c_str());
- out->append(buffer);
- }
- };
- EXPECT_EQ("0x0000000a-hell-3.",
- absl::StrJoin(std::make_tuple(x, y, z), "-", TestFormatter()));
- EXPECT_EQ(
- "0x0000000a-hell-3.",
- absl::StrJoin(std::make_tuple(x, std::cref(y), z), "-", TestFormatter()));
- EXPECT_EQ("0x0000000a-hell-3.",
- absl::StrJoin(std::make_tuple(&x, &y, &z), "-",
- absl::DereferenceFormatter(TestFormatter())));
- EXPECT_EQ("0x0000000a-hell-3.",
- absl::StrJoin(std::make_tuple(absl::make_unique<int>(x),
- absl::make_unique<std::string>(y),
- absl::make_unique<double>(z)),
- "-", absl::DereferenceFormatter(TestFormatter())));
- EXPECT_EQ("0x0000000a-hell-3.",
- absl::StrJoin(std::make_tuple(absl::make_unique<int>(x), &y, &z),
- "-", absl::DereferenceFormatter(TestFormatter())));
- }
- } // namespace
|