• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/strings/to_string.h"
6 
7 #include <ios>
8 #include <ostream>
9 #include <string>
10 
11 #include "testing/gtest/include/gtest/gtest.h"
12 
13 namespace base {
14 namespace {
15 
16 class NotStringifiable {};
17 class HasToString {
18  public:
ToString() const19   std::string ToString() const { return "yay!"; }
20 };
21 
22 // .ToString() support on structs.
23 static_assert(!internal::SupportsToString<NotStringifiable>,
24               "value without ToString() shouldn't be marked SupportsToString");
25 static_assert(!internal::SupportsToString<NotStringifiable&>,
26               "& without ToString() shouldn't be marked SupportsToString");
27 static_assert(!internal::SupportsToString<const NotStringifiable&>,
28               "const& without ToString() shouldn't be marked SupportsToString");
29 static_assert(!internal::SupportsToString<NotStringifiable&&>,
30               "&& without ToString() shouldn't be marked SupportsToString");
31 static_assert(internal::SupportsToString<HasToString>,
32               "value with ToString() should be marked SupportsToString");
33 static_assert(internal::SupportsToString<HasToString&>,
34               "& with ToString() should be marked SupportsToString");
35 static_assert(internal::SupportsToString<const HasToString&>,
36               "const& with ToString() should be marked SupportsToString");
37 static_assert(internal::SupportsToString<HasToString&&>,
38               "&& with ToString() should be marked SupportsToString");
39 
TEST(ToStringTest,Streamable)40 TEST(ToStringTest, Streamable) {
41   // Types with built-in <<.
42   EXPECT_EQ(ToString("foo"), "foo");
43   EXPECT_EQ(ToString(123), "123");
44 }
45 
46 enum class StreamableTestEnum { kGreeting, kLocation };
47 
operator <<(std::ostream & os,const StreamableTestEnum & value)48 std::ostream& operator<<(std::ostream& os, const StreamableTestEnum& value) {
49   switch (value) {
50     case StreamableTestEnum::kGreeting:
51       return os << "hello";
52     case StreamableTestEnum::kLocation:
53       return os << "world";
54   }
55 }
56 
TEST(ToStringTest,UserDefinedStreamable)57 TEST(ToStringTest, UserDefinedStreamable) {
58   // Type with user-defined <<.
59   EXPECT_EQ(ToString(StreamableTestEnum::kGreeting), "hello");
60   EXPECT_EQ(ToString(StreamableTestEnum::kGreeting, " ",
61                      StreamableTestEnum::kLocation),
62             "hello world");
63 }
64 
TEST(ToStringTest,UserDefinedToString)65 TEST(ToStringTest, UserDefinedToString) {
66   // Type with user-defined ToString().
67   EXPECT_EQ(ToString(HasToString()), "yay!");
68 }
69 
70 class UnusualToString {
71  public:
ToString() const72   HasToString ToString() const { return HasToString(); }
73 };
74 
TEST(ToStringTest,ToStringReturnsNonStdString)75 TEST(ToStringTest, ToStringReturnsNonStdString) {
76   // Types with a ToString() that does not directly return a std::string should
77   // still work.
78   EXPECT_EQ(ToString(UnusualToString()), "yay!");
79 }
80 
81 enum class NonStreamableTestEnum { kGreeting = 0, kLocation };
82 
TEST(ToStringTest,ScopedEnum)83 TEST(ToStringTest, ScopedEnum) {
84   // Scoped enums without a defined << should print as their underlying type.
85   EXPECT_EQ(ToString(NonStreamableTestEnum::kLocation), "1");
86 }
87 
TEST(ToStringTest,WideChars)88 TEST(ToStringTest, WideChars) {
89   EXPECT_EQ(ToString(u'a'), "97");
90   EXPECT_EQ(ToString(L'a'), "97");
91 }
92 
TEST(ToStringTest,IoManip)93 TEST(ToStringTest, IoManip) {
94   // I/O manipulators should have their expected effect, not be printed as
95   // function pointers.
96   EXPECT_EQ(ToString("42 in hex is ", std::hex, 42), "42 in hex is 2a");
97 }
98 
TEST(ToStringTest,Tuple)99 TEST(ToStringTest, Tuple) {
100   // Tuples should correctly format the contained types.
101   EXPECT_EQ(ToString(std::make_tuple(StreamableTestEnum::kGreeting,
102                                      HasToString(), "a string")),
103             "<hello, yay!, a string>");
104 }
105 
Func()106 void Func() {}
107 
TEST(ToStringTest,FunctionPointer)108 TEST(ToStringTest, FunctionPointer) {
109   // We don't care about the actual address, but a function pointer should not
110   // be implicitly converted to bool.
111   EXPECT_NE(ToString(&Func), ToString(true));
112 
113   // Functions should be treated like function pointers.
114   EXPECT_EQ(ToString(Func), ToString(&Func));
115 }
116 
117 class OverloadsAddressOp {
118  public:
operator &()119   OverloadsAddressOp* operator&() { return nullptr; }
operator &() const120   const OverloadsAddressOp* operator&() const { return nullptr; }
121 };
122 
TEST(ToStringTest,NonStringifiable)123 TEST(ToStringTest, NonStringifiable) {
124   // Non-stringifiable types should be printed using a fallback.
125   EXPECT_NE(ToString(NotStringifiable()).find("-byte object at 0x"),
126             std::string::npos);
127 
128   // Non-stringifiable types which overload operator& should print their real
129   // address.
130   EXPECT_NE(ToString(OverloadsAddressOp()),
131             ToString(static_cast<OverloadsAddressOp*>(nullptr)));
132 }
133 
134 }  // namespace
135 }  // namespace base
136