• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Dawn 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 <gtest/gtest.h>
16 
17 #include "common/RefCounted.h"
18 #include "common/Result.h"
19 
20 namespace {
21 
22     template <typename T, typename E>
TestError(Result<T,E> * result,E expectedError)23     void TestError(Result<T, E>* result, E expectedError) {
24         EXPECT_TRUE(result->IsError());
25         EXPECT_FALSE(result->IsSuccess());
26 
27         std::unique_ptr<E> storedError = result->AcquireError();
28         EXPECT_EQ(*storedError, expectedError);
29     }
30 
31     template <typename T, typename E>
TestSuccess(Result<T,E> * result,T expectedSuccess)32     void TestSuccess(Result<T, E>* result, T expectedSuccess) {
33         EXPECT_FALSE(result->IsError());
34         EXPECT_TRUE(result->IsSuccess());
35 
36         const T storedSuccess = result->AcquireSuccess();
37         EXPECT_EQ(storedSuccess, expectedSuccess);
38 
39         // Once the success is acquired, result has an empty
40         // payload and is neither in the success nor error state.
41         EXPECT_FALSE(result->IsError());
42         EXPECT_FALSE(result->IsSuccess());
43     }
44 
45     static int dummyError = 0xbeef;
46     static float dummySuccess = 42.0f;
47     static const float dummyConstSuccess = 42.0f;
48 
49     class AClass : public RefCounted {
50       public:
51         int a = 0;
52     };
53 
54     // Tests using the following overload of TestSuccess make
55     // local Ref instances to dummySuccessObj. Tests should
56     // ensure any local Ref objects made along the way continue
57     // to point to dummySuccessObj.
58     template <typename T, typename E>
TestSuccess(Result<Ref<T>,E> * result,T * expectedSuccess)59     void TestSuccess(Result<Ref<T>, E>* result, T* expectedSuccess) {
60         EXPECT_FALSE(result->IsError());
61         EXPECT_TRUE(result->IsSuccess());
62 
63         // AClass starts with a reference count of 1 and stored
64         // on the stack in the caller. The result parameter should
65         // hold the only other reference to the object.
66         EXPECT_EQ(expectedSuccess->GetRefCountForTesting(), 2u);
67 
68         const Ref<T> storedSuccess = result->AcquireSuccess();
69         EXPECT_EQ(storedSuccess.Get(), expectedSuccess);
70 
71         // Once the success is acquired, result has an empty
72         // payload and is neither in the success nor error state.
73         EXPECT_FALSE(result->IsError());
74         EXPECT_FALSE(result->IsSuccess());
75 
76         // Once we call AcquireSuccess, result no longer stores
77         // the object. storedSuccess should contain the only other
78         // reference to the object.
79         EXPECT_EQ(storedSuccess->GetRefCountForTesting(), 2u);
80     }
81 
82     // Result<void, E*>
83 
84     // Test constructing an error Result<void, E>
TEST(ResultOnlyPointerError,ConstructingError)85     TEST(ResultOnlyPointerError, ConstructingError) {
86         Result<void, int> result(std::make_unique<int>(dummyError));
87         TestError(&result, dummyError);
88     }
89 
90     // Test moving an error Result<void, E>
TEST(ResultOnlyPointerError,MovingError)91     TEST(ResultOnlyPointerError, MovingError) {
92         Result<void, int> result(std::make_unique<int>(dummyError));
93         Result<void, int> movedResult(std::move(result));
94         TestError(&movedResult, dummyError);
95     }
96 
97     // Test returning an error Result<void, E>
TEST(ResultOnlyPointerError,ReturningError)98     TEST(ResultOnlyPointerError, ReturningError) {
99         auto CreateError = []() -> Result<void, int> {
100             return {std::make_unique<int>(dummyError)};
101         };
102 
103         Result<void, int> result = CreateError();
104         TestError(&result, dummyError);
105     }
106 
107     // Test constructing a success Result<void, E>
TEST(ResultOnlyPointerError,ConstructingSuccess)108     TEST(ResultOnlyPointerError, ConstructingSuccess) {
109         Result<void, int> result;
110         EXPECT_TRUE(result.IsSuccess());
111         EXPECT_FALSE(result.IsError());
112     }
113 
114     // Test moving a success Result<void, E>
TEST(ResultOnlyPointerError,MovingSuccess)115     TEST(ResultOnlyPointerError, MovingSuccess) {
116         Result<void, int> result;
117         Result<void, int> movedResult(std::move(result));
118         EXPECT_TRUE(movedResult.IsSuccess());
119         EXPECT_FALSE(movedResult.IsError());
120     }
121 
122     // Test returning a success Result<void, E>
TEST(ResultOnlyPointerError,ReturningSuccess)123     TEST(ResultOnlyPointerError, ReturningSuccess) {
124         auto CreateError = []() -> Result<void, int> { return {}; };
125 
126         Result<void, int> result = CreateError();
127         EXPECT_TRUE(result.IsSuccess());
128         EXPECT_FALSE(result.IsError());
129     }
130 
131     // Result<T*, E*>
132 
133     // Test constructing an error Result<T*, E>
TEST(ResultBothPointer,ConstructingError)134     TEST(ResultBothPointer, ConstructingError) {
135         Result<float*, int> result(std::make_unique<int>(dummyError));
136         TestError(&result, dummyError);
137     }
138 
139     // Test moving an error Result<T*, E>
TEST(ResultBothPointer,MovingError)140     TEST(ResultBothPointer, MovingError) {
141         Result<float*, int> result(std::make_unique<int>(dummyError));
142         Result<float*, int> movedResult(std::move(result));
143         TestError(&movedResult, dummyError);
144     }
145 
146     // Test returning an error Result<T*, E>
TEST(ResultBothPointer,ReturningError)147     TEST(ResultBothPointer, ReturningError) {
148         auto CreateError = []() -> Result<float*, int> {
149             return {std::make_unique<int>(dummyError)};
150         };
151 
152         Result<float*, int> result = CreateError();
153         TestError(&result, dummyError);
154     }
155 
156     // Test constructing a success Result<T*, E>
TEST(ResultBothPointer,ConstructingSuccess)157     TEST(ResultBothPointer, ConstructingSuccess) {
158         Result<float*, int> result(&dummySuccess);
159         TestSuccess(&result, &dummySuccess);
160     }
161 
162     // Test moving a success Result<T*, E>
TEST(ResultBothPointer,MovingSuccess)163     TEST(ResultBothPointer, MovingSuccess) {
164         Result<float*, int> result(&dummySuccess);
165         Result<float*, int> movedResult(std::move(result));
166         TestSuccess(&movedResult, &dummySuccess);
167     }
168 
169     // Test returning a success Result<T*, E>
TEST(ResultBothPointer,ReturningSuccess)170     TEST(ResultBothPointer, ReturningSuccess) {
171         auto CreateSuccess = []() -> Result<float*, int*> { return {&dummySuccess}; };
172 
173         Result<float*, int*> result = CreateSuccess();
174         TestSuccess(&result, &dummySuccess);
175     }
176 
177     // Tests converting from a Result<TChild*, E>
TEST(ResultBothPointer,ConversionFromChildClass)178     TEST(ResultBothPointer, ConversionFromChildClass) {
179         struct T {
180             int a;
181         };
182         struct TChild : T {};
183 
184         TChild child;
185         T* childAsT = &child;
186         {
187             Result<T*, int> result(&child);
188             TestSuccess(&result, childAsT);
189         }
190         {
191             Result<TChild*, int> resultChild(&child);
192             Result<T*, int> result(std::move(resultChild));
193             TestSuccess(&result, childAsT);
194         }
195         {
196             Result<TChild*, int> resultChild(&child);
197             Result<T*, int> result = std::move(resultChild);
198             TestSuccess(&result, childAsT);
199         }
200     }
201 
202     // Result<const T*, E>
203 
204     // Test constructing an error Result<const T*, E>
TEST(ResultBothPointerWithConstResult,ConstructingError)205     TEST(ResultBothPointerWithConstResult, ConstructingError) {
206         Result<const float*, int> result(std::make_unique<int>(dummyError));
207         TestError(&result, dummyError);
208     }
209 
210     // Test moving an error Result<const T*, E>
TEST(ResultBothPointerWithConstResult,MovingError)211     TEST(ResultBothPointerWithConstResult, MovingError) {
212         Result<const float*, int> result(std::make_unique<int>(dummyError));
213         Result<const float*, int> movedResult(std::move(result));
214         TestError(&movedResult, dummyError);
215     }
216 
217     // Test returning an error Result<const T*, E*>
TEST(ResultBothPointerWithConstResult,ReturningError)218     TEST(ResultBothPointerWithConstResult, ReturningError) {
219         auto CreateError = []() -> Result<const float*, int> {
220             return {std::make_unique<int>(dummyError)};
221         };
222 
223         Result<const float*, int> result = CreateError();
224         TestError(&result, dummyError);
225     }
226 
227     // Test constructing a success Result<const T*, E*>
TEST(ResultBothPointerWithConstResult,ConstructingSuccess)228     TEST(ResultBothPointerWithConstResult, ConstructingSuccess) {
229         Result<const float*, int> result(&dummyConstSuccess);
230         TestSuccess(&result, &dummyConstSuccess);
231     }
232 
233     // Test moving a success Result<const T*, E*>
TEST(ResultBothPointerWithConstResult,MovingSuccess)234     TEST(ResultBothPointerWithConstResult, MovingSuccess) {
235         Result<const float*, int> result(&dummyConstSuccess);
236         Result<const float*, int> movedResult(std::move(result));
237         TestSuccess(&movedResult, &dummyConstSuccess);
238     }
239 
240     // Test returning a success Result<const T*, E*>
TEST(ResultBothPointerWithConstResult,ReturningSuccess)241     TEST(ResultBothPointerWithConstResult, ReturningSuccess) {
242         auto CreateSuccess = []() -> Result<const float*, int> { return {&dummyConstSuccess}; };
243 
244         Result<const float*, int> result = CreateSuccess();
245         TestSuccess(&result, &dummyConstSuccess);
246     }
247 
248     // Result<Ref<T>, E>
249 
250     // Test constructing an error Result<Ref<T>, E>
TEST(ResultRefT,ConstructingError)251     TEST(ResultRefT, ConstructingError) {
252         Result<Ref<AClass>, int> result(std::make_unique<int>(dummyError));
253         TestError(&result, dummyError);
254     }
255 
256     // Test moving an error Result<Ref<T>, E>
TEST(ResultRefT,MovingError)257     TEST(ResultRefT, MovingError) {
258         Result<Ref<AClass>, int> result(std::make_unique<int>(dummyError));
259         Result<Ref<AClass>, int> movedResult(std::move(result));
260         TestError(&movedResult, dummyError);
261     }
262 
263     // Test returning an error Result<Ref<T>, E>
TEST(ResultRefT,ReturningError)264     TEST(ResultRefT, ReturningError) {
265         auto CreateError = []() -> Result<Ref<AClass>, int> {
266             return {std::make_unique<int>(dummyError)};
267         };
268 
269         Result<Ref<AClass>, int> result = CreateError();
270         TestError(&result, dummyError);
271     }
272 
273     // Test constructing a success Result<Ref<T>, E>
TEST(ResultRefT,ConstructingSuccess)274     TEST(ResultRefT, ConstructingSuccess) {
275         AClass success;
276 
277         Ref<AClass> refObj(&success);
278         Result<Ref<AClass>, int> result(std::move(refObj));
279         TestSuccess(&result, &success);
280     }
281 
282     // Test moving a success Result<Ref<T>, E>
TEST(ResultRefT,MovingSuccess)283     TEST(ResultRefT, MovingSuccess) {
284         AClass success;
285 
286         Ref<AClass> refObj(&success);
287         Result<Ref<AClass>, int> result(std::move(refObj));
288         Result<Ref<AClass>, int> movedResult(std::move(result));
289         TestSuccess(&movedResult, &success);
290     }
291 
292     // Test returning a success Result<Ref<T>, E>
TEST(ResultRefT,ReturningSuccess)293     TEST(ResultRefT, ReturningSuccess) {
294         AClass success;
295         auto CreateSuccess = [&success]() -> Result<Ref<AClass>, int> {
296             return Ref<AClass>(&success);
297         };
298 
299         Result<Ref<AClass>, int> result = CreateSuccess();
300         TestSuccess(&result, &success);
301     }
302 
303     class OtherClass {
304       public:
305         int a = 0;
306     };
307     class Base : public RefCounted {};
308     class Child : public OtherClass, public Base {};
309 
310     // Test constructing a Result<Ref<TChild>, E>
TEST(ResultRefT,ConversionFromChildConstructor)311     TEST(ResultRefT, ConversionFromChildConstructor) {
312         Child child;
313         Ref<Child> refChild(&child);
314 
315         Result<Ref<Base>, int> result(std::move(refChild));
316         TestSuccess<Base>(&result, &child);
317     }
318 
319     // Test copy constructing Result<Ref<TChild>, E>
TEST(ResultRefT,ConversionFromChildCopyConstructor)320     TEST(ResultRefT, ConversionFromChildCopyConstructor) {
321         Child child;
322         Ref<Child> refChild(&child);
323 
324         Result<Ref<Child>, int> resultChild(std::move(refChild));
325         Result<Ref<Base>, int> result(std::move(resultChild));
326         TestSuccess<Base>(&result, &child);
327     }
328 
329     // Test assignment operator for Result<Ref<TChild>, E>
TEST(ResultRefT,ConversionFromChildAssignmentOperator)330     TEST(ResultRefT, ConversionFromChildAssignmentOperator) {
331         Child child;
332         Ref<Child> refChild(&child);
333 
334         Result<Ref<Child>, int> resultChild(std::move(refChild));
335         Result<Ref<Base>, int> result = std::move(resultChild);
336         TestSuccess<Base>(&result, &child);
337     }
338 
339     // Result<T, E>
340 
341     // Test constructing an error Result<T, E>
TEST(ResultGeneric,ConstructingError)342     TEST(ResultGeneric, ConstructingError) {
343         Result<std::vector<float>, int> result(std::make_unique<int>(dummyError));
344         TestError(&result, dummyError);
345     }
346 
347     // Test moving an error Result<T, E>
TEST(ResultGeneric,MovingError)348     TEST(ResultGeneric, MovingError) {
349         Result<std::vector<float>, int> result(std::make_unique<int>(dummyError));
350         Result<std::vector<float>, int> movedResult(std::move(result));
351         TestError(&movedResult, dummyError);
352     }
353 
354     // Test returning an error Result<T, E>
TEST(ResultGeneric,ReturningError)355     TEST(ResultGeneric, ReturningError) {
356         auto CreateError = []() -> Result<std::vector<float>, int> {
357             return {std::make_unique<int>(dummyError)};
358         };
359 
360         Result<std::vector<float>, int> result = CreateError();
361         TestError(&result, dummyError);
362     }
363 
364     // Test constructing a success Result<T, E>
TEST(ResultGeneric,ConstructingSuccess)365     TEST(ResultGeneric, ConstructingSuccess) {
366         Result<std::vector<float>, int> result({1.0f});
367         TestSuccess(&result, {1.0f});
368     }
369 
370     // Test moving a success Result<T, E>
TEST(ResultGeneric,MovingSuccess)371     TEST(ResultGeneric, MovingSuccess) {
372         Result<std::vector<float>, int> result({1.0f});
373         Result<std::vector<float>, int> movedResult(std::move(result));
374         TestSuccess(&movedResult, {1.0f});
375     }
376 
377     // Test returning a success Result<T, E>
TEST(ResultGeneric,ReturningSuccess)378     TEST(ResultGeneric, ReturningSuccess) {
379         auto CreateSuccess = []() -> Result<std::vector<float>, int> { return {{1.0f}}; };
380 
381         Result<std::vector<float>, int> result = CreateSuccess();
382         TestSuccess(&result, {1.0f});
383     }
384 
385 }  // anonymous namespace
386