blob: cdcfcb0551ed304fdf515fe4069ca871f2c8425e [file] [log] [blame]
/*
* Copyright 2018 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 com.android.car.arch.common;
import static com.android.car.arch.common.LiveDataFunctions.coalesceNull;
import static com.android.car.arch.common.LiveDataFunctions.dataOf;
import static com.android.car.arch.common.LiveDataFunctions.distinct;
import static com.android.car.arch.common.LiveDataFunctions.emitsNull;
import static com.android.car.arch.common.LiveDataFunctions.falseLiveData;
import static com.android.car.arch.common.LiveDataFunctions.freezable;
import static com.android.car.arch.common.LiveDataFunctions.ifThenElse;
import static com.android.car.arch.common.LiveDataFunctions.not;
import static com.android.car.arch.common.LiveDataFunctions.nullLiveData;
import static com.android.car.arch.common.LiveDataFunctions.split;
import static com.android.car.arch.common.LiveDataFunctions.trueLiveData;
import static com.google.common.truth.Truth.assertThat;
import androidx.core.util.Pair;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.android.car.arch.common.testing.CaptureObserver;
import com.android.car.arch.common.testing.InstantTaskExecutorRule;
import com.android.car.arch.common.testing.TestLifecycleOwner;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
@RunWith(RobolectricTestRunner.class)
public class LiveDataFunctionsTest {
@Rule
public final InstantTaskExecutorRule mRule = new InstantTaskExecutorRule();
@Rule
public final TestLifecycleOwner mLifecycleOwner = new TestLifecycleOwner();
@Test
public void testNullLiveData() {
CaptureObserver<Object> observer = new CaptureObserver<>();
nullLiveData().observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isNull();
assertThat(nullLiveData().getValue()).isNull();
}
@Test
public void testTrueLiveData() {
CaptureObserver<Boolean> observer = new CaptureObserver<>();
trueLiveData().observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isTrue();
assertThat(trueLiveData().getValue()).isTrue();
}
@Test
public void testFalseLiveData() {
CaptureObserver<Boolean> observer = new CaptureObserver<>();
falseLiveData().observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isFalse();
assertThat(falseLiveData().getValue()).isFalse();
}
@Test
public void testNot() {
testUnaryOperator(
LiveDataFunctions::not,
pair(trueLiveData(), false),
pair(falseLiveData(), true),
pair(nullLiveData(), null));
checkUninitialized(not(new MutableLiveData<>()));
}
@Test
public void testEmitsNull() {
testUnaryOperator(
LiveDataFunctions::emitsNull,
pair(dataOf(new Object()), false),
pair(nullLiveData(), true));
checkUninitialized(emitsNull(new MutableLiveData<>()));
}
@Test
public void testDistinct() {
CaptureObserver<Integer> observer = new CaptureObserver<>();
MutableLiveData<Integer> source = dataOf(0);
LiveData<Integer> distinct = distinct(source);
distinct.observe(mLifecycleOwner, observer);
observer.reset();
source.setValue(1);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isEqualTo(1);
observer.reset();
source.setValue(1);
assertThat(observer.hasBeenNotified()).isFalse();
source.setValue(2);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isEqualTo(2);
}
@Test
public void testFreezable() {
CaptureObserver<Integer> observer = new CaptureObserver<>();
MutableLiveData<Boolean> isFrozen = dataOf(false);
MutableLiveData<Integer> source = dataOf(0);
LiveData<Integer> freezable = freezable(isFrozen, source);
freezable.observe(mLifecycleOwner, observer);
// Initialized to correct value.
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isEqualTo(0);
observer.reset();
// Updates with source when not frozen.
source.setValue(1);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isEqualTo(1);
observer.reset();
// Doesn't update when frozen.
isFrozen.setValue(true);
source.setValue(2);
assertThat(observer.hasBeenNotified()).isFalse();
// Updates when unfrozen.
isFrozen.setValue(false);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isEqualTo(2);
observer.reset();
// Doesn't notify if no changes while frozen.
isFrozen.setValue(true);
isFrozen.setValue(false);
assertThat(observer.hasBeenNotified()).isFalse();
}
@Test
public void testAnd_truthTable() {
testBinaryOperator(
LiveDataFunctions::and,
pair(pair(trueLiveData(), trueLiveData()), true),
pair(pair(trueLiveData(), falseLiveData()), false),
pair(pair(trueLiveData(), nullLiveData()), null),
pair(pair(falseLiveData(), trueLiveData()), false),
pair(pair(falseLiveData(), falseLiveData()), false),
pair(pair(falseLiveData(), nullLiveData()), false),
pair(pair(nullLiveData(), trueLiveData()), null),
pair(pair(nullLiveData(), falseLiveData()), false),
pair(pair(nullLiveData(), nullLiveData()), null));
}
@Test
public void testAnd_uninitialized() {
MutableLiveData<Boolean> empty = new MutableLiveData<>();
checkUninitializedBinary(
LiveDataFunctions::and,
pair(trueLiveData(), empty),
pair(falseLiveData(), empty),
pair(nullLiveData(), empty),
pair(empty, trueLiveData()),
pair(empty, falseLiveData()),
pair(empty, nullLiveData()));
}
@Test
public void testAnd_changeValue() {
MutableLiveData<Boolean> source = new MutableLiveData<>();
CaptureObserver<Boolean> observer = new CaptureObserver<>();
LiveDataFunctions.and(trueLiveData(), source).observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isFalse();
source.setValue(true);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isTrue();
}
@Test
public void testOr_truthTable() {
testBinaryOperator(
LiveDataFunctions::or,
pair(pair(trueLiveData(), trueLiveData()), true),
pair(pair(trueLiveData(), falseLiveData()), true),
pair(pair(trueLiveData(), nullLiveData()), true),
pair(pair(falseLiveData(), trueLiveData()), true),
pair(pair(falseLiveData(), falseLiveData()), false),
pair(pair(falseLiveData(), nullLiveData()), null),
pair(pair(nullLiveData(), trueLiveData()), true),
pair(pair(nullLiveData(), falseLiveData()), null),
pair(pair(nullLiveData(), nullLiveData()), null));
}
@Test
public void testOr_uninitialized() {
LiveData<Boolean> empty = new MutableLiveData<>();
checkUninitializedBinary(
LiveDataFunctions::or,
pair(trueLiveData(), empty),
pair(falseLiveData(), empty),
pair(nullLiveData(), empty),
pair(empty, trueLiveData()),
pair(empty, falseLiveData()),
pair(empty, nullLiveData()));
}
@Test
public void testOr_changeValue() {
MutableLiveData<Boolean> source = new MutableLiveData<>();
CaptureObserver<Boolean> observer = new CaptureObserver<>();
LiveDataFunctions.or(trueLiveData(), source).observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isFalse();
source.setValue(true);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isTrue();
}
@Test
public void testIff_truthTable() {
Object object = new Object();
testBinaryOperator(
(predicate, value) -> LiveDataFunctions.iff(predicate, Boolean::booleanValue,
value),
pair(pair(trueLiveData(), dataOf(object)), object),
pair(pair(falseLiveData(), dataOf(object)), null),
pair(pair(nullLiveData(), dataOf(object)), null));
}
@Test
public void testIff_uninitialized() {
checkUninitializedBinary(
(predicate, value) -> LiveDataFunctions.iff(predicate, Boolean::booleanValue,
value),
pair(new MutableLiveData<>(), dataOf(new Object())),
pair(falseLiveData(), new MutableLiveData<>()),
pair(trueLiveData(), new MutableLiveData<>()));
}
@Test
public void testIff_changePredicate() {
MutableLiveData<Boolean> predicate = new MutableLiveData<>();
MutableLiveData<Object> value = new MutableLiveData<>();
Object valueObject = new Object();
value.setValue(valueObject);
CaptureObserver<Object> observer = new CaptureObserver<>();
LiveDataFunctions.iff(predicate, Boolean::booleanValue, value)
.observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isFalse();
predicate.setValue(false);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isNull();
observer.reset();
predicate.setValue(true);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(valueObject);
observer.reset();
predicate.setValue(null);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isNull();
}
@Test
public void testIff_changeValue() {
LiveData<Boolean> predicate = trueLiveData();
MutableLiveData<Object> value = new MutableLiveData<>();
Object firstObject = new Object();
CaptureObserver<Object> observer = new CaptureObserver<>();
LiveDataFunctions.iff(predicate, Boolean::booleanValue, value)
.observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isFalse();
value.setValue(null);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isNull();
observer.reset();
value.setValue(firstObject);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(firstObject);
observer.reset();
value.setValue(new Object());
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isNotSameAs(firstObject);
}
@Test
public void testIff_changeValue_doesntNotifyForIrrelevantChanges() {
MutableLiveData<Object> irrelevantValue = new MutableLiveData<>();
irrelevantValue.setValue(new Object());
CaptureObserver<Object> observer = new CaptureObserver<>();
// irrelevantValue irrelevant because iff() always emits null when predicate is false.
LiveDataFunctions.iff(falseLiveData(), Boolean::booleanValue, irrelevantValue)
.observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isTrue();
observer.reset();
irrelevantValue.setValue(null);
assertThat(observer.hasBeenNotified()).isFalse();
}
@Test
public void testIfThenElse_liveDataParams_truthTable() {
Object trueObject = new Object();
Object falseObject = new Object();
LiveData<Object> trueObjectData = dataOf(trueObject);
LiveData<Object> falseObjectData = dataOf(falseObject);
testOperator(arg -> () ->
ifThenElse(arg.mPredicate, Boolean::booleanValue, arg.mTrueData,
arg.mFalseData),
pair(new IfThenElseDataParams<>(trueLiveData(), trueObjectData, falseObjectData),
trueObject),
pair(new IfThenElseDataParams<>(falseLiveData(), trueObjectData, falseObjectData),
falseObject),
pair(new IfThenElseDataParams<>(dataOf(null), trueObjectData, falseObjectData),
null));
}
@Test
public void testIfThenElse_liveDataParams_uninitialized() {
Object trueObject = new Object();
Object falseObject = new Object();
LiveData<Object> trueObjectData = dataOf(trueObject);
LiveData<Object> falseObjectData = dataOf(falseObject);
checkUninitialized(
ifThenElse(
new MutableLiveData<>(), Boolean::booleanValue, trueObjectData,
falseObjectData));
checkUninitialized(
ifThenElse(
trueLiveData(), Boolean::booleanValue, new MutableLiveData<>(),
falseObjectData));
checkUninitialized(
ifThenElse(
falseLiveData(), Boolean::booleanValue, trueObjectData,
new MutableLiveData<>()));
}
@Test
public void testIfThenElse_liveDataParams_changePredicate() {
Object trueObject = new Object();
Object falseObject = new Object();
LiveData<Object> trueObjectData = dataOf(trueObject);
LiveData<Object> falseObjectData = dataOf(falseObject);
MutableLiveData<Boolean> predicate = new MutableLiveData<>();
CaptureObserver<Object> observer = new CaptureObserver<>();
ifThenElse(predicate, Boolean::booleanValue, trueObjectData,
falseObjectData)
.observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isFalse();
predicate.setValue(false);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(falseObject);
observer.reset();
predicate.setValue(true);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(trueObject);
observer.reset();
predicate.setValue(null);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isNull();
}
@Test
public void testIfThenElse_liveDataParams_changeValue_value() {
Object trueObject = new Object();
Object falseObject = new Object();
MutableLiveData<Object> trueObjectData = new MutableLiveData<>();
LiveData<Object> falseObjectData = dataOf(falseObject);
LiveData<Boolean> predicate = trueLiveData();
CaptureObserver<Object> observer = new CaptureObserver<>();
ifThenElse(predicate, Boolean::booleanValue, trueObjectData,
falseObjectData)
.observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isFalse();
trueObjectData.setValue(null);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isNull();
observer.reset();
trueObjectData.setValue(trueObject);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(trueObject);
observer.reset();
trueObjectData.setValue(new Object());
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isNotSameAs(trueObject);
}
@Test
public void testIfThenElse_liveDataParams_changeValue_doesntNotifyForIrrelevantChanges() {
MutableLiveData<Object> irrelevantValue = new MutableLiveData<>();
irrelevantValue.setValue(new Object());
CaptureObserver<Object> observer = new CaptureObserver<>();
// irrelevantValue irrelevant because ifThenElse() is backed by other param when
// predicate is
// false.
ifThenElse(
falseLiveData(), Boolean::booleanValue, irrelevantValue, dataOf(new Object()))
.observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isTrue();
observer.reset();
irrelevantValue.setValue(null);
assertThat(observer.hasBeenNotified()).isFalse();
}
@Test
public void testIfThenElse_valueParams_truthTable() {
Object trueObject = new Object();
Object falseObject = new Object();
testOperator(arg -> () -> ifThenElse(arg.mPredicate, Boolean::booleanValue, arg.mTrueValue,
arg.mFalseValue),
pair(new IfThenElseValueParams<>(trueLiveData(), trueObject, falseObject),
trueObject),
pair(new IfThenElseValueParams<>(falseLiveData(), trueObject, falseObject),
falseObject),
pair(new IfThenElseValueParams<>(dataOf(null), trueObject, falseObject), null));
}
@Test
public void testIfThenElse_valueParams_uninitialized() {
Object trueObject = new Object();
Object falseObject = new Object();
checkUninitialized(
ifThenElse(new MutableLiveData<>(), Boolean::booleanValue, trueObject,
falseObject));
}
@Test
public void testIfThenElse_valueParams_changePredicate() {
Object trueObject = new Object();
Object falseObject = new Object();
MutableLiveData<Boolean> predicate = new MutableLiveData<>();
CaptureObserver<Object> observer = new CaptureObserver<>();
ifThenElse(predicate, Boolean::booleanValue, trueObject, falseObject)
.observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isFalse();
predicate.setValue(false);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(falseObject);
observer.reset();
predicate.setValue(true);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(trueObject);
observer.reset();
predicate.setValue(null);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isNull();
}
@Test
public void testCoalesceNull_liveDataParams_truthTable() {
TestObject sourceObject = new TestObject();
TestObject fallbackObject = new TestObject();
LiveData<TestObject> sourceData = dataOf(sourceObject);
LiveData<TestObject> fallbackData = dataOf(fallbackObject);
testBinaryOperator(LiveDataFunctions::coalesceNull,
pair(pair(sourceData, fallbackData), sourceObject),
pair(pair(sourceData, nullLiveData()), sourceObject),
// uninitialized fallback is fine.
pair(pair(sourceData, new MutableLiveData<>()), sourceObject),
pair(pair(nullLiveData(), fallbackData), fallbackObject),
pair(pair(nullLiveData(), nullLiveData()), null));
}
@Test
public void testCoalesceNull_liveDataParams_uninitialized() {
TestObject fallbackObject = new TestObject();
LiveData<TestObject> fallbackData = dataOf(fallbackObject);
checkUninitialized(coalesceNull(new MutableLiveData<TestObject>(), fallbackData));
}
@Test
public void testCoalesceNull_liveDataParams_changeSource() {
TestObject firstSourceObject = new TestObject();
TestObject secondSourceObject = new TestObject();
TestObject fallbackObject = new TestObject();
MutableLiveData<TestObject> sourceData = dataOf(null);
LiveData<TestObject> fallbackData = dataOf(fallbackObject);
CaptureObserver<TestObject> observer = new CaptureObserver<>();
LiveData<TestObject> data = coalesceNull(sourceData, fallbackData);
data.observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(fallbackObject);
observer.reset();
sourceData.setValue(firstSourceObject);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(firstSourceObject);
observer.reset();
sourceData.setValue(secondSourceObject);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(secondSourceObject);
observer.reset();
sourceData.setValue(null);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(fallbackObject);
observer.reset();
}
@Test
public void testCoalesceNull_liveDataParams_changeFallback() {
TestObject firstFallbackObject = new TestObject();
TestObject secondFallbackObject = new TestObject();
LiveData<TestObject> sourceData = nullLiveData();
MutableLiveData<TestObject> fallbackData = dataOf(null);
CaptureObserver<TestObject> observer = new CaptureObserver<>();
LiveData<TestObject> data = coalesceNull(sourceData, fallbackData);
data.observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isNull();
observer.reset();
fallbackData.setValue(firstFallbackObject);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(firstFallbackObject);
observer.reset();
fallbackData.setValue(secondFallbackObject);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(secondFallbackObject);
observer.reset();
fallbackData.setValue(null);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(null);
observer.reset();
}
@Test
public void testCoalesceNull_liveDataParams_changeFallback_doesntNotifyForIrrelevantChanges() {
TestObject sourceObject = new TestObject();
TestObject fallbackObject = new TestObject();
LiveData<TestObject> sourceData = dataOf(sourceObject);
// Irrelevant because sourceData is always non-null
MutableLiveData<TestObject> irrelevantData = dataOf(fallbackObject);
CaptureObserver<TestObject> observer = new CaptureObserver<>();
LiveData<TestObject> data = coalesceNull(sourceData, irrelevantData);
data.observe(mLifecycleOwner, observer);
observer.reset();
irrelevantData.setValue(null);
assertThat(observer.hasBeenNotified()).isFalse();
}
@Test
public void testCoalesceNull_valueParams_truthTable() {
Object sourceObject = new Object();
Object fallbackObject = new Object();
LiveData<Object> sourceData = dataOf(sourceObject);
testOperator(args -> () -> coalesceNull(Objects.requireNonNull(args.first), args.second),
pair(pair(sourceData, fallbackObject), sourceObject),
pair(pair(sourceData, null), sourceObject),
pair(pair(nullLiveData(), fallbackObject), fallbackObject),
pair(pair(nullLiveData(), null), null));
}
@Test
public void testCoalesceNull_valueParams_uninitialized() {
// Values contained in SoftReference don't actually matter. SoftReference is just used as
// an easily instantiable type. Object cannot be used because LiveData extends Object,
// and thus some method calls would become ambiguous due to overloads.
Object fallbackObject = new Object();
checkUninitialized(coalesceNull(new MutableLiveData<>(), fallbackObject));
}
@Test
public void testCoalesceNull_valueParams_changeSource() {
// Values contained in SoftReference don't actually matter. SoftReference is just used as
// an easily instantiable type. Object cannot be used because LiveData extends Object,
// and thus some method calls would become ambiguous.
Object firstSourceObject = new Object();
Object secondSourceObject = new Object();
Object fallbackObject = new Object();
MutableLiveData<Object> sourceData = dataOf(null);
CaptureObserver<Object> observer = new CaptureObserver<>();
LiveData<Object> data = coalesceNull(sourceData, fallbackObject);
data.observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(fallbackObject);
observer.reset();
sourceData.setValue(firstSourceObject);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(firstSourceObject);
observer.reset();
sourceData.setValue(secondSourceObject);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(secondSourceObject);
observer.reset();
sourceData.setValue(null);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isSameAs(fallbackObject);
observer.reset();
}
@Test
public void testSplit() {
Object first = new Object();
Object second = new Object();
MutableLiveData<Object> firstData = new MutableLiveData<>();
MutableLiveData<Object> secondData = new MutableLiveData<>();
firstData.setValue(first);
secondData.setValue(second);
Object[] observedValues = new Object[2];
boolean[] notified = new boolean[1];
LiveDataFunctions.pair(firstData, secondData)
.observe(
mLifecycleOwner,
split(
(left, right) -> {
notified[0] = true;
observedValues[0] = left;
observedValues[1] = right;
}));
assertThat(notified[0]).isTrue();
assertThat(observedValues[0]).isSameAs(first);
assertThat(observedValues[1]).isSameAs(second);
}
@Test
public void testSplit_null() {
Object[] observedValues = new Object[2];
boolean[] notified = new boolean[1];
dataOf((Pair<Object, Object>) null)
.observe(
mLifecycleOwner,
split(
(left, right) -> {
notified[0] = true;
observedValues[0] = left;
observedValues[1] = right;
}));
assertThat(notified[0]).isTrue();
assertThat(observedValues[0]).isNull();
assertThat(observedValues[1]).isNull();
}
@Test
public void testCombine() {
Object first = new Object();
Object second = new Object();
MutableLiveData<Object> firstData = new MutableLiveData<>();
MutableLiveData<Object> secondData = new MutableLiveData<>();
firstData.setValue(first);
secondData.setValue(second);
CaptureObserver<Pair<Object, Object>> observer = new CaptureObserver<>();
LiveDataFunctions.combine(firstData, secondData, Pair::new).observe(mLifecycleOwner,
observer);
Pair<Object, Object> observedValue = observer.getObservedValue();
assertThat(observedValue).isNotNull();
assertThat(observedValue.first).isSameAs(first);
assertThat(observedValue.second).isSameAs(second);
Object third = new Object();
firstData.setValue(third);
observedValue = observer.getObservedValue();
assertThat(observedValue).isNotNull();
assertThat(observedValue.first).isSameAs(third);
assertThat(observedValue.second).isSameAs(second);
}
private static class IfThenElseDataParams<T> {
final LiveData<Boolean> mPredicate;
final LiveData<T> mTrueData;
final LiveData<T> mFalseData;
private IfThenElseDataParams(
LiveData<Boolean> predicate, LiveData<T> trueData, LiveData<T> falseData) {
this.mPredicate = predicate;
this.mTrueData = trueData;
this.mFalseData = falseData;
}
}
private static class IfThenElseValueParams<T> {
final LiveData<Boolean> mPredicate;
final T mTrueValue;
final T mFalseValue;
private IfThenElseValueParams(LiveData<Boolean> predicate, T trueValue, T falseValue) {
this.mPredicate = predicate;
this.mTrueValue = trueValue;
this.mFalseValue = falseValue;
}
}
private <R> void testOperator(Supplier<LiveData<R>> op, R result) {
CaptureObserver<R> observer = new CaptureObserver<>();
LiveData<R> data = op.get();
data.observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isEqualTo(result);
assertThat(data.getValue()).isEqualTo(result);
}
@SafeVarargs // args are never written to
private final <P, R> void testOperator(
Function<P, Supplier<LiveData<R>>> ops, Pair<P, R>... args) {
for (Pair<P, R> arg : args) {
testOperator(ops.apply(arg.first), arg.second);
}
}
@SafeVarargs // args are never written to
private final <T, R> void testUnaryOperator(
Function<LiveData<T>, LiveData<R>> op, Pair<LiveData<T>, R>... args) {
testOperator(arg -> () -> op.apply(arg), args);
}
@SafeVarargs // args are never written to
private final <A, B, R> void testBinaryOperator(
BiFunction<LiveData<A>, LiveData<B>, LiveData<R>> op,
Pair<Pair<LiveData<A>, LiveData<B>>, R>... args) {
testOperator(arg -> () -> op.apply(arg.first, arg.second), args);
}
private <T, R> Pair<T, R> pair(T first, R second) {
return new Pair<>(first, second);
}
private <T> void checkUninitialized(LiveData<T> liveData) {
CaptureObserver<T> observer = new CaptureObserver<>();
liveData.observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isFalse();
assertThat(liveData.getValue()).isNull();
}
@SafeVarargs // args are never written to
private final <A, B> void checkUninitializedBinary(
BiFunction<LiveData<A>, LiveData<B>, LiveData<?>> op,
Pair<LiveData<A>, LiveData<B>>... args) {
for (Pair<LiveData<A>, LiveData<B>> arg : args) {
checkUninitialized(op.apply(arg.first, arg.second));
}
}
/**
* Used as an easily instantiable type where Object cannot be used because LiveData extends
* Object, and thus some method calls would become ambiguous.
**/
private class TestObject {
}
}