| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/strings/to_string.h" |
| |
| #include <ios> |
| #include <ostream> |
| #include <string> |
| |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace gurl_base { |
| namespace { |
| |
| class NotStringifiable {}; |
| class HasToString { |
| public: |
| std::string ToString() const { return "yay!"; } |
| }; |
| |
| // .ToString() support on structs. |
| static_assert(!internal::SupportsToString<NotStringifiable>, |
| "value without ToString() shouldn't be marked SupportsToString"); |
| static_assert(!internal::SupportsToString<NotStringifiable&>, |
| "& without ToString() shouldn't be marked SupportsToString"); |
| static_assert(!internal::SupportsToString<const NotStringifiable&>, |
| "const& without ToString() shouldn't be marked SupportsToString"); |
| static_assert(!internal::SupportsToString<NotStringifiable&&>, |
| "&& without ToString() shouldn't be marked SupportsToString"); |
| static_assert(internal::SupportsToString<HasToString>, |
| "value with ToString() should be marked SupportsToString"); |
| static_assert(internal::SupportsToString<HasToString&>, |
| "& with ToString() should be marked SupportsToString"); |
| static_assert(internal::SupportsToString<const HasToString&>, |
| "const& with ToString() should be marked SupportsToString"); |
| static_assert(internal::SupportsToString<HasToString&&>, |
| "&& with ToString() should be marked SupportsToString"); |
| |
| TEST(ToStringTest, Streamable) { |
| // Types with built-in <<. |
| EXPECT_EQ(ToString("foo"), "foo"); |
| EXPECT_EQ(ToString(123), "123"); |
| } |
| |
| enum class StreamableTestEnum { kGreeting, kLocation }; |
| |
| std::ostream& operator<<(std::ostream& os, const StreamableTestEnum& value) { |
| switch (value) { |
| case StreamableTestEnum::kGreeting: |
| return os << "hello"; |
| case StreamableTestEnum::kLocation: |
| return os << "world"; |
| } |
| } |
| |
| TEST(ToStringTest, UserDefinedStreamable) { |
| // Type with user-defined <<. |
| EXPECT_EQ(ToString(StreamableTestEnum::kGreeting), "hello"); |
| EXPECT_EQ(ToString(StreamableTestEnum::kGreeting, " ", |
| StreamableTestEnum::kLocation), |
| "hello world"); |
| } |
| |
| TEST(ToStringTest, UserDefinedToString) { |
| // Type with user-defined ToString(). |
| EXPECT_EQ(ToString(HasToString()), "yay!"); |
| } |
| |
| class UnusualToString { |
| public: |
| HasToString ToString() const { return HasToString(); } |
| }; |
| |
| TEST(ToStringTest, ToStringReturnsNonStdString) { |
| // Types with a ToString() that does not directly return a std::string should |
| // still work. |
| EXPECT_EQ(ToString(UnusualToString()), "yay!"); |
| } |
| |
| enum class NonStreamableTestEnum { kGreeting = 0, kLocation }; |
| |
| TEST(ToStringTest, ScopedEnum) { |
| // Scoped enums without a defined << should print as their underlying type. |
| EXPECT_EQ(ToString(NonStreamableTestEnum::kLocation), "1"); |
| } |
| |
| TEST(ToStringTest, IoManip) { |
| // I/O manipulators should have their expected effect, not be printed as |
| // function pointers. |
| EXPECT_EQ(ToString("42 in hex is ", std::hex, 42), "42 in hex is 2a"); |
| } |
| |
| TEST(ToStringTest, Tuple) { |
| // Tuples should correctly format the contained types. |
| EXPECT_EQ(ToString(std::make_tuple(StreamableTestEnum::kGreeting, |
| HasToString(), "a string")), |
| "<hello, yay!, a string>"); |
| } |
| |
| void Func() {} |
| |
| TEST(ToStringTest, FunctionPointer) { |
| // We don't care about the actual address, but a function pointer should not |
| // be implicitly converted to bool. |
| EXPECT_NE(ToString(&Func), ToString(true)); |
| |
| // Functions should be treated like function pointers. |
| EXPECT_EQ(ToString(Func), ToString(&Func)); |
| } |
| |
| class OverloadsAddressOp { |
| public: |
| OverloadsAddressOp* operator&() { return nullptr; } |
| const OverloadsAddressOp* operator&() const { return nullptr; } |
| }; |
| |
| TEST(ToStringTest, NonStringifiable) { |
| // Non-stringifiable types should be printed using a fallback. |
| EXPECT_NE(ToString(NotStringifiable()).find("-byte object at 0x"), |
| std::string::npos); |
| |
| // Non-stringifiable types which overload operator& should print their real |
| // address. |
| EXPECT_NE(ToString(OverloadsAddressOp()), |
| ToString(static_cast<OverloadsAddressOp*>(nullptr))); |
| } |
| |
| } // namespace |
| } // namespace base |