blob: 3538c9e510f92e48c52893ad352595f6963783df [file] [log] [blame]
stuartmorgan4733f552015-02-14 22:19:301// Copyright 2014 The Chromium 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#import "base/ios/crb_protocol_observers.h"
Sylvain Defresneb20b7d52019-11-22 13:23:006
stuartmorgan4733f552015-02-14 22:19:307#include "base/ios/weak_nsobject.h"
justincohen5a8629932015-06-10 17:38:168#include "base/logging.h"
stuartmorgan4733f552015-02-14 22:19:309#include "base/mac/scoped_nsobject.h"
10#include "testing/gtest/include/gtest/gtest.h"
11#include "testing/gtest_mac.h"
12#include "testing/platform_test.h"
13
14@protocol TestObserver
15
16@required
17- (void)requiredMethod;
18- (void)reset;
19
20@optional
21- (void)optionalMethod;
jbbegue12d50e72015-06-05 08:12:4322- (void)mutateByAddingObserver:(id<TestObserver>)observer;
23- (void)mutateByRemovingObserver:(id<TestObserver>)observer;
24- (void)nestedMutateByAddingObserver:(id<TestObserver>)observer;
25- (void)nestedMutateByRemovingObserver:(id<TestObserver>)observer;
stuartmorgan4733f552015-02-14 22:19:3026
27@end
28
29// Implements only the required methods in the TestObserver protocol.
30@interface TestPartialObserver : NSObject<TestObserver>
31@property(nonatomic, readonly) BOOL requiredMethodInvoked;
32@end
33
34// Implements all the methods in the TestObserver protocol.
35@interface TestCompleteObserver : TestPartialObserver<TestObserver>
36@property(nonatomic, readonly) BOOL optionalMethodInvoked;
37@end
38
jbbegue12d50e72015-06-05 08:12:4339@interface TestMutateObserver : TestCompleteObserver
jbbegue12d50e72015-06-05 08:12:4340- (instancetype)initWithObserver:(CRBProtocolObservers*)observer
41 NS_DESIGNATED_INITIALIZER;
justincohen5a8629932015-06-10 17:38:1642- (instancetype)init NS_UNAVAILABLE;
jbbegue12d50e72015-06-05 08:12:4343@end
44
stuartmorgan4733f552015-02-14 22:19:3045namespace {
46
47class CRBProtocolObserversTest : public PlatformTest {
48 public:
49 CRBProtocolObserversTest() {}
50
51 protected:
52 void SetUp() override {
53 PlatformTest::SetUp();
54
55 observers_.reset([[CRBProtocolObservers observersWithProtocol:
56 @protocol(TestObserver)] retain]);
57
58 partial_observer_.reset([[TestPartialObserver alloc] init]);
59 EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
60
61 complete_observer_.reset([[TestCompleteObserver alloc] init]);
62 EXPECT_FALSE([complete_observer_ requiredMethodInvoked]);
63 EXPECT_FALSE([complete_observer_ optionalMethodInvoked]);
jbbegue12d50e72015-06-05 08:12:4364
65 mutate_observer_.reset(
66 [[TestMutateObserver alloc] initWithObserver:observers_.get()]);
67 EXPECT_FALSE([mutate_observer_ requiredMethodInvoked]);
stuartmorgan4733f552015-02-14 22:19:3068 }
69
70 base::scoped_nsobject<id> observers_;
71 base::scoped_nsobject<TestPartialObserver> partial_observer_;
72 base::scoped_nsobject<TestCompleteObserver> complete_observer_;
jbbegue12d50e72015-06-05 08:12:4373 base::scoped_nsobject<TestMutateObserver> mutate_observer_;
stuartmorgan4733f552015-02-14 22:19:3074};
75
76// Verifies basic functionality of -[CRBProtocolObservers addObserver:] and
77// -[CRBProtocolObservers removeObserver:].
78TEST_F(CRBProtocolObserversTest, AddRemoveObserver) {
79 // Add an observer and verify that the CRBProtocolObservers instance forwards
80 // an invocation to it.
81 [observers_ addObserver:partial_observer_];
82 [observers_ requiredMethod];
83 EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
84
85 [partial_observer_ reset];
86 EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
87
88 // Remove the observer and verify that the CRBProtocolObservers instance no
89 // longer forwards an invocation to it.
90 [observers_ removeObserver:partial_observer_];
91 [observers_ requiredMethod];
92 EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
93}
94
95// Verifies that CRBProtocolObservers correctly forwards the invocation of a
96// required method in the protocol.
97TEST_F(CRBProtocolObserversTest, RequiredMethods) {
98 [observers_ addObserver:partial_observer_];
99 [observers_ addObserver:complete_observer_];
100 [observers_ requiredMethod];
101 EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
102 EXPECT_TRUE([complete_observer_ requiredMethodInvoked]);
103}
104
105// Verifies that CRBProtocolObservers correctly forwards the invocation of an
106// optional method in the protocol.
107TEST_F(CRBProtocolObserversTest, OptionalMethods) {
108 [observers_ addObserver:partial_observer_];
109 [observers_ addObserver:complete_observer_];
110 [observers_ optionalMethod];
111 EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
112 EXPECT_FALSE([complete_observer_ requiredMethodInvoked]);
113 EXPECT_TRUE([complete_observer_ optionalMethodInvoked]);
114}
115
116// Verifies that CRBProtocolObservers only holds a weak reference to an
117// observer.
118TEST_F(CRBProtocolObserversTest, WeakReference) {
119 base::WeakNSObject<TestPartialObserver> weak_observer(
120 partial_observer_);
121 EXPECT_TRUE(weak_observer);
122
123 [observers_ addObserver:partial_observer_];
124
Avi Drissman91160c632019-09-06 19:24:58125 // Need an autorelease pool here, because
126 // -[CRBProtocolObservers forwardInvocation:] creates a temporary
127 // autoreleased array that holds all the observers.
128 @autoreleasepool {
stuartmorgan4733f552015-02-14 22:19:30129 [observers_ requiredMethod];
130 EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
131 }
132
133 partial_observer_.reset();
134 EXPECT_FALSE(weak_observer.get());
135}
136
jbbegue12d50e72015-06-05 08:12:43137// Verifies that an observer can safely remove itself as observer while being
138// notified.
139TEST_F(CRBProtocolObserversTest, SelfMutateObservers) {
140 [observers_ addObserver:mutate_observer_];
141 EXPECT_FALSE([observers_ empty]);
142
143 [observers_ requiredMethod];
144 EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
145
146 [mutate_observer_ reset];
147
148 [observers_ nestedMutateByRemovingObserver:mutate_observer_];
149 EXPECT_FALSE([mutate_observer_ requiredMethodInvoked]);
150
151 [observers_ addObserver:partial_observer_];
152
153 [observers_ requiredMethod];
154 EXPECT_FALSE([mutate_observer_ requiredMethodInvoked]);
155 EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
156
157 [observers_ removeObserver:partial_observer_];
158 EXPECT_TRUE([observers_ empty]);
159}
160
161// Verifies that - [CRBProtocolObservers addObserver:] and
162// - [CRBProtocolObservers removeObserver:] can be called while methods are
163// being forwarded.
164TEST_F(CRBProtocolObserversTest, MutateObservers) {
165 // Indirectly add an observer while forwarding an observer method.
166 [observers_ addObserver:mutate_observer_];
167
168 [observers_ mutateByAddingObserver:partial_observer_];
169 EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
170
171 // Check that methods are correctly forwared to the indirectly added observer.
172 [mutate_observer_ reset];
173 [observers_ requiredMethod];
174 EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
175 EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
176
177 [mutate_observer_ reset];
178 [partial_observer_ reset];
179
180 // Indirectly remove an observer while forwarding an observer method.
181 [observers_ mutateByRemovingObserver:partial_observer_];
182
183 // Check that method is not forwared to the indirectly removed observer.
184 [observers_ requiredMethod];
185 EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
186 EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
187}
188
189// Verifies that - [CRBProtocolObservers addObserver:] and
190// - [CRBProtocolObservers removeObserver:] can be called while methods are
191// being forwarded with a nested invocation depth > 0.
192TEST_F(CRBProtocolObserversTest, NestedMutateObservers) {
193 // Indirectly add an observer while forwarding an observer method.
194 [observers_ addObserver:mutate_observer_];
195
196 [observers_ nestedMutateByAddingObserver:partial_observer_];
197 EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
198
199 // Check that methods are correctly forwared to the indirectly added observer.
200 [mutate_observer_ reset];
201 [observers_ requiredMethod];
202 EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
203 EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
204
205 [mutate_observer_ reset];
206 [partial_observer_ reset];
207
208 // Indirectly remove an observer while forwarding an observer method.
209 [observers_ nestedMutateByRemovingObserver:partial_observer_];
210
211 // Check that method is not forwared to the indirectly removed observer.
212 [observers_ requiredMethod];
213 EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
214 EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
215}
216
stuartmorgan4733f552015-02-14 22:19:30217} // namespace
218
219@implementation TestPartialObserver {
220 BOOL _requiredMethodInvoked;
221}
222
223- (BOOL)requiredMethodInvoked {
224 return _requiredMethodInvoked;
225}
226
227- (void)requiredMethod {
228 _requiredMethodInvoked = YES;
229}
230
231- (void)reset {
232 _requiredMethodInvoked = NO;
233}
234
235@end
236
237@implementation TestCompleteObserver {
238 BOOL _optionalMethodInvoked;
239}
240
241- (BOOL)optionalMethodInvoked {
242 return _optionalMethodInvoked;
243}
244
245- (void)optionalMethod {
246 _optionalMethodInvoked = YES;
247}
248
249- (void)reset {
250 [super reset];
251 _optionalMethodInvoked = NO;
252}
253
254@end
jbbegue12d50e72015-06-05 08:12:43255
256@implementation TestMutateObserver {
Nico Weberd38012862015-11-04 22:47:16257 id _observers; // weak
jbbegue12d50e72015-06-05 08:12:43258}
259
260- (instancetype)initWithObserver:(CRBProtocolObservers*)observers {
261 self = [super init];
262 if (self) {
263 _observers = observers;
264 }
265 return self;
266}
267
justincohen5a8629932015-06-10 17:38:16268- (instancetype)init {
269 NOTREACHED();
270 return nil;
271}
272
jbbegue12d50e72015-06-05 08:12:43273- (void)mutateByAddingObserver:(id<TestObserver>)observer {
274 [_observers addObserver:observer];
275}
276
277- (void)mutateByRemovingObserver:(id<TestObserver>)observer {
278 [_observers removeObserver:observer];
279}
280
281- (void)nestedMutateByAddingObserver:(id<TestObserver>)observer {
282 [_observers mutateByAddingObserver:observer];
283}
284
285- (void)nestedMutateByRemovingObserver:(id<TestObserver>)observer {
286 [_observers mutateByRemovingObserver:observer];
287}
288
289@end