[go: nahoru, domu]

blob: f57d864b5a80d58f4ec3f70d1f7a8914a21ab24e [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.lifecycle;
import static androidx.lifecycle.Lifecycle.Event.ON_CREATE;
import static androidx.lifecycle.Lifecycle.Event.ON_DESTROY;
import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
import static androidx.lifecycle.Lifecycle.Event.ON_START;
import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.only;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import androidx.annotation.Nullable;
import androidx.arch.core.executor.ArchTaskExecutor;
import androidx.arch.core.executor.testing.InstantTaskExecutorRule;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mockito;
@SuppressWarnings({"unchecked"})
@RunWith(JUnit4.class)
public class LiveDataTest {
@Rule
public InstantTaskExecutorRule mInstantTaskExecutorRule = new InstantTaskExecutorRule();
private PublicLiveData<String> mLiveData;
private MethodExec mActiveObserversChanged;
private LifecycleOwner mOwner;
private LifecycleRegistry mRegistry;
private LifecycleOwner mOwner2;
private LifecycleRegistry mRegistry2;
private LifecycleOwner mOwner3;
private Lifecycle mLifecycle3;
private Observer<String> mObserver3;
private LifecycleOwner mOwner4;
private Lifecycle mLifecycle4;
private Observer<String> mObserver4;
private boolean mInObserver;
@Before
public void init() {
mLiveData = new PublicLiveData<>();
mActiveObserversChanged = mock(MethodExec.class);
mLiveData.activeObserversChanged = mActiveObserversChanged;
mOwner = mock(LifecycleOwner.class);
mRegistry = new LifecycleRegistry(mOwner);
when(mOwner.getLifecycle()).thenReturn(mRegistry);
mOwner2 = mock(LifecycleOwner.class);
mRegistry2 = new LifecycleRegistry(mOwner2);
when(mOwner2.getLifecycle()).thenReturn(mRegistry2);
mInObserver = false;
}
@Before
public void initNonLifecycleRegistry() {
mOwner3 = mock(LifecycleOwner.class);
mLifecycle3 = mock(Lifecycle.class);
mObserver3 = (Observer<String>) mock(Observer.class);
when(mOwner3.getLifecycle()).thenReturn(mLifecycle3);
mOwner4 = mock(LifecycleOwner.class);
mLifecycle4 = mock(Lifecycle.class);
mObserver4 = (Observer<String>) mock(Observer.class);
when(mOwner4.getLifecycle()).thenReturn(mLifecycle4);
}
@After
public void removeExecutorDelegate() {
ArchTaskExecutor.getInstance().setDelegate(null);
}
@Test
public void testObserverToggle() {
Observer<String> observer = (Observer<String>) mock(Observer.class);
mLiveData.observe(mOwner, observer);
verify(mActiveObserversChanged, never()).onCall(anyBoolean());
assertThat(mLiveData.hasObservers(), is(true));
assertThat(mLiveData.hasActiveObservers(), is(false));
mLiveData.removeObserver(observer);
verify(mActiveObserversChanged, never()).onCall(anyBoolean());
assertThat(mLiveData.hasObservers(), is(false));
assertThat(mLiveData.hasActiveObservers(), is(false));
}
@Test
public void testActiveObserverToggle() {
Observer<String> observer = (Observer<String>) mock(Observer.class);
mLiveData.observe(mOwner, observer);
verify(mActiveObserversChanged, never()).onCall(anyBoolean());
assertThat(mLiveData.hasObservers(), is(true));
assertThat(mLiveData.hasActiveObservers(), is(false));
mRegistry.handleLifecycleEvent(ON_START);
verify(mActiveObserversChanged).onCall(true);
assertThat(mLiveData.hasActiveObservers(), is(true));
reset(mActiveObserversChanged);
mRegistry.handleLifecycleEvent(ON_STOP);
verify(mActiveObserversChanged).onCall(false);
assertThat(mLiveData.hasActiveObservers(), is(false));
assertThat(mLiveData.hasObservers(), is(true));
reset(mActiveObserversChanged);
mRegistry.handleLifecycleEvent(ON_START);
verify(mActiveObserversChanged).onCall(true);
assertThat(mLiveData.hasActiveObservers(), is(true));
assertThat(mLiveData.hasObservers(), is(true));
reset(mActiveObserversChanged);
mLiveData.removeObserver(observer);
verify(mActiveObserversChanged).onCall(false);
assertThat(mLiveData.hasActiveObservers(), is(false));
assertThat(mLiveData.hasObservers(), is(false));
verifyNoMoreInteractions(mActiveObserversChanged);
}
@Test
public void testReAddSameObserverTuple() {
Observer<String> observer = (Observer<String>) mock(Observer.class);
mLiveData.observe(mOwner, observer);
mLiveData.observe(mOwner, observer);
assertThat(mLiveData.hasObservers(), is(true));
}
@Test
public void testAdd2ObserversWithSameOwnerAndRemove() {
Observer<String> o1 = (Observer<String>) mock(Observer.class);
Observer<String> o2 = (Observer<String>) mock(Observer.class);
mLiveData.observe(mOwner, o1);
mLiveData.observe(mOwner, o2);
assertThat(mLiveData.hasObservers(), is(true));
verify(mActiveObserversChanged, never()).onCall(anyBoolean());
mRegistry.handleLifecycleEvent(ON_START);
verify(mActiveObserversChanged).onCall(true);
mLiveData.setValue("a");
verify(o1).onChanged("a");
verify(o2).onChanged("a");
mLiveData.removeObservers(mOwner);
assertThat(mLiveData.hasObservers(), is(false));
assertThat(mRegistry.getObserverCount(), is(0));
}
@Test
public void testAddSameObserverIn2LifecycleOwners() {
Observer<String> observer = (Observer<String>) mock(Observer.class);
mLiveData.observe(mOwner, observer);
Throwable throwable = null;
try {
mLiveData.observe(mOwner2, observer);
} catch (Throwable t) {
throwable = t;
}
assertThat(throwable, instanceOf(IllegalArgumentException.class));
//noinspection ConstantConditions
assertThat(throwable.getMessage(),
is("Cannot add the same observer with different lifecycles"));
}
@Test
public void testRemoveDestroyedObserver() {
Observer<String> observer = (Observer<String>) mock(Observer.class);
mLiveData.observe(mOwner, observer);
mRegistry.handleLifecycleEvent(ON_START);
verify(mActiveObserversChanged).onCall(true);
assertThat(mLiveData.hasObservers(), is(true));
assertThat(mLiveData.hasActiveObservers(), is(true));
reset(mActiveObserversChanged);
mRegistry.handleLifecycleEvent(ON_DESTROY);
assertThat(mLiveData.hasObservers(), is(false));
assertThat(mLiveData.hasActiveObservers(), is(false));
verify(mActiveObserversChanged).onCall(false);
}
@Test
public void testInactiveRegistry() {
Observer<String> observer = (Observer<String>) mock(Observer.class);
mRegistry.handleLifecycleEvent(ON_DESTROY);
mLiveData.observe(mOwner, observer);
assertThat(mLiveData.hasObservers(), is(false));
}
@Test
public void testNotifyActiveInactive() {
Observer<String> observer = (Observer<String>) mock(Observer.class);
mRegistry.handleLifecycleEvent(ON_CREATE);
mLiveData.observe(mOwner, observer);
mLiveData.setValue("a");
verify(observer, never()).onChanged(anyString());
mRegistry.handleLifecycleEvent(ON_START);
verify(observer).onChanged("a");
mLiveData.setValue("b");
verify(observer).onChanged("b");
mRegistry.handleLifecycleEvent(ON_STOP);
mLiveData.setValue("c");
verify(observer, never()).onChanged("c");
mRegistry.handleLifecycleEvent(ON_START);
verify(observer).onChanged("c");
reset(observer);
mRegistry.handleLifecycleEvent(ON_STOP);
mRegistry.handleLifecycleEvent(ON_START);
verify(observer, never()).onChanged(anyString());
}
@Test
public void testStopObservingOwner_onDestroy() {
Observer<String> observer = (Observer<String>) mock(Observer.class);
mRegistry.handleLifecycleEvent(ON_CREATE);
mLiveData.observe(mOwner, observer);
assertThat(mRegistry.getObserverCount(), is(1));
mRegistry.handleLifecycleEvent(ON_DESTROY);
assertThat(mRegistry.getObserverCount(), is(0));
}
@Test
public void testStopObservingOwner_onStopObserving() {
Observer<String> observer = (Observer<String>) mock(Observer.class);
mRegistry.handleLifecycleEvent(ON_CREATE);
mLiveData.observe(mOwner, observer);
assertThat(mRegistry.getObserverCount(), is(1));
mLiveData.removeObserver(observer);
assertThat(mRegistry.getObserverCount(), is(0));
}
@Test
public void testActiveChangeInCallback() {
mRegistry.handleLifecycleEvent(ON_START);
Observer<String> observer1 = spy(new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
mRegistry.handleLifecycleEvent(ON_STOP);
assertThat(mLiveData.hasObservers(), is(true));
assertThat(mLiveData.hasActiveObservers(), is(false));
}
});
final Observer observer2 = mock(Observer.class);
mLiveData.observe(mOwner, observer1);
mLiveData.observe(mOwner, observer2);
mLiveData.setValue("bla");
verify(observer1).onChanged(anyString());
verify(observer2, Mockito.never()).onChanged(anyString());
assertThat(mLiveData.hasObservers(), is(true));
assertThat(mLiveData.hasActiveObservers(), is(false));
}
@Test
public void testActiveChangeInCallback2() {
Observer<String> observer1 = spy(new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
assertThat(mInObserver, is(false));
mInObserver = true;
mRegistry.handleLifecycleEvent(ON_START);
assertThat(mLiveData.hasActiveObservers(), is(true));
mInObserver = false;
}
});
final Observer observer2 = spy(new FailReentranceObserver());
mLiveData.observeForever(observer1);
mLiveData.observe(mOwner, observer2);
mLiveData.setValue("bla");
verify(observer1).onChanged(anyString());
verify(observer2).onChanged(anyString());
assertThat(mLiveData.hasObservers(), is(true));
assertThat(mLiveData.hasActiveObservers(), is(true));
}
@Test
public void testObserverRemovalInCallback() {
mRegistry.handleLifecycleEvent(ON_START);
Observer<String> observer = spy(new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
assertThat(mLiveData.hasObservers(), is(true));
mLiveData.removeObserver(this);
assertThat(mLiveData.hasObservers(), is(false));
}
});
mLiveData.observe(mOwner, observer);
mLiveData.setValue("bla");
verify(observer).onChanged(anyString());
assertThat(mLiveData.hasObservers(), is(false));
}
@Test
public void testObserverAdditionInCallback() {
mRegistry.handleLifecycleEvent(ON_START);
final Observer observer2 = spy(new FailReentranceObserver());
Observer<String> observer1 = spy(new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
assertThat(mInObserver, is(false));
mInObserver = true;
mLiveData.observe(mOwner, observer2);
assertThat(mLiveData.hasObservers(), is(true));
assertThat(mLiveData.hasActiveObservers(), is(true));
mInObserver = false;
}
});
mLiveData.observe(mOwner, observer1);
mLiveData.setValue("bla");
verify(observer1).onChanged(anyString());
verify(observer2).onChanged(anyString());
assertThat(mLiveData.hasObservers(), is(true));
assertThat(mLiveData.hasActiveObservers(), is(true));
}
@Test
public void testObserverWithoutLifecycleOwner() {
Observer<String> observer = (Observer<String>) mock(Observer.class);
mLiveData.setValue("boring");
mLiveData.observeForever(observer);
verify(mActiveObserversChanged).onCall(true);
verify(observer).onChanged("boring");
mLiveData.setValue("tihs");
verify(observer).onChanged("tihs");
mLiveData.removeObserver(observer);
verify(mActiveObserversChanged).onCall(false);
mLiveData.setValue("boring");
reset(observer);
verify(observer, never()).onChanged(anyString());
}
@Test
public void testSetValueDuringSetValue() {
mRegistry.handleLifecycleEvent(ON_START);
final Observer observer1 = spy(new Observer<String>() {
@Override
public void onChanged(String o) {
assertThat(mInObserver, is(false));
mInObserver = true;
if (o.equals(("bla"))) {
mLiveData.setValue("gt");
}
mInObserver = false;
}
});
final Observer observer2 = spy(new FailReentranceObserver());
mLiveData.observe(mOwner, observer1);
mLiveData.observe(mOwner, observer2);
mLiveData.setValue("bla");
verify(observer1, Mockito.atMost(2)).onChanged("gt");
verify(observer2, Mockito.atMost(2)).onChanged("gt");
}
@Test
public void testRemoveDuringSetValue() {
mRegistry.handleLifecycleEvent(ON_START);
final Observer observer1 = spy(new Observer<String>() {
@Override
public void onChanged(String o) {
mLiveData.removeObserver(this);
}
});
Observer<String> observer2 = (Observer<String>) mock(Observer.class);
mLiveData.observeForever(observer1);
mLiveData.observe(mOwner, observer2);
mLiveData.setValue("gt");
verify(observer2).onChanged("gt");
}
@Test
public void testDataChangeDuringStateChange() {
mRegistry.handleLifecycleEvent(ON_START);
mRegistry.addObserver(new LifecycleObserver() {
@OnLifecycleEvent(ON_STOP)
public void onStop() {
// change data in onStop, observer should not be called!
mLiveData.setValue("b");
}
});
Observer<String> observer = (Observer<String>) mock(Observer.class);
mLiveData.setValue("a");
mLiveData.observe(mOwner, observer);
verify(observer).onChanged("a");
mRegistry.handleLifecycleEvent(ON_PAUSE);
mRegistry.handleLifecycleEvent(ON_STOP);
verify(observer, never()).onChanged("b");
mRegistry.handleLifecycleEvent(ON_RESUME);
verify(observer).onChanged("b");
}
@Test
public void testNotCallInactiveWithObserveForever() {
mRegistry.handleLifecycleEvent(ON_START);
Observer<String> observer = (Observer<String>) mock(Observer.class);
Observer<String> observer2 = (Observer<String>) mock(Observer.class);
mLiveData.observe(mOwner, observer);
mLiveData.observeForever(observer2);
verify(mActiveObserversChanged).onCall(true);
reset(mActiveObserversChanged);
mRegistry.handleLifecycleEvent(ON_STOP);
verify(mActiveObserversChanged, never()).onCall(anyBoolean());
mRegistry.handleLifecycleEvent(ON_START);
verify(mActiveObserversChanged, never()).onCall(anyBoolean());
}
@Test
public void testRemoveDuringAddition() {
mRegistry.handleLifecycleEvent(ON_START);
mLiveData.setValue("bla");
mLiveData.observeForever(new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
mLiveData.removeObserver(this);
}
});
assertThat(mLiveData.hasActiveObservers(), is(false));
InOrder inOrder = Mockito.inOrder(mActiveObserversChanged);
inOrder.verify(mActiveObserversChanged).onCall(true);
inOrder.verify(mActiveObserversChanged).onCall(false);
inOrder.verifyNoMoreInteractions();
}
@Test
public void testRemoveDuringBringingUpToState() {
mLiveData.setValue("bla");
mLiveData.observeForever(new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
mLiveData.removeObserver(this);
}
});
mRegistry.handleLifecycleEvent(ON_RESUME);
assertThat(mLiveData.hasActiveObservers(), is(false));
InOrder inOrder = Mockito.inOrder(mActiveObserversChanged);
inOrder.verify(mActiveObserversChanged).onCall(true);
inOrder.verify(mActiveObserversChanged).onCall(false);
inOrder.verifyNoMoreInteractions();
}
@Test
public void setValue_neverActive_observerOnChangedNotCalled() {
Observer<String> observer = (Observer<String>) mock(Observer.class);
mLiveData.observe(mOwner, observer);
mLiveData.setValue("1");
verify(observer, never()).onChanged(anyString());
}
@Test
public void setValue_twoObserversTwoStartedOwners_onChangedCalledOnBoth() {
Observer<String> observer1 = mock(Observer.class);
Observer<String> observer2 = mock(Observer.class);
mLiveData.observe(mOwner, observer1);
mLiveData.observe(mOwner2, observer2);
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
mRegistry2.handleLifecycleEvent(Lifecycle.Event.ON_START);
mLiveData.setValue("1");
verify(observer1).onChanged("1");
verify(observer2).onChanged("1");
}
@Test
public void setValue_twoObserversOneStartedOwner_onChangedCalledOnOneCorrectObserver() {
Observer<String> observer1 = mock(Observer.class);
Observer<String> observer2 = mock(Observer.class);
mLiveData.observe(mOwner, observer1);
mLiveData.observe(mOwner2, observer2);
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
mLiveData.setValue("1");
verify(observer1).onChanged("1");
verify(observer2, never()).onChanged(anyString());
}
@Test
public void setValue_twoObserversBothStartedAfterSetValue_onChangedCalledOnBoth() {
Observer<String> observer1 = mock(Observer.class);
Observer<String> observer2 = mock(Observer.class);
mLiveData.observe(mOwner, observer1);
mLiveData.observe(mOwner2, observer2);
mLiveData.setValue("1");
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
mRegistry2.handleLifecycleEvent(Lifecycle.Event.ON_START);
verify(observer1).onChanged("1");
verify(observer1).onChanged("1");
}
@Test
public void setValue_twoObserversOneStartedAfterSetValue_onChangedCalledOnCorrectObserver() {
Observer<String> observer1 = mock(Observer.class);
Observer<String> observer2 = mock(Observer.class);
mLiveData.observe(mOwner, observer1);
mLiveData.observe(mOwner2, observer2);
mLiveData.setValue("1");
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
verify(observer1).onChanged("1");
verify(observer2, never()).onChanged(anyString());
}
@Test
public void setValue_twoObserversOneStarted_liveDataBecomesActive() {
Observer<String> observer1 = mock(Observer.class);
Observer<String> observer2 = mock(Observer.class);
mLiveData.observe(mOwner, observer1);
mLiveData.observe(mOwner2, observer2);
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
verify(mActiveObserversChanged).onCall(true);
}
@Test
public void setValue_twoObserversOneStopped_liveDataStaysActive() {
Observer<String> observer1 = mock(Observer.class);
Observer<String> observer2 = mock(Observer.class);
mLiveData.observe(mOwner, observer1);
mLiveData.observe(mOwner2, observer2);
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
mRegistry2.handleLifecycleEvent(Lifecycle.Event.ON_START);
verify(mActiveObserversChanged).onCall(true);
reset(mActiveObserversChanged);
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
verify(mActiveObserversChanged, never()).onCall(anyBoolean());
}
@Test
public void setValue_lifecycleIsCreatedNoEvent_liveDataBecomesInactiveAndObserverNotCalled() {
// Arrange.
mLiveData.observe(mOwner3, mObserver3);
LifecycleEventObserver lifecycleObserver = getLiveDataInternalObserver(mLifecycle3);
when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
lifecycleObserver.onStateChanged(mOwner3, Lifecycle.Event.ON_START);
when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.CREATED);
reset(mActiveObserversChanged);
reset(mObserver3);
// Act.
mLiveData.setValue("1");
// Assert.
verify(mActiveObserversChanged).onCall(false);
verify(mObserver3, never()).onChanged(anyString());
}
/*
* Arrange: LiveData was made inactive via SetValue (because the Lifecycle it was
* observing was in the CREATED state and no event was dispatched).
* Act: Lifecycle enters Started state and dispatches event.
* Assert: LiveData becomes active and dispatches new value to observer.
*/
@Test
public void test_liveDataInactiveViaSetValueThenLifecycleResumes() {
// Arrange.
mLiveData.observe(mOwner3, mObserver3);
LifecycleEventObserver lifecycleObserver = getLiveDataInternalObserver(mLifecycle3);
when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
lifecycleObserver.onStateChanged(mOwner3, Lifecycle.Event.ON_START);
when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.CREATED);
mLiveData.setValue("1");
reset(mActiveObserversChanged);
reset(mObserver3);
// Act.
when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
lifecycleObserver.onStateChanged(mOwner3, Lifecycle.Event.ON_START);
// Assert.
verify(mActiveObserversChanged).onCall(true);
verify(mObserver3).onChanged("1");
}
/*
* Arrange: One of two Lifecycles enter the CREATED state without sending an event.
* Act: Lifecycle's setValue method is called with new value.
* Assert: LiveData stays active and new value is dispatched to Lifecycle that is still at least
* STARTED.
*/
@Test
public void setValue_oneOfTwoLifecyclesAreCreatedNoEvent() {
// Arrange.
mLiveData.observe(mOwner3, mObserver3);
mLiveData.observe(mOwner4, mObserver4);
LifecycleEventObserver lifecycleObserver3 = getLiveDataInternalObserver(mLifecycle3);
LifecycleEventObserver lifecycleObserver4 = getLiveDataInternalObserver(mLifecycle4);
when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
when(mLifecycle4.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
lifecycleObserver3.onStateChanged(mOwner3, Lifecycle.Event.ON_START);
lifecycleObserver4.onStateChanged(mOwner4, Lifecycle.Event.ON_START);
when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.CREATED);
reset(mActiveObserversChanged);
reset(mObserver3);
reset(mObserver4);
// Act.
mLiveData.setValue("1");
// Assert.
verify(mActiveObserversChanged, never()).onCall(anyBoolean());
verify(mObserver3, never()).onChanged(anyString());
verify(mObserver4).onChanged("1");
}
/*
* Arrange: Two observed Lifecycles enter the CREATED state without sending an event.
* Act: Lifecycle's setValue method is called with new value.
* Assert: LiveData becomes inactive and nothing is dispatched to either observer.
*/
@Test
public void setValue_twoLifecyclesAreCreatedNoEvent() {
// Arrange.
mLiveData.observe(mOwner3, mObserver3);
mLiveData.observe(mOwner4, mObserver4);
LifecycleEventObserver lifecycleObserver3 = getLiveDataInternalObserver(mLifecycle3);
LifecycleEventObserver lifecycleObserver4 = getLiveDataInternalObserver(mLifecycle4);
when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
when(mLifecycle4.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
lifecycleObserver3.onStateChanged(mOwner3, Lifecycle.Event.ON_START);
lifecycleObserver4.onStateChanged(mOwner4, Lifecycle.Event.ON_START);
when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.CREATED);
when(mLifecycle4.getCurrentState()).thenReturn(Lifecycle.State.CREATED);
reset(mActiveObserversChanged);
reset(mObserver3);
reset(mObserver4);
// Act.
mLiveData.setValue("1");
// Assert.
verify(mActiveObserversChanged).onCall(false);
verify(mObserver3, never()).onChanged(anyString());
verify(mObserver3, never()).onChanged(anyString());
}
/*
* Arrange: LiveData was made inactive via SetValue (because both Lifecycles it was
* observing were in the CREATED state and no event was dispatched).
* Act: One Lifecycle enters STARTED state and dispatches lifecycle event.
* Assert: LiveData becomes active and dispatches new value to observer associated with started
* Lifecycle.
*/
@Test
public void test_liveDataInactiveViaSetValueThenOneLifecycleResumes() {
// Arrange.
mLiveData.observe(mOwner3, mObserver3);
mLiveData.observe(mOwner4, mObserver4);
LifecycleEventObserver lifecycleObserver3 = getLiveDataInternalObserver(mLifecycle3);
LifecycleEventObserver lifecycleObserver4 = getLiveDataInternalObserver(mLifecycle4);
when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
when(mLifecycle4.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
lifecycleObserver3.onStateChanged(mOwner3, Lifecycle.Event.ON_START);
lifecycleObserver4.onStateChanged(mOwner4, Lifecycle.Event.ON_START);
when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.CREATED);
when(mLifecycle4.getCurrentState()).thenReturn(Lifecycle.State.CREATED);
mLiveData.setValue("1");
reset(mActiveObserversChanged);
reset(mObserver3);
reset(mObserver4);
// Act.
when(mLifecycle3.getCurrentState()).thenReturn(Lifecycle.State.STARTED);
lifecycleObserver3.onStateChanged(mOwner3, Lifecycle.Event.ON_START);
// Assert.
verify(mActiveObserversChanged).onCall(true);
verify(mObserver3).onChanged("1");
verify(mObserver4, never()).onChanged(anyString());
}
@Test
public void nestedForeverObserver() {
mLiveData.setValue(".");
mLiveData.observeForever(new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
mLiveData.observeForever(mock(Observer.class));
mLiveData.removeObserver(this);
}
});
verify(mActiveObserversChanged, only()).onCall(true);
}
@Test
public void readdForeverObserver() {
Observer observer = mock(Observer.class);
mLiveData.observeForever(observer);
mLiveData.observeForever(observer);
mLiveData.removeObserver(observer);
assertThat(mLiveData.hasObservers(), is(false));
}
@Test
public void initialValue() {
MutableLiveData<String> mutableLiveData = new MutableLiveData<>("foo");
Observer<String> observer = mock(Observer.class);
mRegistry.handleLifecycleEvent(ON_START);
mutableLiveData.observe(mOwner, observer);
verify(observer).onChanged("foo");
}
private LifecycleEventObserver getLiveDataInternalObserver(Lifecycle lifecycle) {
ArgumentCaptor<LifecycleEventObserver> captor =
ArgumentCaptor.forClass(LifecycleEventObserver.class);
verify(lifecycle).addObserver(captor.capture());
return (captor.getValue());
}
@SuppressWarnings("WeakerAccess")
static class PublicLiveData<T> extends LiveData<T> {
// cannot spy due to internal calls
public MethodExec activeObserversChanged;
@Override
protected void onActive() {
if (activeObserversChanged != null) {
activeObserversChanged.onCall(true);
}
}
@Override
protected void onInactive() {
if (activeObserversChanged != null) {
activeObserversChanged.onCall(false);
}
}
}
private class FailReentranceObserver<T> implements Observer<T> {
@Override
public void onChanged(@Nullable T t) {
assertThat(mInObserver, is(false));
}
}
interface MethodExec {
void onCall(boolean value);
}
}