/**
* Copyright 2014 Netflix, Inc.
*
* 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 rx.internal.operators;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import java.util.*;
import org.junit.Test;
import org.mockito.InOrder;
import rx.Observable;
import rx.Observer;
import rx.exceptions.TestException;
import rx.functions.Func2;
import rx.observers.TestSubscriber;
import rx.subjects.PublishSubject;
public class OperatorWithLatestFromTest {
static final Func2<Integer, Integer, Integer> COMBINER = new Func2<Integer, Integer, Integer>() {
@Override
public Integer call(Integer t1, Integer t2) {
return (t1 << 8) + t2;
}
};
static final Func2<Integer, Integer, Integer> COMBINER_ERROR = new Func2<Integer, Integer, Integer>() {
@Override
public Integer call(Integer t1, Integer t2) {
throw new TestException("Forced failure");
}
};
@Test
public void testSimple() {
PublishSubject<Integer> source = PublishSubject.create();
PublishSubject<Integer> other = PublishSubject.create();
@SuppressWarnings("unchecked")
Observer<Integer> o = mock(Observer.class);
InOrder inOrder = inOrder(o);
Observable<Integer> result = source.withLatestFrom(other, COMBINER);
result.subscribe(o);
source.onNext(1);
inOrder.verify(o, never()).onNext(anyInt());
other.onNext(1);
inOrder.verify(o, never()).onNext(anyInt());
source.onNext(2);
inOrder.verify(o).onNext((2 << 8) + 1);
other.onNext(2);
inOrder.verify(o, never()).onNext(anyInt());
other.onCompleted();
inOrder.verify(o, never()).onCompleted();
source.onNext(3);
inOrder.verify(o).onNext((3 << 8) + 2);
source.onCompleted();
inOrder.verify(o).onCompleted();
verify(o, never()).onError(any(Throwable.class));
}
@Test
public void testEmptySource() {
PublishSubject<Integer> source = PublishSubject.create();
PublishSubject<Integer> other = PublishSubject.create();
Observable<Integer> result = source.withLatestFrom(other, COMBINER);
TestSubscriber<Integer> ts = new TestSubscriber<Integer>();
result.subscribe(ts);
assertTrue(source.hasObservers());
assertTrue(other.hasObservers());
other.onNext(1);
source.onCompleted();
ts.assertNoErrors();
ts.assertTerminalEvent();
assertEquals(0, ts.getOnNextEvents().size());
assertFalse(source.hasObservers());
assertFalse(other.hasObservers());
}
@Test
public void testEmptyOther() {
PublishSubject<Integer> source = PublishSubject.create();
PublishSubject<Integer> other = PublishSubject.create();
Observable<Integer> result = source.withLatestFrom(other, COMBINER);
TestSubscriber<Integer> ts = new TestSubscriber<Integer>();
result.subscribe(ts);
assertTrue(source.hasObservers());
assertTrue(other.hasObservers());
source.onNext(1);
source.onCompleted();
ts.assertNoErrors();
ts.assertTerminalEvent();
assertEquals(0, ts.getOnNextEvents().size());
assertFalse(source.hasObservers());
assertFalse(other.hasObservers());
}
@Test
public void testUnsubscription() {
PublishSubject<Integer> source = PublishSubject.create();
PublishSubject<Integer> other = PublishSubject.create();
Observable<Integer> result = source.withLatestFrom(other, COMBINER);
TestSubscriber<Integer> ts = new TestSubscriber<Integer>();
result.subscribe(ts);
assertTrue(source.hasObservers());
assertTrue(other.hasObservers());
other.onNext(1);
source.onNext(1);
ts.unsubscribe();
ts.assertReceivedOnNext(Arrays.asList((1 << 8) + 1));
ts.assertNoErrors();
assertEquals(0, ts.getOnCompletedEvents().size());
assertFalse(source.hasObservers());
assertFalse(other.hasObservers());
}
@Test
public void testSourceThrows() {
PublishSubject<Integer> source = PublishSubject.create();
PublishSubject<Integer> other = PublishSubject.create();
Observable<Integer> result = source.withLatestFrom(other, COMBINER);
TestSubscriber<Integer> ts = new TestSubscriber<Integer>();
result.subscribe(ts);
assertTrue(source.hasObservers());
assertTrue(other.hasObservers());
other.onNext(1);
source.onNext(1);
source.onError(new TestException());
ts.assertTerminalEvent();
ts.assertReceivedOnNext(Arrays.asList((1 << 8) + 1));
assertEquals(1, ts.getOnErrorEvents().size());
assertTrue(ts.getOnErrorEvents().get(0) instanceof TestException);
assertFalse(source.hasObservers());
assertFalse(other.hasObservers());
}
@Test
public void testOtherThrows() {
PublishSubject<Integer> source = PublishSubject.create();
PublishSubject<Integer> other = PublishSubject.create();
Observable<Integer> result = source.withLatestFrom(other, COMBINER);
TestSubscriber<Integer> ts = new TestSubscriber<Integer>();
result.subscribe(ts);
assertTrue(source.hasObservers());
assertTrue(other.hasObservers());
other.onNext(1);
source.onNext(1);
other.onError(new TestException());
ts.assertTerminalEvent();
ts.assertReceivedOnNext(Arrays.asList((1 << 8) + 1));
assertEquals(1, ts.getOnErrorEvents().size());
assertTrue(ts.getOnErrorEvents().get(0) instanceof TestException);
assertFalse(source.hasObservers());
assertFalse(other.hasObservers());
}
@Test
public void testFunctionThrows() {
PublishSubject<Integer> source = PublishSubject.create();
PublishSubject<Integer> other = PublishSubject.create();
Observable<Integer> result = source.withLatestFrom(other, COMBINER_ERROR);
TestSubscriber<Integer> ts = new TestSubscriber<Integer>();
result.subscribe(ts);
assertTrue(source.hasObservers());
assertTrue(other.hasObservers());
other.onNext(1);
source.onNext(1);
ts.assertTerminalEvent();
assertEquals(0, ts.getOnNextEvents().size());
assertEquals(1, ts.getOnErrorEvents().size());
assertTrue(ts.getOnErrorEvents().get(0) instanceof TestException);
assertFalse(source.hasObservers());
assertFalse(other.hasObservers());
}
@Test
public void testNoDownstreamUnsubscribe() {
PublishSubject<Integer> source = PublishSubject.create();
PublishSubject<Integer> other = PublishSubject.create();
Observable<Integer> result = source.withLatestFrom(other, COMBINER);
TestSubscriber<Integer> ts = new TestSubscriber<Integer>();
result.unsafeSubscribe(ts);
source.onCompleted();
assertFalse(ts.isUnsubscribed());
}
@Test
public void testBackpressure() {
Observable<Integer> source = Observable.range(1, 10);
PublishSubject<Integer> other = PublishSubject.create();
Observable<Integer> result = source.withLatestFrom(other, COMBINER);
TestSubscriber<Integer> ts = new TestSubscriber<Integer>() {
@Override
public void onStart() {
request(0);
}
};
result.subscribe(ts);
ts.requestMore(1);
ts.assertReceivedOnNext(Collections.<Integer>emptyList());
other.onNext(1);
ts.requestMore(1);
ts.assertReceivedOnNext(Arrays.asList((2 << 8) + 1));
ts.requestMore(5);
ts.assertReceivedOnNext(Arrays.asList(
(2 << 8) + 1, (3 << 8) + 1, (4 << 8) + 1, (5 << 8) + 1,
(6 << 8) + 1, (7 << 8) + 1
));
ts.unsubscribe();
assertFalse("Other has observers!", other.hasObservers());
ts.assertNoErrors();
}
}