1 // Copyright 2020 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/castable.h"
16
17 #include <memory>
18 #include <string>
19
20 #include "gtest/gtest.h"
21
22 namespace tint {
23 namespace {
24
25 struct Animal : public tint::Castable<Animal> {
Animaltint::__anon8381b6cf0111::Animal26 explicit Animal(std::string n) : name(n) {}
27 const std::string name;
28 };
29
30 struct Amphibian : public tint::Castable<Amphibian, Animal> {
Amphibiantint::__anon8381b6cf0111::Amphibian31 explicit Amphibian(std::string n) : Base(n) {}
32 };
33
34 struct Mammal : public tint::Castable<Mammal, Animal> {
Mammaltint::__anon8381b6cf0111::Mammal35 explicit Mammal(std::string n) : Base(n) {}
36 };
37
38 struct Reptile : public tint::Castable<Reptile, Animal> {
Reptiletint::__anon8381b6cf0111::Reptile39 explicit Reptile(std::string n) : Base(n) {}
40 };
41
42 struct Frog : public tint::Castable<Frog, Amphibian> {
Frogtint::__anon8381b6cf0111::Frog43 Frog() : Base("Frog") {}
44 };
45
46 struct Bear : public tint::Castable<Bear, Mammal> {
Beartint::__anon8381b6cf0111::Bear47 Bear() : Base("Bear") {}
48 };
49
50 struct Gecko : public tint::Castable<Gecko, Reptile> {
Geckotint::__anon8381b6cf0111::Gecko51 Gecko() : Base("Gecko") {}
52 };
53
TEST(CastableBase,Is)54 TEST(CastableBase, Is) {
55 std::unique_ptr<CastableBase> frog = std::make_unique<Frog>();
56 std::unique_ptr<CastableBase> bear = std::make_unique<Bear>();
57 std::unique_ptr<CastableBase> gecko = std::make_unique<Gecko>();
58
59 ASSERT_TRUE(frog->Is<Animal>());
60 ASSERT_TRUE(bear->Is<Animal>());
61 ASSERT_TRUE(gecko->Is<Animal>());
62
63 ASSERT_TRUE(frog->Is<Amphibian>());
64 ASSERT_FALSE(bear->Is<Amphibian>());
65 ASSERT_FALSE(gecko->Is<Amphibian>());
66
67 ASSERT_FALSE(frog->Is<Mammal>());
68 ASSERT_TRUE(bear->Is<Mammal>());
69 ASSERT_FALSE(gecko->Is<Mammal>());
70
71 ASSERT_FALSE(frog->Is<Reptile>());
72 ASSERT_FALSE(bear->Is<Reptile>());
73 ASSERT_TRUE(gecko->Is<Reptile>());
74 }
75
TEST(CastableBase,Is_kDontErrorOnImpossibleCast)76 TEST(CastableBase, Is_kDontErrorOnImpossibleCast) {
77 // Unlike TEST(CastableBase, Is), we're dynamically querying [A -> B] without
78 // going via CastableBase.
79 auto frog = std::make_unique<Frog>();
80 auto bear = std::make_unique<Bear>();
81 auto gecko = std::make_unique<Gecko>();
82
83 ASSERT_TRUE((frog->Is<Animal, kDontErrorOnImpossibleCast>()));
84 ASSERT_TRUE((bear->Is<Animal, kDontErrorOnImpossibleCast>()));
85 ASSERT_TRUE((gecko->Is<Animal, kDontErrorOnImpossibleCast>()));
86
87 ASSERT_TRUE((frog->Is<Amphibian, kDontErrorOnImpossibleCast>()));
88 ASSERT_FALSE((bear->Is<Amphibian, kDontErrorOnImpossibleCast>()));
89 ASSERT_FALSE((gecko->Is<Amphibian, kDontErrorOnImpossibleCast>()));
90
91 ASSERT_FALSE((frog->Is<Mammal, kDontErrorOnImpossibleCast>()));
92 ASSERT_TRUE((bear->Is<Mammal, kDontErrorOnImpossibleCast>()));
93 ASSERT_FALSE((gecko->Is<Mammal, kDontErrorOnImpossibleCast>()));
94
95 ASSERT_FALSE((frog->Is<Reptile, kDontErrorOnImpossibleCast>()));
96 ASSERT_FALSE((bear->Is<Reptile, kDontErrorOnImpossibleCast>()));
97 ASSERT_TRUE((gecko->Is<Reptile, kDontErrorOnImpossibleCast>()));
98 }
99
TEST(CastableBase,IsWithPredicate)100 TEST(CastableBase, IsWithPredicate) {
101 std::unique_ptr<CastableBase> frog = std::make_unique<Frog>();
102
103 frog->Is<Animal>([&frog](const Animal* a) {
104 EXPECT_EQ(a, frog.get());
105 return true;
106 });
107
108 ASSERT_TRUE((frog->Is<Animal>([](const Animal*) { return true; })));
109 ASSERT_FALSE((frog->Is<Animal>([](const Animal*) { return false; })));
110
111 // Predicate not called if cast is invalid
112 auto expect_not_called = [] { FAIL() << "Should not be called"; };
113 ASSERT_FALSE((frog->Is<Bear>([&](const Animal*) {
114 expect_not_called();
115 return true;
116 })));
117 }
118
TEST(CastableBase,IsAnyOf)119 TEST(CastableBase, IsAnyOf) {
120 std::unique_ptr<CastableBase> frog = std::make_unique<Frog>();
121 std::unique_ptr<CastableBase> bear = std::make_unique<Bear>();
122 std::unique_ptr<CastableBase> gecko = std::make_unique<Gecko>();
123
124 ASSERT_TRUE((frog->IsAnyOf<Animal, Mammal, Amphibian, Reptile>()));
125 ASSERT_TRUE((frog->IsAnyOf<Mammal, Amphibian>()));
126 ASSERT_TRUE((frog->IsAnyOf<Amphibian, Reptile>()));
127 ASSERT_FALSE((frog->IsAnyOf<Mammal, Reptile>()));
128
129 ASSERT_TRUE((bear->IsAnyOf<Animal, Mammal, Amphibian, Reptile>()));
130 ASSERT_TRUE((bear->IsAnyOf<Mammal, Amphibian>()));
131 ASSERT_TRUE((bear->IsAnyOf<Mammal, Reptile>()));
132 ASSERT_FALSE((bear->IsAnyOf<Amphibian, Reptile>()));
133
134 ASSERT_TRUE((gecko->IsAnyOf<Animal, Mammal, Amphibian, Reptile>()));
135 ASSERT_TRUE((gecko->IsAnyOf<Mammal, Reptile>()));
136 ASSERT_TRUE((gecko->IsAnyOf<Amphibian, Reptile>()));
137 ASSERT_FALSE((gecko->IsAnyOf<Mammal, Amphibian>()));
138 }
139
TEST(CastableBase,As)140 TEST(CastableBase, As) {
141 std::unique_ptr<CastableBase> frog = std::make_unique<Frog>();
142 std::unique_ptr<CastableBase> bear = std::make_unique<Bear>();
143 std::unique_ptr<CastableBase> gecko = std::make_unique<Gecko>();
144
145 ASSERT_EQ(frog->As<Animal>(), static_cast<Animal*>(frog.get()));
146 ASSERT_EQ(bear->As<Animal>(), static_cast<Animal*>(bear.get()));
147 ASSERT_EQ(gecko->As<Animal>(), static_cast<Animal*>(gecko.get()));
148
149 ASSERT_EQ(frog->As<Amphibian>(), static_cast<Amphibian*>(frog.get()));
150 ASSERT_EQ(bear->As<Amphibian>(), nullptr);
151 ASSERT_EQ(gecko->As<Amphibian>(), nullptr);
152
153 ASSERT_EQ(frog->As<Mammal>(), nullptr);
154 ASSERT_EQ(bear->As<Mammal>(), static_cast<Mammal*>(bear.get()));
155 ASSERT_EQ(gecko->As<Mammal>(), nullptr);
156
157 ASSERT_EQ(frog->As<Reptile>(), nullptr);
158 ASSERT_EQ(bear->As<Reptile>(), nullptr);
159 ASSERT_EQ(gecko->As<Reptile>(), static_cast<Reptile*>(gecko.get()));
160 }
161
TEST(CastableBase,As_kDontErrorOnImpossibleCast)162 TEST(CastableBase, As_kDontErrorOnImpossibleCast) {
163 // Unlike TEST(CastableBase, As), we're dynamically casting [A -> B] without
164 // going via CastableBase.
165 auto frog = std::make_unique<Frog>();
166 auto bear = std::make_unique<Bear>();
167 auto gecko = std::make_unique<Gecko>();
168
169 ASSERT_EQ((frog->As<Animal, kDontErrorOnImpossibleCast>()),
170 static_cast<Animal*>(frog.get()));
171 ASSERT_EQ((bear->As<Animal, kDontErrorOnImpossibleCast>()),
172 static_cast<Animal*>(bear.get()));
173 ASSERT_EQ((gecko->As<Animal, kDontErrorOnImpossibleCast>()),
174 static_cast<Animal*>(gecko.get()));
175
176 ASSERT_EQ((frog->As<Amphibian, kDontErrorOnImpossibleCast>()),
177 static_cast<Amphibian*>(frog.get()));
178 ASSERT_EQ((bear->As<Amphibian, kDontErrorOnImpossibleCast>()), nullptr);
179 ASSERT_EQ((gecko->As<Amphibian, kDontErrorOnImpossibleCast>()), nullptr);
180
181 ASSERT_EQ((frog->As<Mammal, kDontErrorOnImpossibleCast>()), nullptr);
182 ASSERT_EQ((bear->As<Mammal, kDontErrorOnImpossibleCast>()),
183 static_cast<Mammal*>(bear.get()));
184 ASSERT_EQ((gecko->As<Mammal, kDontErrorOnImpossibleCast>()), nullptr);
185
186 ASSERT_EQ((frog->As<Reptile, kDontErrorOnImpossibleCast>()), nullptr);
187 ASSERT_EQ((bear->As<Reptile, kDontErrorOnImpossibleCast>()), nullptr);
188 ASSERT_EQ((gecko->As<Reptile, kDontErrorOnImpossibleCast>()),
189 static_cast<Reptile*>(gecko.get()));
190 }
191
TEST(Castable,Is)192 TEST(Castable, Is) {
193 std::unique_ptr<Animal> frog = std::make_unique<Frog>();
194 std::unique_ptr<Animal> bear = std::make_unique<Bear>();
195 std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
196
197 ASSERT_TRUE(frog->Is<Animal>());
198 ASSERT_TRUE(bear->Is<Animal>());
199 ASSERT_TRUE(gecko->Is<Animal>());
200
201 ASSERT_TRUE(frog->Is<Amphibian>());
202 ASSERT_FALSE(bear->Is<Amphibian>());
203 ASSERT_FALSE(gecko->Is<Amphibian>());
204
205 ASSERT_FALSE(frog->Is<Mammal>());
206 ASSERT_TRUE(bear->Is<Mammal>());
207 ASSERT_FALSE(gecko->Is<Mammal>());
208
209 ASSERT_FALSE(frog->Is<Reptile>());
210 ASSERT_FALSE(bear->Is<Reptile>());
211 ASSERT_TRUE(gecko->Is<Reptile>());
212 }
213
TEST(Castable,IsWithPredicate)214 TEST(Castable, IsWithPredicate) {
215 std::unique_ptr<Animal> frog = std::make_unique<Frog>();
216
217 frog->Is([&frog](const Animal* a) {
218 EXPECT_EQ(a, frog.get());
219 return true;
220 });
221
222 ASSERT_TRUE((frog->Is([](const Animal*) { return true; })));
223 ASSERT_FALSE((frog->Is([](const Animal*) { return false; })));
224
225 // Predicate not called if cast is invalid
226 auto expect_not_called = [] { FAIL() << "Should not be called"; };
227 ASSERT_FALSE((frog->Is([&](const Bear*) {
228 expect_not_called();
229 return true;
230 })));
231 }
232
TEST(Castable,As)233 TEST(Castable, As) {
234 std::unique_ptr<Animal> frog = std::make_unique<Frog>();
235 std::unique_ptr<Animal> bear = std::make_unique<Bear>();
236 std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
237
238 ASSERT_EQ(frog->As<Animal>(), static_cast<Animal*>(frog.get()));
239 ASSERT_EQ(bear->As<Animal>(), static_cast<Animal*>(bear.get()));
240 ASSERT_EQ(gecko->As<Animal>(), static_cast<Animal*>(gecko.get()));
241
242 ASSERT_EQ(frog->As<Amphibian>(), static_cast<Amphibian*>(frog.get()));
243 ASSERT_EQ(bear->As<Amphibian>(), nullptr);
244 ASSERT_EQ(gecko->As<Amphibian>(), nullptr);
245
246 ASSERT_EQ(frog->As<Mammal>(), nullptr);
247 ASSERT_EQ(bear->As<Mammal>(), static_cast<Mammal*>(bear.get()));
248 ASSERT_EQ(gecko->As<Mammal>(), nullptr);
249
250 ASSERT_EQ(frog->As<Reptile>(), nullptr);
251 ASSERT_EQ(bear->As<Reptile>(), nullptr);
252 ASSERT_EQ(gecko->As<Reptile>(), static_cast<Reptile*>(gecko.get()));
253 }
254
255 } // namespace
256
257 TINT_INSTANTIATE_TYPEINFO(Animal);
258 TINT_INSTANTIATE_TYPEINFO(Amphibian);
259 TINT_INSTANTIATE_TYPEINFO(Mammal);
260 TINT_INSTANTIATE_TYPEINFO(Reptile);
261 TINT_INSTANTIATE_TYPEINFO(Frog);
262 TINT_INSTANTIATE_TYPEINFO(Bear);
263 TINT_INSTANTIATE_TYPEINFO(Gecko);
264
265 } // namespace tint
266