Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
weak_ptr_unittest.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#define FML_USED_ON_EMBEDDER
6
7#include "flutter/fml/memory/weak_ptr.h"
8
9#include <thread>
10#include <utility>
11
12#include "flutter/fml/message_loop.h"
13#include "flutter/fml/raster_thread_merger.h"
14#include "flutter/fml/synchronization/count_down_latch.h"
15#include "gtest/gtest.h"
16
17namespace fml {
18namespace {
19
20TEST(WeakPtrTest, Basic) {
21 int data = 0;
22 WeakPtrFactory<int> factory(&data);
23 WeakPtr<int> ptr = factory.GetWeakPtr();
24 EXPECT_EQ(&data, ptr.get());
25}
26
27TEST(WeakPtrTest, CopyConstruction) {
28 int data = 0;
29 WeakPtrFactory<int> factory(&data);
30 WeakPtr<int> ptr = factory.GetWeakPtr();
31 const WeakPtr<int>& ptr2(ptr);
32 EXPECT_EQ(&data, ptr.get());
33 EXPECT_EQ(&data, ptr2.get());
34}
35
36TEST(WeakPtrTest, MoveConstruction) {
37 int data = 0;
38 WeakPtrFactory<int> factory(&data);
39 WeakPtr<int> ptr = factory.GetWeakPtr();
40 WeakPtr<int> ptr2(std::move(ptr));
41 // The clang linter flags the method called on the moved-from reference, but
42 // this is testing the move implementation, so it is marked NOLINT.
43 EXPECT_EQ(nullptr, ptr.get()); // NOLINT
44 EXPECT_EQ(&data, ptr2.get());
45}
46
47TEST(WeakPtrTest, CopyAssignment) {
48 int data = 0;
49 WeakPtrFactory<int> factory(&data);
50 WeakPtr<int> ptr = factory.GetWeakPtr();
51 WeakPtr<int> ptr2;
52 EXPECT_EQ(nullptr, ptr2.get());
53 ptr2 = ptr;
54 EXPECT_EQ(&data, ptr.get());
55 EXPECT_EQ(&data, ptr2.get());
56}
57
58TEST(WeakPtrTest, MoveAssignment) {
59 int data = 0;
60 WeakPtrFactory<int> factory(&data);
61 WeakPtr<int> ptr = factory.GetWeakPtr();
62 WeakPtr<int> ptr2;
63 EXPECT_EQ(nullptr, ptr2.get());
64 ptr2 = std::move(ptr);
65 // The clang linter flags the method called on the moved-from reference, but
66 // this is testing the move implementation, so it is marked NOLINT.
67 EXPECT_EQ(nullptr, ptr.get()); // NOLINT
68 EXPECT_EQ(&data, ptr2.get());
69}
70
71TEST(WeakPtrTest, Testable) {
72 int data = 0;
73 WeakPtrFactory<int> factory(&data);
74 WeakPtr<int> ptr;
75 EXPECT_EQ(nullptr, ptr.get());
76 EXPECT_FALSE(ptr);
77 ptr = factory.GetWeakPtr();
78 EXPECT_EQ(&data, ptr.get());
79 EXPECT_TRUE(ptr);
80}
81
82TEST(WeakPtrTest, OutOfScope) {
83 WeakPtr<int> ptr;
84 EXPECT_EQ(nullptr, ptr.get());
85 {
86 int data = 0;
87 WeakPtrFactory<int> factory(&data);
88 ptr = factory.GetWeakPtr();
89 }
90 EXPECT_EQ(nullptr, ptr.get());
91}
92
93TEST(WeakPtrTest, Multiple) {
94 WeakPtr<int> a;
95 WeakPtr<int> b;
96 {
97 int data = 0;
98 WeakPtrFactory<int> factory(&data);
99 a = factory.GetWeakPtr();
100 b = factory.GetWeakPtr();
101 EXPECT_EQ(&data, a.get());
102 EXPECT_EQ(&data, b.get());
103 }
104 EXPECT_EQ(nullptr, a.get());
105 EXPECT_EQ(nullptr, b.get());
106}
107
108TEST(WeakPtrTest, MultipleStaged) {
109 WeakPtr<int> a;
110 {
111 int data = 0;
112 WeakPtrFactory<int> factory(&data);
113 a = factory.GetWeakPtr();
114 { WeakPtr<int> b = factory.GetWeakPtr(); }
115 EXPECT_NE(a.get(), nullptr);
116 }
117 EXPECT_EQ(nullptr, a.get());
118}
119
120struct Base {
121 double member = 0.;
122};
123struct Derived : public Base {};
124
125TEST(WeakPtrTest, Dereference) {
126 Base data;
127 data.member = 123456.;
128 WeakPtrFactory<Base> factory(&data);
129 WeakPtr<Base> ptr = factory.GetWeakPtr();
130 EXPECT_EQ(&data, ptr.get());
131 EXPECT_EQ(data.member, (*ptr).member);
132 EXPECT_EQ(data.member, ptr->member);
133}
134
135TEST(WeakPtrTest, UpcastCopyConstruction) {
136 Derived data;
137 WeakPtrFactory<Derived> factory(&data);
138 WeakPtr<Derived> ptr = factory.GetWeakPtr();
139 WeakPtr<Base> ptr2(ptr);
140 EXPECT_EQ(&data, ptr.get());
141 EXPECT_EQ(&data, ptr2.get());
142}
143
144TEST(WeakPtrTest, UpcastMoveConstruction) {
145 Derived data;
146 WeakPtrFactory<Derived> factory(&data);
147 WeakPtr<Derived> ptr = factory.GetWeakPtr();
148 WeakPtr<Base> ptr2(std::move(ptr));
149 // The clang linter flags the method called on the moved-from reference, but
150 // this is testing the move implementation, so it is marked NOLINT.
151 EXPECT_EQ(nullptr, ptr.get()); // NOLINT
152 EXPECT_EQ(&data, ptr2.get());
153}
154
155TEST(WeakPtrTest, UpcastCopyAssignment) {
156 Derived data;
157 WeakPtrFactory<Derived> factory(&data);
158 WeakPtr<Derived> ptr = factory.GetWeakPtr();
159 WeakPtr<Base> ptr2;
160 EXPECT_EQ(nullptr, ptr2.get());
161 ptr2 = ptr;
162 EXPECT_EQ(&data, ptr.get());
163 EXPECT_EQ(&data, ptr2.get());
164}
165
166TEST(WeakPtrTest, UpcastMoveAssignment) {
167 Derived data;
168 WeakPtrFactory<Derived> factory(&data);
169 WeakPtr<Derived> ptr = factory.GetWeakPtr();
170 WeakPtr<Base> ptr2;
171 EXPECT_EQ(nullptr, ptr2.get());
172 ptr2 = std::move(ptr);
173 // The clang linter flags the method called on the moved-from reference, but
174 // this is testing the move implementation, so it is marked NOLINT.
175 EXPECT_EQ(nullptr, ptr.get()); // NOLINT
176 EXPECT_EQ(&data, ptr2.get());
177}
178
179TEST(TaskRunnerAffineWeakPtrTest, ShouldNotCrashIfRunningOnTheSameTaskRunner) {
180 fml::MessageLoop* loop1 = nullptr;
183 std::thread thread1([&loop1, &latch1, &term1]() {
186 latch1.Signal();
187 term1.Wait();
188 });
189
190 fml::MessageLoop* loop2 = nullptr;
193 fml::AutoResetWaitableEvent loop2_task_finish_latch;
194 fml::AutoResetWaitableEvent loop2_task_start_latch;
195 std::thread thread2([&loop2, &latch2, &term2, &loop2_task_finish_latch,
196 &loop2_task_start_latch]() {
198 int data = 0;
199 TaskRunnerAffineWeakPtrFactory<int> factory(&data);
201
202 loop2->GetTaskRunner()->PostTask([&]() {
203 latch2.Signal();
204 loop2_task_start_latch.Wait();
205 TaskRunnerAffineWeakPtr<int> ptr = factory.GetWeakPtr();
206 EXPECT_EQ(*ptr, data);
207 loop2_task_finish_latch.Signal();
208 });
209 loop2->Run();
210 term2.Wait();
211 });
212
213 latch1.Wait();
214 latch2.Wait();
215 fml::TaskQueueId qid1 = loop1->GetTaskRunner()->GetTaskQueueId();
216 fml::TaskQueueId qid2 = loop2->GetTaskRunner()->GetTaskQueueId();
217 const auto raster_thread_merger =
218 fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
219 const size_t kNumFramesMerged = 5;
220
221 raster_thread_merger->MergeWithLease(kNumFramesMerged);
222
223 loop2_task_start_latch.Signal();
224 loop2_task_finish_latch.Wait();
225
226 for (size_t i = 0; i < kNumFramesMerged; i++) {
227 ASSERT_TRUE(raster_thread_merger->IsMerged());
228 raster_thread_merger->DecrementLease();
229 }
230
231 ASSERT_FALSE(raster_thread_merger->IsMerged());
232 loop2->Terminate();
233
234 term1.Signal();
235 term2.Signal();
236 thread1.join();
237 thread2.join();
238}
239
240} // namespace
241} // namespace fml
#define TEST(S, s, D, expected)
static void loop1(skiatest::Reporter *reporter, const char *filename)
static void loop2(skiatest::Reporter *reporter, const char *filename)
static void EnsureInitializedForCurrentThread()
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
static bool b
struct MyStruct a[10]
#define EXPECT_TRUE(handle)
Definition unit_test.h:685