1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.internal.util;
17
18import junit.framework.TestCase;
19
20import org.junit.Test;
21
22import java.util.ArrayList;
23
24import static org.junit.Assert.assertEquals;
25import static org.junit.Assert.assertFalse;
26import static org.junit.Assert.assertNotNull;
27import static org.junit.Assert.assertTrue;
28
29public class CallbackRegistryTest extends TestCase {
30
31    final Integer callback1 = 1;
32    final Integer callback2 = 2;
33    final Integer callback3 = 3;
34    CallbackRegistry<Integer, CallbackRegistryTest, Integer> registry;
35    int notify1;
36    int notify2;
37    int notify3;
38    int[] deepNotifyCount = new int[300];
39    Integer argValue;
40
41    private void addNotifyCount(Integer callback) {
42        if (callback == callback1) {
43            notify1++;
44        } else if (callback == callback2) {
45            notify2++;
46        } else if (callback == callback3) {
47            notify3++;
48        }
49        deepNotifyCount[callback]++;
50    }
51
52    public void testAddListener() {
53        CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
54                new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
55                    @Override
56                    public void onNotifyCallback(Integer callback, CallbackRegistryTest sender,
57                            int arg, Integer arg2) {
58                    }
59                };
60        registry = new CallbackRegistry<Integer, CallbackRegistryTest, Integer>(notifier);
61        Integer callback = 0;
62
63        assertNotNull(registry.copyListeners());
64        assertEquals(0, registry.copyListeners().size());
65
66        registry.add(callback);
67        ArrayList<Integer> callbacks = registry.copyListeners();
68        assertEquals(1, callbacks.size());
69        assertEquals(callback, callbacks.get(0));
70
71        registry.add(callback);
72        callbacks = registry.copyListeners();
73        assertEquals(1, callbacks.size());
74        assertEquals(callback, callbacks.get(0));
75
76        Integer otherListener = 1;
77        registry.add(otherListener);
78        callbacks = registry.copyListeners();
79        assertEquals(2, callbacks.size());
80        assertEquals(callback, callbacks.get(0));
81        assertEquals(otherListener, callbacks.get(1));
82
83        registry.remove(callback);
84        registry.add(callback);
85        callbacks = registry.copyListeners();
86        assertEquals(2, callbacks.size());
87        assertEquals(callback, callbacks.get(1));
88        assertEquals(otherListener, callbacks.get(0));
89    }
90
91    public void testSimpleNotify() {
92        CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
93                new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
94                    @Override
95                    public void onNotifyCallback(Integer callback, CallbackRegistryTest sender,
96                            int arg1, Integer arg) {
97                        assertEquals(arg1, (int) arg);
98                        addNotifyCount(callback);
99                        argValue = arg;
100                    }
101                };
102        registry = new CallbackRegistry<Integer, CallbackRegistryTest, Integer>(notifier);
103        registry.add(callback2);
104        Integer arg = 1;
105        registry.notifyCallbacks(this, arg, arg);
106        assertEquals(arg, argValue);
107        assertEquals(1, notify2);
108    }
109
110    public void testRemoveWhileNotifying() {
111        CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
112                new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
113                    @Override
114                    public void onNotifyCallback(Integer callback, CallbackRegistryTest sender,
115                            int arg1, Integer arg) {
116                        addNotifyCount(callback);
117                        if (callback == callback1) {
118                            registry.remove(callback1);
119                            registry.remove(callback2);
120                        }
121                    }
122                };
123        registry = new CallbackRegistry<Integer, CallbackRegistryTest, Integer>(notifier);
124        registry.add(callback1);
125        registry.add(callback2);
126        registry.add(callback3);
127        registry.notifyCallbacks(this, 0, null);
128        assertEquals(1, notify1);
129        assertEquals(1, notify2);
130        assertEquals(1, notify3);
131
132        ArrayList<Integer> callbacks = registry.copyListeners();
133        assertEquals(1, callbacks.size());
134        assertEquals(callback3, callbacks.get(0));
135    }
136
137    public void testDeepRemoveWhileNotifying() {
138        CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
139                new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
140                    @Override
141                    public void onNotifyCallback(Integer callback, CallbackRegistryTest sender,
142                            int arg1, Integer arg) {
143                        addNotifyCount(callback);
144                        registry.remove(callback);
145                        registry.notifyCallbacks(CallbackRegistryTest.this, arg1, null);
146                    }
147                };
148        registry = new CallbackRegistry<Integer, CallbackRegistryTest, Integer>(notifier);
149        registry.add(callback1);
150        registry.add(callback2);
151        registry.add(callback3);
152        registry.notifyCallbacks(this, 0, null);
153        assertEquals(1, notify1);
154        assertEquals(2, notify2);
155        assertEquals(3, notify3);
156
157        ArrayList<Integer> callbacks = registry.copyListeners();
158        assertEquals(0, callbacks.size());
159    }
160
161    public void testAddRemovedListener() {
162
163        CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
164                new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
165                    @Override
166                    public void onNotifyCallback(Integer callback, CallbackRegistryTest sender,
167                            int arg1, Integer arg) {
168                        addNotifyCount(callback);
169                        if (callback == callback1) {
170                            registry.remove(callback2);
171                        } else if (callback == callback3) {
172                            registry.add(callback2);
173                        }
174                    }
175                };
176        registry = new CallbackRegistry<Integer, CallbackRegistryTest, Integer>(notifier);
177
178        registry.add(callback1);
179        registry.add(callback2);
180        registry.add(callback3);
181        registry.notifyCallbacks(this, 0, null);
182
183        ArrayList<Integer> callbacks = registry.copyListeners();
184        assertEquals(3, callbacks.size());
185        assertEquals(callback1, callbacks.get(0));
186        assertEquals(callback3, callbacks.get(1));
187        assertEquals(callback2, callbacks.get(2));
188        assertEquals(1, notify1);
189        assertEquals(1, notify2);
190        assertEquals(1, notify3);
191    }
192
193    public void testVeryDeepRemoveWhileNotifying() {
194        final Integer[] callbacks = new Integer[deepNotifyCount.length];
195        for (int i = 0; i < callbacks.length; i++) {
196            callbacks[i] = i;
197        }
198        CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
199                new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
200                    @Override
201                    public void onNotifyCallback(Integer callback, CallbackRegistryTest sender,
202                            int arg1, Integer arg) {
203                        addNotifyCount(callback);
204                        registry.remove(callback);
205                        registry.remove(callbacks[callbacks.length - callback - 1]);
206                        registry.notifyCallbacks(CallbackRegistryTest.this, arg1, null);
207                    }
208                };
209        registry = new CallbackRegistry<Integer, CallbackRegistryTest, Integer>(notifier);
210        for (int i = 0; i < callbacks.length; i++) {
211            registry.add(callbacks[i]);
212        }
213        registry.notifyCallbacks(this, 0, null);
214        for (int i = 0; i < deepNotifyCount.length; i++) {
215            int expectedCount = Math.min(i + 1, deepNotifyCount.length - i);
216            assertEquals(expectedCount, deepNotifyCount[i]);
217        }
218
219        ArrayList<Integer> callbackList = registry.copyListeners();
220        assertEquals(0, callbackList.size());
221    }
222
223    public void testClear() {
224        CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
225                new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
226                    @Override
227                    public void onNotifyCallback(Integer callback, CallbackRegistryTest sender,
228                            int arg1, Integer arg) {
229                        addNotifyCount(callback);
230                    }
231                };
232        registry = new CallbackRegistry<Integer, CallbackRegistryTest, Integer>(notifier);
233        for (int i = 0; i < deepNotifyCount.length; i++) {
234            registry.add(i);
235        }
236        registry.clear();
237
238        ArrayList<Integer> callbackList = registry.copyListeners();
239        assertEquals(0, callbackList.size());
240
241        registry.notifyCallbacks(this, 0, null);
242        for (int i = 0; i < deepNotifyCount.length; i++) {
243            assertEquals(0, deepNotifyCount[i]);
244        }
245    }
246
247    public void testNestedClear() {
248        CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
249                new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
250                    @Override
251                    public void onNotifyCallback(Integer callback, CallbackRegistryTest sender,
252                            int arg1, Integer arg) {
253                        addNotifyCount(callback);
254                        registry.clear();
255                    }
256                };
257        registry = new CallbackRegistry<Integer, CallbackRegistryTest, Integer>(notifier);
258        for (int i = 0; i < deepNotifyCount.length; i++) {
259            registry.add(i);
260        }
261        registry.notifyCallbacks(this, 0, null);
262        for (int i = 0; i < deepNotifyCount.length; i++) {
263            assertEquals(1, deepNotifyCount[i]);
264        }
265
266        ArrayList<Integer> callbackList = registry.copyListeners();
267        assertEquals(0, callbackList.size());
268    }
269
270    public void testIsEmpty() throws Exception {
271        CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
272                new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
273                    @Override
274                    public void onNotifyCallback(Integer callback, CallbackRegistryTest sender,
275                            int arg, Integer arg2) {
276                    }
277                };
278        registry = new CallbackRegistry<Integer, CallbackRegistryTest, Integer>(notifier);
279        Integer callback = 0;
280
281        assertTrue(registry.isEmpty());
282        registry.add(callback);
283        assertFalse(registry.isEmpty());
284    }
285
286    public void testClone() throws Exception {
287        CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
288                new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
289                    @Override
290                    public void onNotifyCallback(Integer callback, CallbackRegistryTest sender,
291                            int arg, Integer arg2) {
292                    }
293                };
294        registry = new CallbackRegistry<Integer, CallbackRegistryTest, Integer>(notifier);
295
296        assertTrue(registry.isEmpty());
297        CallbackRegistry<Integer, CallbackRegistryTest, Integer> registry2 = registry.clone();
298        Integer callback = 0;
299        registry.add(callback);
300        assertFalse(registry.isEmpty());
301        assertTrue(registry2.isEmpty());
302        registry2 = registry.clone();
303        assertFalse(registry2.isEmpty());
304    }
305}
306