1/*
2 * Copyright (C) 2016 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#include "Counters.h"
29#include "RefLogger.h"
30#include <wtf/Ref.h>
31#include <wtf/RefPtr.h>
32#include <wtf/StdLibExtras.h>
33#include <wtf/Variant.h>
34#include <wtf/text/WTFString.h>
35
36namespace TestWebKitAPI {
37
38TEST(WTF_Variant, Initial)
39{
40 Variant<int, double> v1;
41 EXPECT_TRUE(v1.index() == 0);
42 EXPECT_TRUE(WTF::get<int>(v1) == 0);
43
44 struct T {
45 T() : value(15) { }
46 int value;
47 };
48
49 Variant<T, int> v2;
50 EXPECT_TRUE(v2.index() == 0);
51 EXPECT_TRUE(WTF::get<T>(v2).value == 15);
52}
53
54TEST(WTF_Variant, Basic)
55{
56 Variant<int, double> variant = 1;
57 EXPECT_TRUE(variant.index() == 0);
58 EXPECT_TRUE(WTF::get<int>(variant) == 1);
59 EXPECT_TRUE(*WTF::get_if<int>(variant) == 1);
60 EXPECT_TRUE(WTF::get_if<double>(variant) == nullptr);
61 EXPECT_TRUE(WTF::holds_alternative<int>(variant));
62 EXPECT_FALSE(WTF::holds_alternative<double>(variant));
63
64 variant = 1.0;
65 EXPECT_TRUE(variant.index() == 1);
66 EXPECT_TRUE(WTF::get<double>(variant) == 1);
67 EXPECT_TRUE(*WTF::get_if<double>(variant) == 1.0);
68 EXPECT_TRUE(WTF::get_if<int>(variant) == nullptr);
69 EXPECT_TRUE(WTF::holds_alternative<double>(variant));
70 EXPECT_FALSE(WTF::holds_alternative<int>(variant));
71}
72
73TEST(WTF_Variant, BasicVisitor)
74{
75 enum class Type {
76 None,
77 Int,
78 Float,
79 String,
80 };
81
82 struct Visitor {
83 Visitor(Type& t)
84 : type(t)
85 {
86 }
87
88 Type& type;
89
90 void operator()(int) const { type = Type::Int; }
91 void operator()(float) const { type = Type::Float; }
92 void operator()(String) const { type = Type::String; }
93 };
94
95 Type type = Type::None;
96
97 Variant<int, float, String> variant = 8;
98 WTF::visit(Visitor(type), variant);
99 EXPECT_TRUE(Type::Int == type);
100
101
102 variant = 1.0f;
103 WTF::visit(Visitor(type), variant);
104 EXPECT_TRUE(Type::Float == type);
105
106
107 variant = "hello";
108 WTF::visit(Visitor(type), variant);
109 EXPECT_TRUE(Type::String == type);
110}
111
112#if USE(CF)
113TEST(WTF_Variant, RetainPtr)
114{
115 enum class Type {
116 None,
117 RefPtr,
118 RetainPtr,
119 };
120
121 Type type = Type::None;
122
123 auto visitor = WTF::makeVisitor(
124 [&](const RefPtr<RefLogger>&) { type = Type::RefPtr; },
125 [&](const RetainPtr<CFDataRef>&) { type = Type::RetainPtr; }
126 );
127
128 RefPtr<RefLogger> refPtr;
129 RetainPtr<CFDataRef> retainPtr;
130 Variant<RefPtr<RefLogger>, RetainPtr<CFDataRef>> variant(WTFMove(refPtr));
131 WTF::visit(visitor, variant);
132 EXPECT_TRUE(Type::RefPtr == type);
133
134 variant = WTFMove(retainPtr);
135 WTF::visit(visitor, variant);
136 EXPECT_TRUE(Type::RetainPtr == type);
137}
138#endif
139
140TEST(WTF_Variant, VisitorUsingMakeVisitor)
141{
142 enum class Type {
143 None,
144 Int,
145 Float,
146 String,
147 };
148
149 Type type = Type::None;
150
151 auto visitor = WTF::makeVisitor(
152 [&](int) { type = Type::Int; },
153 [&](float) { type = Type::Float; },
154 [&](String) { type = Type::String; }
155 );
156
157 Variant<int, float, String> variant = 8;
158 WTF::visit(visitor, variant);
159 EXPECT_TRUE(Type::Int == type);
160
161
162 variant = 1.0f;
163 WTF::visit(visitor, variant);
164 EXPECT_TRUE(Type::Float == type);
165
166
167 variant = "hello";
168 WTF::visit(visitor, variant);
169 EXPECT_TRUE(Type::String == type);
170}
171
172TEST(WTF_Variant, VisitorUsingSwitchOn)
173{
174 enum class Type {
175 None,
176 Int,
177 Float,
178 String,
179 };
180
181 Type type = Type::None;
182
183 Variant<int, float, String> variant = 8;
184 type = WTF::switchOn(variant,
185 [](int) { return Type::Int; },
186 [](float) { return Type::Float; },
187 [](String) { return Type::String; }
188 );
189 EXPECT_TRUE(Type::Int == type);
190
191
192 variant = 1.0f;
193 type = WTF::switchOn(variant,
194 [](int) { return Type::Int; },
195 [](float) { return Type::Float; },
196 [](String) { return Type::String; }
197 );
198 EXPECT_TRUE(Type::Float == type);
199
200
201 variant = "hello";
202 type = WTF::switchOn(variant,
203 [](int) { return Type::Int; },
204 [](float) { return Type::Float; },
205 [](String) { return Type::String; }
206 );
207 EXPECT_TRUE(Type::String == type);
208}
209
210TEST(WTF_Variant, ConstructorDestructor)
211{
212 ConstructorDestructorCounter::TestingScope scope;
213
214 {
215 auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
216 Variant<std::unique_ptr<ConstructorDestructorCounter>, int> v = WTFMove(uniquePtr);
217
218 EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
219 EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
220 }
221
222 EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
223 EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
224}
225
226TEST(WTF_Variant, RefPtr)
227{
228 {
229 RefLogger a("a");
230 RefPtr<RefLogger> ref(&a);
231 Variant<RefPtr<RefLogger>, int> v = ref;
232 }
233
234 ASSERT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
235
236 {
237 RefLogger a("a");
238 RefPtr<RefLogger> ref(&a);
239 Variant<RefPtr<RefLogger>, int> v = WTFMove(ref);
240 }
241
242 ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
243}
244
245TEST(WTF_Variant, Ref)
246{
247 {
248 RefLogger a("a");
249 Ref<RefLogger> ref(a);
250 Variant<Ref<RefLogger>, int> v = WTFMove(ref);
251 }
252
253 ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
254}
255
256template<class T>
257class Holder {
258public:
259 T data;
260
261 Holder(T data) : data(data) { }
262
263 T* operator&() { return &data; }
264};
265
266TEST(WTF_Variant, OperatorAmpersand)
267{
268 Variant<Holder<int>, int> v = Holder<int>(10);
269 EXPECT_TRUE(WTF::get<Holder<int>>(v).data == 10);
270
271 v = 20;
272 EXPECT_TRUE(WTF::get<int>(v) == 20);
273}
274
275}
276