QUIC - cleanup changes to sync chromium tree with internal source.
[chromium-blink-merge.git] / base / ios / crb_protocol_observers_unittest.mm
blobb8cf4231e4d3b64d4cbc21bef4fac21ce15d639a
1 // 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.
5 #import "base/ios/crb_protocol_observers.h"
6 #include "base/ios/weak_nsobject.h"
7 #include "base/logging.h"
8 #include "base/mac/scoped_nsautorelease_pool.h"
9 #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"
14 @protocol TestObserver
16 @required
17 - (void)requiredMethod;
18 - (void)reset;
20 @optional
21 - (void)optionalMethod;
22 - (void)mutateByAddingObserver:(id<TestObserver>)observer;
23 - (void)mutateByRemovingObserver:(id<TestObserver>)observer;
24 - (void)nestedMutateByAddingObserver:(id<TestObserver>)observer;
25 - (void)nestedMutateByRemovingObserver:(id<TestObserver>)observer;
27 @end
29 // Implements only the required methods in the TestObserver protocol.
30 @interface TestPartialObserver : NSObject<TestObserver>
31 @property(nonatomic, readonly) BOOL requiredMethodInvoked;
32 @end
34 // Implements all the methods in the TestObserver protocol.
35 @interface TestCompleteObserver : TestPartialObserver<TestObserver>
36 @property(nonatomic, readonly) BOOL optionalMethodInvoked;
37 @end
39 @interface TestMutateObserver : TestCompleteObserver
40 - (instancetype)initWithObserver:(CRBProtocolObservers*)observer
41     NS_DESIGNATED_INITIALIZER;
42 - (instancetype)init NS_UNAVAILABLE;
43 @end
45 namespace {
47 class CRBProtocolObserversTest : public PlatformTest {
48  public:
49   CRBProtocolObserversTest() {}
51  protected:
52   void SetUp() override {
53     PlatformTest::SetUp();
55     observers_.reset([[CRBProtocolObservers observersWithProtocol:
56         @protocol(TestObserver)] retain]);
58     partial_observer_.reset([[TestPartialObserver alloc] init]);
59     EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
61     complete_observer_.reset([[TestCompleteObserver alloc] init]);
62     EXPECT_FALSE([complete_observer_ requiredMethodInvoked]);
63     EXPECT_FALSE([complete_observer_ optionalMethodInvoked]);
65     mutate_observer_.reset(
66         [[TestMutateObserver alloc] initWithObserver:observers_.get()]);
67     EXPECT_FALSE([mutate_observer_ requiredMethodInvoked]);
68   }
70   base::scoped_nsobject<id> observers_;
71   base::scoped_nsobject<TestPartialObserver> partial_observer_;
72   base::scoped_nsobject<TestCompleteObserver> complete_observer_;
73   base::scoped_nsobject<TestMutateObserver> mutate_observer_;
76 // Verifies basic functionality of -[CRBProtocolObservers addObserver:] and
77 // -[CRBProtocolObservers removeObserver:].
78 TEST_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]);
85   [partial_observer_ reset];
86   EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
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]);
95 // Verifies that CRBProtocolObservers correctly forwards the invocation of a
96 // required method in the protocol.
97 TEST_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]);
105 // Verifies that CRBProtocolObservers correctly forwards the invocation of an
106 // optional method in the protocol.
107 TEST_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]);
116 // Verifies that CRBProtocolObservers only holds a weak reference to an
117 // observer.
118 TEST_F(CRBProtocolObserversTest, WeakReference) {
119   base::WeakNSObject<TestPartialObserver> weak_observer(
120       partial_observer_);
121   EXPECT_TRUE(weak_observer);
123   [observers_ addObserver:partial_observer_];
125   {
126     // Need an autorelease pool here, because
127     // -[CRBProtocolObservers forwardInvocation:] creates a temporary
128     // autoreleased array that holds all the observers.
129     base::mac::ScopedNSAutoreleasePool pool;
130     [observers_ requiredMethod];
131     EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
132   }
134   partial_observer_.reset();
135   EXPECT_FALSE(weak_observer.get());
138 // Verifies that an observer can safely remove itself as observer while being
139 // notified.
140 TEST_F(CRBProtocolObserversTest, SelfMutateObservers) {
141   [observers_ addObserver:mutate_observer_];
142   EXPECT_FALSE([observers_ empty]);
144   [observers_ requiredMethod];
145   EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
147   [mutate_observer_ reset];
149   [observers_ nestedMutateByRemovingObserver:mutate_observer_];
150   EXPECT_FALSE([mutate_observer_ requiredMethodInvoked]);
152   [observers_ addObserver:partial_observer_];
154   [observers_ requiredMethod];
155   EXPECT_FALSE([mutate_observer_ requiredMethodInvoked]);
156   EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
158   [observers_ removeObserver:partial_observer_];
159   EXPECT_TRUE([observers_ empty]);
162 // Verifies that - [CRBProtocolObservers addObserver:] and
163 // - [CRBProtocolObservers removeObserver:] can be called while methods are
164 // being forwarded.
165 TEST_F(CRBProtocolObserversTest, MutateObservers) {
166   // Indirectly add an observer while forwarding an observer method.
167   [observers_ addObserver:mutate_observer_];
169   [observers_ mutateByAddingObserver:partial_observer_];
170   EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
172   // Check that methods are correctly forwared to the indirectly added observer.
173   [mutate_observer_ reset];
174   [observers_ requiredMethod];
175   EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
176   EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
178   [mutate_observer_ reset];
179   [partial_observer_ reset];
181   // Indirectly remove an observer while forwarding an observer method.
182   [observers_ mutateByRemovingObserver:partial_observer_];
184   // Check that method is not forwared to the indirectly removed observer.
185   [observers_ requiredMethod];
186   EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
187   EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
190 // Verifies that - [CRBProtocolObservers addObserver:] and
191 // - [CRBProtocolObservers removeObserver:] can be called while methods are
192 // being forwarded with a nested invocation depth > 0.
193 TEST_F(CRBProtocolObserversTest, NestedMutateObservers) {
194   // Indirectly add an observer while forwarding an observer method.
195   [observers_ addObserver:mutate_observer_];
197   [observers_ nestedMutateByAddingObserver:partial_observer_];
198   EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
200   // Check that methods are correctly forwared to the indirectly added observer.
201   [mutate_observer_ reset];
202   [observers_ requiredMethod];
203   EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
204   EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
206   [mutate_observer_ reset];
207   [partial_observer_ reset];
209   // Indirectly remove an observer while forwarding an observer method.
210   [observers_ nestedMutateByRemovingObserver:partial_observer_];
212   // Check that method is not forwared to the indirectly removed observer.
213   [observers_ requiredMethod];
214   EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
215   EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
218 }  // namespace
220 @implementation TestPartialObserver {
221   BOOL _requiredMethodInvoked;
224 - (BOOL)requiredMethodInvoked {
225   return _requiredMethodInvoked;
228 - (void)requiredMethod {
229   _requiredMethodInvoked = YES;
232 - (void)reset {
233   _requiredMethodInvoked = NO;
236 @end
238 @implementation TestCompleteObserver {
239   BOOL _optionalMethodInvoked;
242 - (BOOL)optionalMethodInvoked {
243   return _optionalMethodInvoked;
246 - (void)optionalMethod {
247   _optionalMethodInvoked = YES;
250 - (void)reset {
251   [super reset];
252   _optionalMethodInvoked = NO;
255 @end
257 @implementation TestMutateObserver {
258   __weak id _observers;
261 - (instancetype)initWithObserver:(CRBProtocolObservers*)observers {
262   self = [super init];
263   if (self) {
264     _observers = observers;
265   }
266   return self;
269 - (instancetype)init {
270   NOTREACHED();
271   return nil;
274 - (void)mutateByAddingObserver:(id<TestObserver>)observer {
275   [_observers addObserver:observer];
278 - (void)mutateByRemovingObserver:(id<TestObserver>)observer {
279   [_observers removeObserver:observer];
282 - (void)nestedMutateByAddingObserver:(id<TestObserver>)observer {
283   [_observers mutateByAddingObserver:observer];
286 - (void)nestedMutateByRemovingObserver:(id<TestObserver>)observer {
287   [_observers mutateByRemovingObserver:observer];
290 @end