1 // Copyright 2017 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 "dawn/webgpu_cpp.h"
18 
19 class Object : public wgpu::ObjectBase<Object, int*> {
20   public:
21     using ObjectBase::ObjectBase;
22     using ObjectBase::operator=;
23 
WGPUReference(int * handle)24     static void WGPUReference(int* handle) {
25         ASSERT_LE(0, *handle);
26         *handle += 1;
27     }
WGPURelease(int * handle)28     static void WGPURelease(int* handle) {
29         ASSERT_LT(0, *handle);
30         *handle -= 1;
31     }
32 };
33 
34 // Test that creating an C++ object from a C object takes a ref.
35 // Also test that the C++ object destructor removes a ref.
TEST(ObjectBase,CTypeConstructor)36 TEST(ObjectBase, CTypeConstructor) {
37     int refcount = 1;
38     {
39         Object obj(&refcount);
40         ASSERT_EQ(2, refcount);
41     }
42     ASSERT_EQ(1, refcount);
43 }
44 
45 // Test consuming a C object into a C++ object doesn't take a ref.
TEST(ObjectBase,AcquireConstruction)46 TEST(ObjectBase, AcquireConstruction) {
47     int refcount = 1;
48     {
49         Object object = Object::Acquire(&refcount);
50         ASSERT_EQ(1, refcount);
51     }
52     ASSERT_EQ(0, refcount);
53 }
54 
55 // Test .Get().
TEST(ObjectBase,Get)56 TEST(ObjectBase, Get) {
57     int refcount = 1;
58     {
59         Object obj1(&refcount);
60 
61         ASSERT_EQ(2, refcount);
62         ASSERT_EQ(&refcount, obj1.Get());
63     }
64     ASSERT_EQ(1, refcount);
65 }
66 
67 // Test that Release consumes the C++ object into a C object and doesn't release
TEST(ObjectBase,Release)68 TEST(ObjectBase, Release) {
69     int refcount = 1;
70     {
71         Object obj(&refcount);
72         ASSERT_EQ(2, refcount);
73 
74         ASSERT_EQ(&refcount, obj.Release());
75         ASSERT_EQ(nullptr, obj.Get());
76         ASSERT_EQ(2, refcount);
77     }
78     ASSERT_EQ(2, refcount);
79 }
80 
81 // Test using C++ objects in conditions
TEST(ObjectBase,OperatorBool)82 TEST(ObjectBase, OperatorBool) {
83     int refcount = 1;
84     Object trueObj(&refcount);
85     Object falseObj;
86 
87     if (falseObj || !trueObj) {
88         ASSERT_TRUE(false);
89     }
90 }
91 
92 // Test the copy constructor of C++ objects
TEST(ObjectBase,CopyConstructor)93 TEST(ObjectBase, CopyConstructor) {
94     int refcount = 1;
95 
96     Object source(&refcount);
97     Object destination(source);
98 
99     ASSERT_EQ(source.Get(), &refcount);
100     ASSERT_EQ(destination.Get(), &refcount);
101     ASSERT_EQ(3, refcount);
102 
103     destination = Object();
104     ASSERT_EQ(refcount, 2);
105 }
106 
107 // Test the copy assignment of C++ objects
TEST(ObjectBase,CopyAssignment)108 TEST(ObjectBase, CopyAssignment) {
109     int refcount = 1;
110     Object source(&refcount);
111 
112     Object destination;
113     destination = source;
114 
115     ASSERT_EQ(source.Get(), &refcount);
116     ASSERT_EQ(destination.Get(), &refcount);
117     ASSERT_EQ(3, refcount);
118 
119     destination = Object();
120     ASSERT_EQ(refcount, 2);
121 }
122 
123 // Test the copy assignment of C++ objects onto themselves
TEST(ObjectBase,CopyAssignmentSelf)124 TEST(ObjectBase, CopyAssignmentSelf) {
125     int refcount = 1;
126 
127     Object obj(&refcount);
128 
129     // Fool the compiler to avoid a -Wself-assign-overload
130     Object* objPtr = &obj;
131     obj = *objPtr;
132 
133     ASSERT_EQ(obj.Get(), &refcount);
134     ASSERT_EQ(refcount, 2);
135 }
136 
137 // Test the move constructor of C++ objects
TEST(ObjectBase,MoveConstructor)138 TEST(ObjectBase, MoveConstructor) {
139     int refcount = 1;
140     Object source(&refcount);
141     Object destination(std::move(source));
142 
143     ASSERT_EQ(source.Get(), nullptr);
144     ASSERT_EQ(destination.Get(), &refcount);
145     ASSERT_EQ(2, refcount);
146 
147     destination = Object();
148     ASSERT_EQ(refcount, 1);
149 }
150 
151 // Test the move assignment of C++ objects
TEST(ObjectBase,MoveAssignment)152 TEST(ObjectBase, MoveAssignment) {
153     int refcount = 1;
154     Object source(&refcount);
155 
156     Object destination;
157     destination = std::move(source);
158 
159     ASSERT_EQ(source.Get(), nullptr);
160     ASSERT_EQ(destination.Get(), &refcount);
161     ASSERT_EQ(2, refcount);
162 
163     destination = Object();
164     ASSERT_EQ(refcount, 1);
165 }
166 
167 // Test the move assignment of C++ objects onto themselves
TEST(ObjectBase,MoveAssignmentSelf)168 TEST(ObjectBase, MoveAssignmentSelf) {
169     int refcount = 1;
170 
171     Object obj(&refcount);
172 
173     // Fool the compiler to avoid a -Wself-move
174     Object* objPtr = &obj;
175     obj = std::move(*objPtr);
176 
177     ASSERT_EQ(obj.Get(), &refcount);
178     ASSERT_EQ(refcount, 2);
179 }
180 
181 // Test the constructor using nullptr
TEST(ObjectBase,NullptrConstructor)182 TEST(ObjectBase, NullptrConstructor) {
183     Object obj(nullptr);
184     ASSERT_EQ(obj.Get(), nullptr);
185 }
186 
187 // Test assigning nullptr to the object
TEST(ObjectBase,AssignNullptr)188 TEST(ObjectBase, AssignNullptr) {
189     int refcount = 1;
190 
191     Object obj(&refcount);
192     ASSERT_EQ(refcount, 2);
193 
194     obj = nullptr;
195     ASSERT_EQ(refcount, 1);
196 }
197