LifecycleRegistryTest.java revision bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8
1/*
2 * Copyright (C) 2017 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 */
16
17package androidx.lifecycle;
18
19import static androidx.lifecycle.Lifecycle.Event.ON_CREATE;
20import static androidx.lifecycle.Lifecycle.Event.ON_DESTROY;
21import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
22import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
23import static androidx.lifecycle.Lifecycle.Event.ON_START;
24import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
25
26import static org.hamcrest.CoreMatchers.is;
27import static org.hamcrest.MatcherAssert.assertThat;
28import static org.mockito.Mockito.inOrder;
29import static org.mockito.Mockito.mock;
30import static org.mockito.Mockito.never;
31import static org.mockito.Mockito.reset;
32import static org.mockito.Mockito.spy;
33import static org.mockito.Mockito.times;
34import static org.mockito.Mockito.verify;
35import static org.mockito.Mockito.when;
36
37import org.junit.Before;
38import org.junit.Test;
39import org.junit.runner.RunWith;
40import org.junit.runners.JUnit4;
41import org.mockito.InOrder;
42
43@RunWith(JUnit4.class)
44public class LifecycleRegistryTest {
45    private LifecycleOwner mLifecycleOwner;
46    private Lifecycle mLifecycle;
47    private LifecycleRegistry mRegistry;
48
49    @Before
50    public void init() {
51        mLifecycleOwner = mock(LifecycleOwner.class);
52        mLifecycle = mock(Lifecycle.class);
53        when(mLifecycleOwner.getLifecycle()).thenReturn(mLifecycle);
54        mRegistry = new LifecycleRegistry(mLifecycleOwner);
55    }
56
57    @Test
58    public void addRemove() {
59        LifecycleObserver observer = mock(LifecycleObserver.class);
60        mRegistry.addObserver(observer);
61        assertThat(mRegistry.getObserverCount(), is(1));
62        mRegistry.removeObserver(observer);
63        assertThat(mRegistry.getObserverCount(), is(0));
64    }
65
66    @Test
67    public void addGenericAndObserve() {
68        GenericLifecycleObserver generic = mock(GenericLifecycleObserver.class);
69        mRegistry.addObserver(generic);
70        dispatchEvent(ON_CREATE);
71        verify(generic).onStateChanged(mLifecycleOwner, ON_CREATE);
72        reset(generic);
73        dispatchEvent(ON_CREATE);
74        verify(generic, never()).onStateChanged(mLifecycleOwner, ON_CREATE);
75    }
76
77    @Test
78    public void addRegularClass() {
79        TestObserver testObserver = mock(TestObserver.class);
80        mRegistry.addObserver(testObserver);
81        dispatchEvent(ON_START);
82        verify(testObserver, never()).onStop();
83        dispatchEvent(ON_STOP);
84        verify(testObserver).onStop();
85    }
86
87    @Test
88    public void add2RemoveOne() {
89        TestObserver observer1 = mock(TestObserver.class);
90        TestObserver observer2 = mock(TestObserver.class);
91        TestObserver observer3 = mock(TestObserver.class);
92        mRegistry.addObserver(observer1);
93        mRegistry.addObserver(observer2);
94        mRegistry.addObserver(observer3);
95
96        dispatchEvent(ON_CREATE);
97
98        verify(observer1).onCreate();
99        verify(observer2).onCreate();
100        verify(observer3).onCreate();
101        reset(observer1, observer2, observer3);
102
103        mRegistry.removeObserver(observer2);
104        dispatchEvent(ON_START);
105
106        verify(observer1).onStart();
107        verify(observer2, never()).onStart();
108        verify(observer3).onStart();
109    }
110
111    @Test
112    public void removeWhileTraversing() {
113        final TestObserver observer2 = mock(TestObserver.class);
114        TestObserver observer1 = spy(new TestObserver() {
115            @Override
116            public void onCreate() {
117                mRegistry.removeObserver(observer2);
118            }
119        });
120        mRegistry.addObserver(observer1);
121        mRegistry.addObserver(observer2);
122        dispatchEvent(ON_CREATE);
123        verify(observer2, never()).onCreate();
124        verify(observer1).onCreate();
125    }
126
127    @Test
128    public void constructionOrder() {
129        fullyInitializeRegistry();
130        final TestObserver observer = mock(TestObserver.class);
131        mRegistry.addObserver(observer);
132        InOrder inOrder = inOrder(observer);
133        inOrder.verify(observer).onCreate();
134        inOrder.verify(observer).onStart();
135        inOrder.verify(observer).onResume();
136    }
137
138    @Test
139    public void constructionDestruction1() {
140        fullyInitializeRegistry();
141        final TestObserver observer = spy(new TestObserver() {
142            @Override
143            void onStart() {
144                dispatchEvent(ON_PAUSE);
145            }
146        });
147        mRegistry.addObserver(observer);
148        InOrder constructionOrder = inOrder(observer);
149        constructionOrder.verify(observer).onCreate();
150        constructionOrder.verify(observer).onStart();
151        constructionOrder.verify(observer, never()).onResume();
152    }
153
154    @Test
155    public void constructionDestruction2() {
156        fullyInitializeRegistry();
157        final TestObserver observer = spy(new TestObserver() {
158            @Override
159            void onStart() {
160                dispatchEvent(ON_PAUSE);
161                dispatchEvent(ON_STOP);
162                dispatchEvent(ON_DESTROY);
163            }
164        });
165        mRegistry.addObserver(observer);
166        InOrder orderVerifier = inOrder(observer);
167        orderVerifier.verify(observer).onCreate();
168        orderVerifier.verify(observer).onStart();
169        orderVerifier.verify(observer).onStop();
170        orderVerifier.verify(observer).onDestroy();
171        orderVerifier.verify(observer, never()).onResume();
172    }
173
174    @Test
175    public void twoObserversChangingState() {
176        final TestObserver observer1 = spy(new TestObserver() {
177            @Override
178            void onCreate() {
179                dispatchEvent(ON_START);
180            }
181        });
182        final TestObserver observer2 = mock(TestObserver.class);
183        mRegistry.addObserver(observer1);
184        mRegistry.addObserver(observer2);
185        dispatchEvent(ON_CREATE);
186        verify(observer1, times(1)).onCreate();
187        verify(observer2, times(1)).onCreate();
188        verify(observer1, times(1)).onStart();
189        verify(observer2, times(1)).onStart();
190    }
191
192    @Test
193    public void addDuringTraversing() {
194        final TestObserver observer3 = mock(TestObserver.class);
195        final TestObserver observer1 = spy(new TestObserver() {
196            @Override
197            public void onStart() {
198                mRegistry.addObserver(observer3);
199            }
200        });
201        final TestObserver observer2 = mock(TestObserver.class);
202
203        mRegistry.addObserver(observer1);
204        mRegistry.addObserver(observer2);
205
206        dispatchEvent(ON_CREATE);
207        dispatchEvent(ON_START);
208
209        InOrder inOrder = inOrder(observer1, observer2, observer3);
210        inOrder.verify(observer1).onCreate();
211        inOrder.verify(observer2).onCreate();
212        inOrder.verify(observer1).onStart();
213        inOrder.verify(observer3).onCreate();
214        inOrder.verify(observer2).onStart();
215        inOrder.verify(observer3).onStart();
216    }
217
218    @Test
219    public void addDuringAddition() {
220        final TestObserver observer3 = mock(TestObserver.class);
221        final TestObserver observer2 = spy(new TestObserver() {
222            @Override
223            public void onCreate() {
224                mRegistry.addObserver(observer3);
225            }
226        });
227
228        final TestObserver observer1 = spy(new TestObserver() {
229            @Override
230            public void onResume() {
231                mRegistry.addObserver(observer2);
232            }
233        });
234
235        mRegistry.addObserver(observer1);
236
237        dispatchEvent(ON_CREATE);
238        dispatchEvent(ON_START);
239        dispatchEvent(ON_RESUME);
240
241        InOrder inOrder = inOrder(observer1, observer2, observer3);
242        inOrder.verify(observer1).onCreate();
243        inOrder.verify(observer1).onStart();
244        inOrder.verify(observer1).onResume();
245        inOrder.verify(observer2).onCreate();
246        inOrder.verify(observer2).onStart();
247        inOrder.verify(observer2).onResume();
248        inOrder.verify(observer3).onCreate();
249        inOrder.verify(observer3).onStart();
250        inOrder.verify(observer3).onResume();
251    }
252
253    @Test
254    public void subscribeToDead() {
255        dispatchEvent(ON_CREATE);
256        final TestObserver observer1 = mock(TestObserver.class);
257        mRegistry.addObserver(observer1);
258        verify(observer1).onCreate();
259        dispatchEvent(ON_DESTROY);
260        verify(observer1).onDestroy();
261        final TestObserver observer2 = mock(TestObserver.class);
262        mRegistry.addObserver(observer2);
263        verify(observer2, never()).onCreate();
264        reset(observer1);
265        dispatchEvent(ON_CREATE);
266        verify(observer1).onCreate();
267        verify(observer2).onCreate();
268    }
269
270    @Test
271    public void downEvents() {
272        fullyInitializeRegistry();
273        final TestObserver observer1 = mock(TestObserver.class);
274        final TestObserver observer2 = mock(TestObserver.class);
275        mRegistry.addObserver(observer1);
276        mRegistry.addObserver(observer2);
277        InOrder orderVerifier = inOrder(observer1, observer2);
278        dispatchEvent(ON_PAUSE);
279        orderVerifier.verify(observer2).onPause();
280        orderVerifier.verify(observer1).onPause();
281        dispatchEvent(ON_STOP);
282        orderVerifier.verify(observer2).onStop();
283        orderVerifier.verify(observer1).onStop();
284        dispatchEvent(ON_DESTROY);
285        orderVerifier.verify(observer2).onDestroy();
286        orderVerifier.verify(observer1).onDestroy();
287    }
288
289    @Test
290    public void downEventsAddition() {
291        dispatchEvent(ON_CREATE);
292        dispatchEvent(ON_START);
293        final TestObserver observer1 = mock(TestObserver.class);
294        final TestObserver observer3 = mock(TestObserver.class);
295        final TestObserver observer2 = spy(new TestObserver() {
296            @Override
297            void onStop() {
298                mRegistry.addObserver(observer3);
299            }
300        });
301        mRegistry.addObserver(observer1);
302        mRegistry.addObserver(observer2);
303        InOrder orderVerifier = inOrder(observer1, observer2, observer3);
304        dispatchEvent(ON_STOP);
305        orderVerifier.verify(observer2).onStop();
306        orderVerifier.verify(observer3).onCreate();
307        orderVerifier.verify(observer1).onStop();
308        dispatchEvent(ON_DESTROY);
309        orderVerifier.verify(observer3).onDestroy();
310        orderVerifier.verify(observer2).onDestroy();
311        orderVerifier.verify(observer1).onDestroy();
312    }
313
314    @Test
315    public void downEventsRemoveAll() {
316        fullyInitializeRegistry();
317        final TestObserver observer1 = mock(TestObserver.class);
318        final TestObserver observer3 = mock(TestObserver.class);
319        final TestObserver observer2 = spy(new TestObserver() {
320            @Override
321            void onStop() {
322                mRegistry.removeObserver(observer3);
323                mRegistry.removeObserver(this);
324                mRegistry.removeObserver(observer1);
325                assertThat(mRegistry.getObserverCount(), is(0));
326            }
327        });
328        mRegistry.addObserver(observer1);
329        mRegistry.addObserver(observer2);
330        mRegistry.addObserver(observer3);
331        InOrder orderVerifier = inOrder(observer1, observer2, observer3);
332        dispatchEvent(ON_PAUSE);
333        orderVerifier.verify(observer3).onPause();
334        orderVerifier.verify(observer2).onPause();
335        orderVerifier.verify(observer1).onPause();
336        dispatchEvent(ON_STOP);
337        orderVerifier.verify(observer3).onStop();
338        orderVerifier.verify(observer2).onStop();
339        orderVerifier.verify(observer1, never()).onStop();
340        dispatchEvent(ON_PAUSE);
341        orderVerifier.verify(observer3, never()).onPause();
342        orderVerifier.verify(observer2, never()).onPause();
343        orderVerifier.verify(observer1, never()).onPause();
344    }
345
346    @Test
347    public void deadParentInAddition() {
348        fullyInitializeRegistry();
349        final TestObserver observer2 = mock(TestObserver.class);
350        final TestObserver observer3 = mock(TestObserver.class);
351
352        TestObserver observer1 = spy(new TestObserver() {
353            @Override
354            void onStart() {
355                mRegistry.removeObserver(this);
356                assertThat(mRegistry.getObserverCount(), is(0));
357                mRegistry.addObserver(observer2);
358                mRegistry.addObserver(observer3);
359            }
360        });
361
362        mRegistry.addObserver(observer1);
363
364        InOrder inOrder = inOrder(observer1, observer2, observer3);
365        inOrder.verify(observer1).onCreate();
366        inOrder.verify(observer1).onStart();
367        inOrder.verify(observer2).onCreate();
368        inOrder.verify(observer3).onCreate();
369        inOrder.verify(observer2).onStart();
370        inOrder.verify(observer2).onResume();
371        inOrder.verify(observer3).onStart();
372        inOrder.verify(observer3).onResume();
373    }
374
375    @Test
376    public void deadParentWhileTraversing() {
377        final TestObserver observer2 = mock(TestObserver.class);
378        final TestObserver observer3 = mock(TestObserver.class);
379        TestObserver observer1 = spy(new TestObserver() {
380            @Override
381            void onStart() {
382                mRegistry.removeObserver(this);
383                assertThat(mRegistry.getObserverCount(), is(0));
384                mRegistry.addObserver(observer2);
385                mRegistry.addObserver(observer3);
386            }
387        });
388        InOrder inOrder = inOrder(observer1, observer2, observer3);
389        mRegistry.addObserver(observer1);
390        dispatchEvent(ON_CREATE);
391        dispatchEvent(ON_START);
392        inOrder.verify(observer1).onCreate();
393        inOrder.verify(observer1).onStart();
394        inOrder.verify(observer2).onCreate();
395        inOrder.verify(observer3).onCreate();
396        inOrder.verify(observer2).onStart();
397        inOrder.verify(observer3).onStart();
398    }
399
400    @Test
401    public void removeCascade() {
402        final TestObserver observer3 = mock(TestObserver.class);
403        final TestObserver observer4 = mock(TestObserver.class);
404
405        final TestObserver observer2 = spy(new TestObserver() {
406            @Override
407            void onStart() {
408                mRegistry.removeObserver(this);
409            }
410        });
411
412        TestObserver observer1 = spy(new TestObserver() {
413            @Override
414            void onResume() {
415                mRegistry.removeObserver(this);
416                mRegistry.addObserver(observer2);
417                mRegistry.addObserver(observer3);
418                mRegistry.addObserver(observer4);
419            }
420        });
421        fullyInitializeRegistry();
422        mRegistry.addObserver(observer1);
423        InOrder inOrder = inOrder(observer1, observer2, observer3, observer4);
424        inOrder.verify(observer1).onCreate();
425        inOrder.verify(observer1).onStart();
426        inOrder.verify(observer1).onResume();
427        inOrder.verify(observer2).onCreate();
428        inOrder.verify(observer2).onStart();
429        inOrder.verify(observer3).onCreate();
430        inOrder.verify(observer3).onStart();
431        inOrder.verify(observer4).onCreate();
432        inOrder.verify(observer4).onStart();
433        inOrder.verify(observer3).onResume();
434        inOrder.verify(observer4).onResume();
435    }
436
437    @Test
438    public void changeStateDuringDescending() {
439        final TestObserver observer2 = mock(TestObserver.class);
440        final TestObserver observer1 = spy(new TestObserver() {
441            @Override
442            void onPause() {
443                // but tonight I bounce back
444                mRegistry.handleLifecycleEvent(ON_RESUME);
445                mRegistry.addObserver(observer2);
446            }
447        });
448        fullyInitializeRegistry();
449        mRegistry.addObserver(observer1);
450        mRegistry.handleLifecycleEvent(ON_PAUSE);
451        InOrder inOrder = inOrder(observer1, observer2);
452        inOrder.verify(observer1).onPause();
453        inOrder.verify(observer2).onCreate();
454        inOrder.verify(observer2).onStart();
455        inOrder.verify(observer1).onResume();
456        inOrder.verify(observer2).onResume();
457    }
458
459    @Test
460    public void siblingLimitationCheck() {
461        fullyInitializeRegistry();
462        final TestObserver observer2 = mock(TestObserver.class);
463        final TestObserver observer3 = mock(TestObserver.class);
464        final TestObserver observer1 = spy(new TestObserver() {
465            @Override
466            void onStart() {
467                mRegistry.addObserver(observer2);
468            }
469
470            @Override
471            void onResume() {
472                mRegistry.addObserver(observer3);
473            }
474        });
475        mRegistry.addObserver(observer1);
476        InOrder inOrder = inOrder(observer1, observer2, observer3);
477        inOrder.verify(observer1).onCreate();
478        inOrder.verify(observer1).onStart();
479        inOrder.verify(observer2).onCreate();
480        inOrder.verify(observer1).onResume();
481        inOrder.verify(observer3).onCreate();
482        inOrder.verify(observer2).onStart();
483        inOrder.verify(observer2).onResume();
484        inOrder.verify(observer3).onStart();
485        inOrder.verify(observer3).onResume();
486    }
487
488    @Test
489    public void siblingRemovalLimitationCheck1() {
490        fullyInitializeRegistry();
491        final TestObserver observer2 = mock(TestObserver.class);
492        final TestObserver observer3 = mock(TestObserver.class);
493        final TestObserver observer4 = mock(TestObserver.class);
494        final TestObserver observer1 = spy(new TestObserver() {
495            @Override
496            void onStart() {
497                mRegistry.addObserver(observer2);
498            }
499
500            @Override
501            void onResume() {
502                mRegistry.removeObserver(observer2);
503                mRegistry.addObserver(observer3);
504                mRegistry.addObserver(observer4);
505            }
506        });
507        mRegistry.addObserver(observer1);
508        InOrder inOrder = inOrder(observer1, observer2, observer3, observer4);
509        inOrder.verify(observer1).onCreate();
510        inOrder.verify(observer1).onStart();
511        inOrder.verify(observer2).onCreate();
512        inOrder.verify(observer1).onResume();
513        inOrder.verify(observer3).onCreate();
514        inOrder.verify(observer3).onStart();
515        inOrder.verify(observer4).onCreate();
516        inOrder.verify(observer4).onStart();
517        inOrder.verify(observer3).onResume();
518        inOrder.verify(observer4).onResume();
519    }
520
521    @Test
522    public void siblingRemovalLimitationCheck2() {
523        fullyInitializeRegistry();
524        final TestObserver observer2 = mock(TestObserver.class);
525        final TestObserver observer3 = spy(new TestObserver() {
526            @Override
527            void onCreate() {
528                mRegistry.removeObserver(observer2);
529            }
530        });
531        final TestObserver observer4 = mock(TestObserver.class);
532        final TestObserver observer1 = spy(new TestObserver() {
533            @Override
534            void onStart() {
535                mRegistry.addObserver(observer2);
536            }
537
538            @Override
539            void onResume() {
540                mRegistry.addObserver(observer3);
541                mRegistry.addObserver(observer4);
542            }
543        });
544
545        mRegistry.addObserver(observer1);
546        InOrder inOrder = inOrder(observer1, observer2, observer3, observer4);
547        inOrder.verify(observer1).onCreate();
548        inOrder.verify(observer1).onStart();
549        inOrder.verify(observer2).onCreate();
550        inOrder.verify(observer1).onResume();
551        inOrder.verify(observer3).onCreate();
552        inOrder.verify(observer3).onStart();
553        inOrder.verify(observer4).onCreate();
554        inOrder.verify(observer4).onStart();
555        inOrder.verify(observer3).onResume();
556        inOrder.verify(observer4).onResume();
557    }
558
559    @Test
560    public void sameObserverReAddition() {
561        TestObserver observer = mock(TestObserver.class);
562        mRegistry.addObserver(observer);
563        mRegistry.removeObserver(observer);
564        mRegistry.addObserver(observer);
565        dispatchEvent(ON_CREATE);
566        verify(observer).onCreate();
567    }
568
569    private static void forceGc() {
570        Runtime.getRuntime().gc();
571        Runtime.getRuntime().runFinalization();
572        Runtime.getRuntime().gc();
573        Runtime.getRuntime().runFinalization();
574    }
575
576    @Test
577    public void goneLifecycleOwner() {
578        fullyInitializeRegistry();
579        mLifecycleOwner = null;
580        forceGc();
581        TestObserver observer = mock(TestObserver.class);
582        mRegistry.addObserver(observer);
583        verify(observer, never()).onCreate();
584        verify(observer, never()).onStart();
585        verify(observer, never()).onResume();
586    }
587
588    private void dispatchEvent(Lifecycle.Event event) {
589        when(mLifecycle.getCurrentState()).thenReturn(LifecycleRegistry.getStateAfter(event));
590        mRegistry.handleLifecycleEvent(event);
591    }
592
593    private void fullyInitializeRegistry() {
594        dispatchEvent(ON_CREATE);
595        dispatchEvent(ON_START);
596        dispatchEvent(ON_RESUME);
597    }
598
599    private abstract class TestObserver implements LifecycleObserver {
600        @OnLifecycleEvent(ON_CREATE)
601        void onCreate() {
602        }
603
604        @OnLifecycleEvent(ON_START)
605        void onStart() {
606        }
607
608        @OnLifecycleEvent(ON_RESUME)
609        void onResume() {
610        }
611
612        @OnLifecycleEvent(ON_PAUSE)
613        void onPause() {
614        }
615
616        @OnLifecycleEvent(ON_STOP)
617        void onStop() {
618        }
619
620        @OnLifecycleEvent(ON_DESTROY)
621        void onDestroy() {
622        }
623    }
624}
625