• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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 <gmock/gmock.h>
16 
17 #include "common/RefBase.h"
18 
19 namespace {
20     using Id = uint32_t;
21 
22     enum class Action {
23         kReference,
24         kRelease,
25         kAssign,
26         kMarker,
27     };
28 
29     struct Event {
30         Action action;
31         Id thisId = 0;
32         Id otherId = 0;
33     };
34 
operator <<(std::ostream & os,const Event & event)35     std::ostream& operator<<(std::ostream& os, const Event& event) {
36         switch (event.action) {
37             case Action::kReference:
38                 os << "Reference " << event.thisId;
39                 break;
40             case Action::kRelease:
41                 os << "Release " << event.thisId;
42                 break;
43             case Action::kAssign:
44                 os << "Assign " << event.thisId << " <- " << event.otherId;
45                 break;
46             case Action::kMarker:
47                 os << "Marker " << event.thisId;
48                 break;
49         }
50         return os;
51     }
52 
operator ==(const Event & a,const Event & b)53     bool operator==(const Event& a, const Event& b) {
54         return a.action == b.action && a.thisId == b.thisId && a.otherId == b.otherId;
55     }
56 
57     using Events = std::vector<Event>;
58 
59     struct RefTracker {
RefTracker__anon8a55f6c90111::RefTracker60         explicit constexpr RefTracker(nullptr_t) : mId(0), mEvents(nullptr) {
61         }
62 
63         constexpr RefTracker(const RefTracker& other) = default;
64 
RefTracker__anon8a55f6c90111::RefTracker65         RefTracker(Id id, Events* events) : mId(id), mEvents(events) {
66         }
67 
Reference__anon8a55f6c90111::RefTracker68         void Reference() const {
69             mEvents->emplace_back(Event{Action::kReference, mId});
70         }
71 
Release__anon8a55f6c90111::RefTracker72         void Release() const {
73             mEvents->emplace_back(Event{Action::kRelease, mId});
74         }
75 
operator =__anon8a55f6c90111::RefTracker76         RefTracker& operator=(const RefTracker& other) {
77             if (mEvents || other.mEvents) {
78                 Events* events = mEvents ? mEvents : other.mEvents;
79                 events->emplace_back(Event{Action::kAssign, mId, other.mId});
80             }
81             mId = other.mId;
82             mEvents = other.mEvents;
83             return *this;
84         }
85 
operator ==__anon8a55f6c90111::RefTracker86         bool operator==(const RefTracker& other) const {
87             return mId == other.mId;
88         }
89 
operator !=__anon8a55f6c90111::RefTracker90         bool operator!=(const RefTracker& other) const {
91             return mId != other.mId;
92         }
93 
94         Id mId;
95         Events* mEvents;
96     };
97 
98     struct RefTrackerTraits {
99         static constexpr RefTracker kNullValue{nullptr};
100 
Reference__anon8a55f6c90111::RefTrackerTraits101         static void Reference(const RefTracker& handle) {
102             handle.Reference();
103         }
104 
Release__anon8a55f6c90111::RefTrackerTraits105         static void Release(const RefTracker& handle) {
106             handle.Release();
107         }
108     };
109 
110     constexpr RefTracker RefTrackerTraits::kNullValue;
111 
112     using Ref = RefBase<RefTracker, RefTrackerTraits>;
113 }  // namespace
114 
TEST(RefBase,Acquire)115 TEST(RefBase, Acquire) {
116     Events events;
117     RefTracker tracker1(1, &events);
118     RefTracker tracker2(2, &events);
119     Ref ref(tracker1);
120 
121     events.clear();
122     { ref.Acquire(tracker2); }
123     EXPECT_THAT(events, testing::ElementsAre(Event{Action::kRelease, 1},   // release ref
124                                              Event{Action::kAssign, 1, 2}  // acquire tracker2
125                                              ));
126 }
127 
TEST(RefBase,Detach)128 TEST(RefBase, Detach) {
129     Events events;
130     RefTracker tracker(1, &events);
131     Ref ref(tracker);
132 
133     events.clear();
134     { DAWN_UNUSED(ref.Detach()); }
135     EXPECT_THAT(events, testing::ElementsAre(Event{Action::kAssign, 1, 0}  // nullify ref
136                                              ));
137 }
138 
TEST(RefBase,Constructor)139 TEST(RefBase, Constructor) {
140     Ref ref;
141     EXPECT_EQ(ref.Get(), RefTrackerTraits::kNullValue);
142 }
143 
TEST(RefBase,ConstructDestruct)144 TEST(RefBase, ConstructDestruct) {
145     Events events;
146     RefTracker tracker(1, &events);
147 
148     events.clear();
149     {
150         Ref ref(tracker);
151         events.emplace_back(Event{Action::kMarker, 10});
152     }
153     EXPECT_THAT(events, testing::ElementsAre(Event{Action::kReference, 1},  // reference tracker
154                                              Event{Action::kMarker, 10},    //
155                                              Event{Action::kRelease, 1}     // destruct ref
156                                              ));
157 }
158 
TEST(RefBase,CopyConstruct)159 TEST(RefBase, CopyConstruct) {
160     Events events;
161     RefTracker tracker(1, &events);
162     Ref refA(tracker);
163 
164     events.clear();
165     {
166         Ref refB(refA);
167         events.emplace_back(Event{Action::kMarker, 10});
168     }
169     EXPECT_THAT(events, testing::ElementsAre(Event{Action::kReference, 1},  // reference tracker
170                                              Event{Action::kMarker, 10},    //
171                                              Event{Action::kRelease, 1}     // destruct ref
172                                              ));
173 }
174 
TEST(RefBase,RefCopyAssignment)175 TEST(RefBase, RefCopyAssignment) {
176     Events events;
177     RefTracker tracker1(1, &events);
178     RefTracker tracker2(2, &events);
179     Ref refA(tracker1);
180     Ref refB(tracker2);
181 
182     events.clear();
183     {
184         Ref ref;
185         events.emplace_back(Event{Action::kMarker, 10});
186         ref = refA;
187         events.emplace_back(Event{Action::kMarker, 20});
188         ref = refB;
189         events.emplace_back(Event{Action::kMarker, 30});
190         ref = refA;
191         events.emplace_back(Event{Action::kMarker, 40});
192     }
193     EXPECT_THAT(events, testing::ElementsAre(Event{Action::kMarker, 10},    //
194                                              Event{Action::kReference, 1},  // reference tracker1
195                                              Event{Action::kAssign, 0, 1},  // copy tracker1
196                                              Event{Action::kMarker, 20},    //
197                                              Event{Action::kReference, 2},  // reference tracker2
198                                              Event{Action::kRelease, 1},    // release tracker1
199                                              Event{Action::kAssign, 1, 2},  // copy tracker2
200                                              Event{Action::kMarker, 30},    //
201                                              Event{Action::kReference, 1},  // reference tracker1
202                                              Event{Action::kRelease, 2},    // release tracker2
203                                              Event{Action::kAssign, 2, 1},  // copy tracker1
204                                              Event{Action::kMarker, 40},    //
205                                              Event{Action::kRelease, 1}     // destruct ref
206                                              ));
207 }
208 
TEST(RefBase,RefMoveAssignment)209 TEST(RefBase, RefMoveAssignment) {
210     Events events;
211     RefTracker tracker1(1, &events);
212     RefTracker tracker2(2, &events);
213     Ref refA(tracker1);
214     Ref refB(tracker2);
215 
216     events.clear();
217     {
218         Ref ref;
219         events.emplace_back(Event{Action::kMarker, 10});
220         ref = std::move(refA);
221         events.emplace_back(Event{Action::kMarker, 20});
222         ref = std::move(refB);
223         events.emplace_back(Event{Action::kMarker, 30});
224     }
225     EXPECT_THAT(events, testing::ElementsAre(Event{Action::kMarker, 10},    //
226                                              Event{Action::kAssign, 1, 0},  // nullify refA
227                                              Event{Action::kAssign, 0, 1},  // move into ref
228                                              Event{Action::kMarker, 20},    //
229                                              Event{Action::kRelease, 1},    // release tracker1
230                                              Event{Action::kAssign, 2, 0},  // nullify refB
231                                              Event{Action::kAssign, 1, 2},  // move into ref
232                                              Event{Action::kMarker, 30},    //
233                                              Event{Action::kRelease, 2}     // destruct ref
234                                              ));
235 }
236 
TEST(RefBase,RefCopyAssignmentSelf)237 TEST(RefBase, RefCopyAssignmentSelf) {
238     Events events;
239     RefTracker tracker(1, &events);
240     Ref ref(tracker);
241     Ref& self = ref;
242 
243     events.clear();
244     {
245         ref = self;
246         ref = self;
247         ref = self;
248     }
249     EXPECT_THAT(events, testing::ElementsAre());
250 }
251 
TEST(RefBase,RefMoveAssignmentSelf)252 TEST(RefBase, RefMoveAssignmentSelf) {
253     Events events;
254     RefTracker tracker(1, &events);
255     Ref ref(tracker);
256     Ref& self = ref;
257 
258     events.clear();
259     {
260         ref = std::move(self);
261         ref = std::move(self);
262         ref = std::move(self);
263     }
264     EXPECT_THAT(events, testing::ElementsAre());
265 }
266 
TEST(RefBase,TCopyAssignment)267 TEST(RefBase, TCopyAssignment) {
268     Events events;
269     RefTracker tracker(1, &events);
270     Ref ref;
271 
272     events.clear();
273     {
274         ref = tracker;
275         ref = tracker;
276         ref = tracker;
277     }
278     EXPECT_THAT(events, testing::ElementsAre(Event{Action::kReference, 1},  //
279                                              Event{Action::kAssign, 0, 1}));
280 }
281 
TEST(RefBase,TMoveAssignment)282 TEST(RefBase, TMoveAssignment) {
283     Events events;
284     RefTracker tracker(1, &events);
285     Ref ref;
286 
287     events.clear();
288     { ref = std::move(tracker); }
289     EXPECT_THAT(events, testing::ElementsAre(Event{Action::kReference, 1},  //
290                                              Event{Action::kAssign, 0, 1}));
291 }
292 
TEST(RefBase,TCopyAssignmentAlternate)293 TEST(RefBase, TCopyAssignmentAlternate) {
294     Events events;
295     RefTracker tracker1(1, &events);
296     RefTracker tracker2(2, &events);
297     Ref ref;
298 
299     events.clear();
300     {
301         ref = tracker1;
302         events.emplace_back(Event{Action::kMarker, 10});
303         ref = tracker2;
304         events.emplace_back(Event{Action::kMarker, 20});
305         ref = tracker1;
306         events.emplace_back(Event{Action::kMarker, 30});
307     }
308     EXPECT_THAT(events, testing::ElementsAre(Event{Action::kReference, 1},  // reference tracker1
309                                              Event{Action::kAssign, 0, 1},  // copy tracker1
310                                              Event{Action::kMarker, 10},    //
311                                              Event{Action::kReference, 2},  // reference tracker2
312                                              Event{Action::kRelease, 1},    // release tracker1
313                                              Event{Action::kAssign, 1, 2},  // copy tracker2
314                                              Event{Action::kMarker, 20},    //
315                                              Event{Action::kReference, 1},  // reference tracker1
316                                              Event{Action::kRelease, 2},    // release tracker2
317                                              Event{Action::kAssign, 2, 1},  // copy tracker1
318                                              Event{Action::kMarker, 30}));
319 }
320