blob: 43a6a8e985254634c1bba8a2a8bcfaf1892c9f5e [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.apps.common;
import static com.android.car.apps.common.util.LiveDataFunctions.dataOf;
import static com.android.car.apps.common.util.LiveDataFunctions.nullLiveData;
import static com.google.common.truth.Truth.assertThat;
import androidx.core.util.Pair;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.car.apps.common.testutils.CaptureObserver;
import com.android.car.apps.common.testutils.InstantTaskExecutorRule;
import com.android.car.apps.common.testutils.TestLifecycleOwner;
import com.android.car.apps.common.util.LiveDataFunctions;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
@RunWith(AndroidJUnit4.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 testIff_truthTable() {
Object object = new Object();
testBinaryOperator(
(predicate, value) -> LiveDataFunctions.iff(predicate, Boolean::booleanValue,
value),
pair(pair(dataOf(true), dataOf(object)), object),
pair(pair(dataOf(false), 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(dataOf(false), new MutableLiveData<>()),
pair(dataOf(true), 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()).isSameInstanceAs(valueObject);
observer.reset();
predicate.setValue(null);
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isNull();
}
@Test
public void testIff_changeValue() {
LiveData<Boolean> predicate = dataOf(true);
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()).isSameInstanceAs(firstObject);
observer.reset();
value.setValue(new Object());
assertThat(observer.hasBeenNotified()).isTrue();
assertThat(observer.getObservedValue()).isNotSameInstanceAs(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(dataOf(false), Boolean::booleanValue, irrelevantValue)
.observe(mLifecycleOwner, observer);
assertThat(observer.hasBeenNotified()).isTrue();
observer.reset();
irrelevantValue.setValue(null);
assertThat(observer.hasBeenNotified()).isFalse();
}
@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).isSameInstanceAs(first);
assertThat(observedValue.second).isSameInstanceAs(second);
Object third = new Object();
firstData.setValue(third);
observedValue = observer.getObservedValue();
assertThat(observedValue).isNotNull();
assertThat(observedValue.first).isSameInstanceAs(third);
assertThat(observedValue.second).isSameInstanceAs(second);
}
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));
}
}
}