1 /* 2 * Copyright (C) 2021 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 17 package com.android.systemui.statusbar.notification.collection 18 19 import android.testing.AndroidTestingRunner 20 import android.testing.TestableLooper.RunWithLooper 21 import androidx.lifecycle.Observer 22 import androidx.test.filters.SmallTest 23 import com.android.systemui.SysuiTestCase 24 import com.android.systemui.util.concurrency.FakeExecutor 25 import com.android.systemui.util.mockito.mock 26 import com.android.systemui.util.time.FakeSystemClock 27 import com.google.common.truth.Truth.assertThat 28 import org.junit.Before 29 import org.junit.Test 30 import org.junit.runner.RunWith 31 import org.mockito.Mockito.eq 32 import org.mockito.Mockito.inOrder 33 import org.mockito.Mockito.verify 34 import org.mockito.Mockito.verifyNoMoreInteractions 35 36 @SmallTest 37 @RunWith(AndroidTestingRunner::class) 38 @RunWithLooper 39 class NotifLiveDataImplTest : SysuiTestCase() { 40 41 private val executor = FakeExecutor(FakeSystemClock()) 42 private val liveDataImpl: NotifLiveDataImpl<Int> = NotifLiveDataImpl("tst", 9, executor) 43 private val syncObserver: Observer<Int> = mock() 44 private val asyncObserver: Observer<Int> = mock() 45 46 @Before 47 fun setup() { 48 allowTestableLooperAsMainThread() 49 liveDataImpl.addSyncObserver(syncObserver) 50 liveDataImpl.addAsyncObserver(asyncObserver) 51 } 52 53 @Test 54 fun testGetInitialValue() { 55 assertThat(liveDataImpl.value).isEqualTo(9) 56 } 57 58 @Test 59 fun testGetModifiedValue() { 60 liveDataImpl.value = 13 61 assertThat(liveDataImpl.value).isEqualTo(13) 62 } 63 64 @Test 65 fun testGetsModifiedValueFromWithinSyncObserver() { 66 liveDataImpl.addSyncObserver { intVal -> 67 assertThat(intVal).isEqualTo(13) 68 assertThat(liveDataImpl.value).isEqualTo(13) 69 } 70 liveDataImpl.value = 13 71 } 72 73 @Test 74 fun testDoesNotAlertsRemovedObservers() { 75 liveDataImpl.removeObserver(syncObserver) 76 liveDataImpl.removeObserver(asyncObserver) 77 78 liveDataImpl.value = 13 79 80 // There should be no runnables on the executor 81 assertThat(executor.runAllReady()).isEqualTo(0) 82 83 // And observers should not be called 84 verifyNoMoreInteractions(syncObserver, asyncObserver) 85 } 86 87 @Test 88 fun testDoesNotAsyncObserversRemovedSinceChange() { 89 liveDataImpl.value = 13 90 liveDataImpl.removeObserver(asyncObserver) 91 92 // There should be a runnable that will get executed... 93 assertThat(executor.runAllReady()).isEqualTo(1) 94 95 // ...but async observers should not be called 96 verifyNoMoreInteractions(asyncObserver) 97 } 98 99 @Test 100 fun testAlertsObservers() { 101 liveDataImpl.value = 13 102 103 // Verify that the synchronous observer is called immediately 104 verify(syncObserver).onChanged(eq(13)) 105 verifyNoMoreInteractions(syncObserver, asyncObserver) 106 107 // Verify that the asynchronous observer is called when the executor runs 108 assertThat(executor.runAllReady()).isEqualTo(1) 109 verify(asyncObserver).onChanged(eq(13)) 110 verifyNoMoreInteractions(syncObserver, asyncObserver) 111 } 112 113 @Test 114 fun testAlertsObserversFromDispatcher() { 115 // GIVEN that we use setValueAndProvideDispatcher() 116 val dispatcher = liveDataImpl.setValueAndProvideDispatcher(13) 117 118 // VERIFY that nothing is done before the dispatcher is called 119 assertThat(executor.numPending()).isEqualTo(0) 120 verifyNoMoreInteractions(syncObserver, asyncObserver) 121 122 // WHEN the dispatcher is invoked... 123 dispatcher.invoke() 124 125 // Verify that the synchronous observer is called immediately 126 verify(syncObserver).onChanged(eq(13)) 127 verifyNoMoreInteractions(syncObserver, asyncObserver) 128 129 // Verify that the asynchronous observer is called when the executor runs 130 assertThat(executor.runAllReady()).isEqualTo(1) 131 verify(asyncObserver).onChanged(eq(13)) 132 verifyNoMoreInteractions(syncObserver, asyncObserver) 133 } 134 135 @Test 136 fun testSkipsAllObserversIfValueDidNotChange() { 137 liveDataImpl.value = 9 138 // Does not add a runnable 139 assertThat(executor.runAllReady()).isEqualTo(0) 140 // Setting the current value does not call synchronous observers 141 verifyNoMoreInteractions(syncObserver, asyncObserver) 142 } 143 144 @Test 145 fun testSkipsAsyncObserversWhenValueTogglesBack() { 146 liveDataImpl.value = 13 147 liveDataImpl.value = 11 148 liveDataImpl.value = 9 149 150 // Synchronous observers will receive every change event immediately 151 inOrder(syncObserver).apply { 152 verify(syncObserver).onChanged(eq(13)) 153 verify(syncObserver).onChanged(eq(11)) 154 verify(syncObserver).onChanged(eq(9)) 155 } 156 verifyNoMoreInteractions(syncObserver, asyncObserver) 157 158 // Running the first runnable on the queue will just emit the most recent value 159 assertThat(executor.runNextReady()).isTrue() 160 verify(asyncObserver).onChanged(eq(9)) 161 verifyNoMoreInteractions(syncObserver, asyncObserver) 162 163 // Running the next 2 runnable will have no effect 164 assertThat(executor.runAllReady()).isEqualTo(2) 165 verifyNoMoreInteractions(syncObserver, asyncObserver) 166 } 167 }