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