1/*
2 * Copyright 2011-present Facebook, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <folly/DiscriminatedPtr.h>
18
19#include <folly/portability/GTest.h>
20
21using namespace folly;
22
23TEST(DiscriminatedPtr, Basic) {
24 struct Foo {};
25 struct Bar {};
26 typedef DiscriminatedPtr<void, int, Foo, Bar> Ptr;
27
28 int a = 10;
29 Ptr p;
30 EXPECT_TRUE(p.empty());
31 EXPECT_FALSE(p.hasType<void>());
32 EXPECT_FALSE(p.hasType<int>());
33 EXPECT_FALSE(p.hasType<Foo>());
34 EXPECT_FALSE(p.hasType<Bar>());
35
36 p.set(&a);
37 EXPECT_FALSE(p.empty());
38 EXPECT_FALSE(p.hasType<void>());
39 EXPECT_TRUE(p.hasType<int>());
40 EXPECT_FALSE(p.hasType<Foo>());
41 EXPECT_FALSE(p.hasType<Bar>());
42
43 EXPECT_EQ(&a, p.get_nothrow<int>());
44 EXPECT_EQ(&a, static_cast<const Ptr&>(p).get_nothrow<int>());
45 EXPECT_EQ(&a, p.get<int>());
46 EXPECT_EQ(&a, static_cast<const Ptr&>(p).get<int>());
47 EXPECT_EQ(static_cast<void*>(nullptr), p.get_nothrow<void>());
48 EXPECT_THROW({ p.get<void>(); }, std::invalid_argument);
49
50 Foo foo;
51 p.set(&foo);
52 EXPECT_FALSE(p.empty());
53 EXPECT_FALSE(p.hasType<void>());
54 EXPECT_FALSE(p.hasType<int>());
55 EXPECT_TRUE(p.hasType<Foo>());
56 EXPECT_FALSE(p.hasType<Bar>());
57
58 EXPECT_EQ(static_cast<int*>(nullptr), p.get_nothrow<int>());
59
60 p.clear();
61 EXPECT_TRUE(p.empty());
62 EXPECT_FALSE(p.hasType<void>());
63 EXPECT_FALSE(p.hasType<int>());
64 EXPECT_FALSE(p.hasType<Foo>());
65 EXPECT_FALSE(p.hasType<Bar>());
66}
67
68TEST(DiscriminatedPtr, Apply) {
69 struct Foo {};
70 struct Visitor {
71 std::string operator()(int* /* ptr */) {
72 return "int";
73 }
74 std::string operator()(const int* /* ptr */) {
75 return "const int";
76 }
77 std::string operator()(Foo* /* ptr */) {
78 return "Foo";
79 }
80 std::string operator()(const Foo* /* ptr */) {
81 return "const Foo";
82 }
83 };
84
85 typedef DiscriminatedPtr<int, Foo> Ptr;
86 Ptr p;
87
88 int a = 0;
89 p.set(&a);
90 EXPECT_EQ("int", p.apply(Visitor()));
91 EXPECT_EQ("const int", static_cast<const Ptr&>(p).apply(Visitor()));
92
93 Foo foo;
94 p.set(&foo);
95 EXPECT_EQ("Foo", p.apply(Visitor()));
96 EXPECT_EQ("const Foo", static_cast<const Ptr&>(p).apply(Visitor()));
97 EXPECT_EQ("Foo", apply_visitor(Visitor(), p));
98 EXPECT_EQ("const Foo", apply_visitor(Visitor(), static_cast<const Ptr&>(p)));
99 EXPECT_EQ("Foo", apply_visitor(Visitor(), std::move(p)));
100
101 p.clear();
102 EXPECT_THROW({ p.apply(Visitor()); }, std::invalid_argument);
103}
104
105TEST(DiscriminatedPtr, ApplyVoid) {
106 struct Foo {};
107 struct Visitor {
108 void operator()(int* /* ptr */) {
109 result = "int";
110 }
111 void operator()(const int* /* ptr */) {
112 result = "const int";
113 }
114 void operator()(Foo* /* ptr */) {
115 result = "Foo";
116 }
117 void operator()(const Foo* /* ptr */) {
118 result = "const Foo";
119 }
120
121 std::string result;
122 };
123
124 typedef DiscriminatedPtr<int, Foo> Ptr;
125 Ptr p;
126 Visitor v;
127
128 int a = 0;
129 p.set(&a);
130 p.apply(v);
131 EXPECT_EQ("int", v.result);
132 static_cast<const Ptr&>(p).apply(v);
133 EXPECT_EQ("const int", v.result);
134
135 Foo foo;
136 p.set(&foo);
137 p.apply(v);
138 EXPECT_EQ("Foo", v.result);
139 static_cast<const Ptr&>(p).apply(v);
140 EXPECT_EQ("const Foo", v.result);
141
142 p.clear();
143 EXPECT_THROW({ p.apply(v); }, std::invalid_argument);
144}
145