Flutter Engine
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 
17 namespace fml {
18 namespace {
19 
20 TEST(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 
27 TEST(WeakPtrTest, CopyConstruction) {
28  int data = 0;
29  WeakPtrFactory<int> factory(&data);
30  WeakPtr<int> ptr = factory.GetWeakPtr();
31  WeakPtr<int> ptr2(ptr);
32  EXPECT_EQ(&data, ptr.get());
33  EXPECT_EQ(&data, ptr2.get());
34 }
35 
36 TEST(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 
47 TEST(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 
58 TEST(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 
71 TEST(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 
82 TEST(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 
93 TEST(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 
108 TEST(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 
120 struct Base {
121  double member = 0.;
122 };
123 struct Derived : public Base {};
124 
125 TEST(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 
135 TEST(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 
144 TEST(WeakPtrTest, UpcastMoveConstruction) {
145  Derived data;
146  WeakPtrFactory<Derived> factory(&data);
147  WeakPtr<Derived> ptr = factory.GetWeakPtr();
148  WeakPtr<Base> ptr2(std::move(ptr));
149  EXPECT_EQ(nullptr, ptr.get());
150  EXPECT_EQ(&data, ptr2.get());
151 }
152 
153 TEST(WeakPtrTest, UpcastCopyAssignment) {
154  Derived data;
155  WeakPtrFactory<Derived> factory(&data);
156  WeakPtr<Derived> ptr = factory.GetWeakPtr();
157  WeakPtr<Base> ptr2;
158  EXPECT_EQ(nullptr, ptr2.get());
159  ptr2 = ptr;
160  EXPECT_EQ(&data, ptr.get());
161  EXPECT_EQ(&data, ptr2.get());
162 }
163 
164 TEST(WeakPtrTest, UpcastMoveAssignment) {
165  Derived data;
166  WeakPtrFactory<Derived> factory(&data);
167  WeakPtr<Derived> ptr = factory.GetWeakPtr();
168  WeakPtr<Base> ptr2;
169  EXPECT_EQ(nullptr, ptr2.get());
170  ptr2 = std::move(ptr);
171  EXPECT_EQ(nullptr, ptr.get());
172  EXPECT_EQ(&data, ptr2.get());
173 }
174 
175 TEST(TaskRunnerAffineWeakPtrTest, ShouldNotCrashIfRunningOnTheSameTaskRunner) {
176  fml::MessageLoop* loop1 = nullptr;
179  std::thread thread1([&loop1, &latch1, &term1]() {
181  loop1 = &fml::MessageLoop::GetCurrent();
182  latch1.Signal();
183  term1.Wait();
184  });
185 
186  fml::MessageLoop* loop2 = nullptr;
189  fml::AutoResetWaitableEvent loop2_task_finish_latch;
190  fml::AutoResetWaitableEvent loop2_task_start_latch;
191  std::thread thread2([&loop2, &latch2, &term2, &loop2_task_finish_latch,
192  &loop2_task_start_latch]() {
194  int data = 0;
195  TaskRunnerAffineWeakPtrFactory<int> factory(&data);
196  loop2 = &fml::MessageLoop::GetCurrent();
197 
198  loop2->GetTaskRunner()->PostTask([&]() {
199  latch2.Signal();
200  loop2_task_start_latch.Wait();
201  TaskRunnerAffineWeakPtr<int> ptr = factory.GetWeakPtr();
202  EXPECT_EQ(*ptr, data);
203  loop2_task_finish_latch.Signal();
204  });
205  loop2->Run();
206  term2.Wait();
207  });
208 
209  latch1.Wait();
210  latch2.Wait();
211  fml::TaskQueueId qid1 = loop1->GetTaskRunner()->GetTaskQueueId();
212  fml::TaskQueueId qid2 = loop2->GetTaskRunner()->GetTaskQueueId();
213  const auto raster_thread_merger_ =
214  fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
215  const int kNumFramesMerged = 5;
216 
217  raster_thread_merger_->MergeWithLease(kNumFramesMerged);
218 
219  loop2_task_start_latch.Signal();
220  loop2_task_finish_latch.Wait();
221 
222  for (int i = 0; i < kNumFramesMerged; i++) {
223  ASSERT_TRUE(raster_thread_merger_->IsMerged());
224  raster_thread_merger_->DecrementLease();
225  }
226 
227  ASSERT_FALSE(raster_thread_merger_->IsMerged());
228  loop2->Terminate();
229 
230  term1.Signal();
231  term2.Signal();
232  thread1.join();
233  thread2.join();
234 }
235 
236 } // namespace
237 } // namespace fml
virtual TaskQueueId GetTaskQueueId()
Definition: task_runner.cc:38
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
Definition: message_loop.cc:19
static void EnsureInitializedForCurrentThread()
Definition: message_loop.cc:27
Definition: ascii_trie.cc:9
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
Definition: message_loop.cc:56
TEST(MessageTest, CanEncodeTriviallyCopyableTypes)