/**
* Copyright (c) 2016-present, RxJava Contributors.
*
* 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 io.reactivex.internal.operators.observable;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.*;
import org.mockito.InOrder;
import io.reactivex.*;
import io.reactivex.disposables.*;
import io.reactivex.exceptions.*;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.internal.functions.Functions;
import io.reactivex.internal.util.ExceptionHelper;
import io.reactivex.observers.TestObserver;
import io.reactivex.plugins.RxJavaPlugins;
import io.reactivex.schedulers.TestScheduler;
import io.reactivex.subjects.PublishSubject;
public class ObservableSwitchTest {
private TestScheduler scheduler;
private Scheduler.Worker innerScheduler;
private Observer<String> observer;
@Before
public void before() {
scheduler = new TestScheduler();
innerScheduler = scheduler.createWorker();
observer = TestHelper.mockObserver();
}
@Test
public void testSwitchWhenOuterCompleteBeforeInner() {
Observable<Observable<String>> source = Observable.unsafeCreate(new ObservableSource<Observable<String>>() {
@Override
public void subscribe(Observer<? super Observable<String>> outerObserver) {
outerObserver.onSubscribe(Disposables.empty());
publishNext(outerObserver, 50, Observable.unsafeCreate(new ObservableSource<String>() {
@Override
public void subscribe(Observer<? super String> innerObserver) {
innerObserver.onSubscribe(Disposables.empty());
publishNext(innerObserver, 70, "one");
publishNext(innerObserver, 100, "two");
publishCompleted(innerObserver, 200);
}
}));
publishCompleted(outerObserver, 60);
}
});
Observable<String> sampled = Observable.switchOnNext(source);
sampled.subscribe(observer);
InOrder inOrder = inOrder(observer);
scheduler.advanceTimeTo(350, TimeUnit.MILLISECONDS);
inOrder.verify(observer, times(2)).onNext(anyString());
inOrder.verify(observer, times(1)).onComplete();
}
@Test
public void testSwitchWhenInnerCompleteBeforeOuter() {
Observable<Observable<String>> source = Observable.unsafeCreate(new ObservableSource<Observable<String>>() {
@Override
public void subscribe(Observer<? super Observable<String>> outerObserver) {
outerObserver.onSubscribe(Disposables.empty());
publishNext(outerObserver, 10, Observable.unsafeCreate(new ObservableSource<String>() {
@Override
public void subscribe(Observer<? super String> innerObserver) {
innerObserver.onSubscribe(Disposables.empty());
publishNext(innerObserver, 0, "one");
publishNext(innerObserver, 10, "two");
publishCompleted(innerObserver, 20);
}
}));
publishNext(outerObserver, 100, Observable.unsafeCreate(new ObservableSource<String>() {
@Override
public void subscribe(Observer<? super String> innerObserver) {
innerObserver.onSubscribe(Disposables.empty());
publishNext(innerObserver, 0, "three");
publishNext(innerObserver, 10, "four");
publishCompleted(innerObserver, 20);
}
}));
publishCompleted(outerObserver, 200);
}
});
Observable<String> sampled = Observable.switchOnNext(source);
sampled.subscribe(observer);
InOrder inOrder = inOrder(observer);
scheduler.advanceTimeTo(150, TimeUnit.MILLISECONDS);
inOrder.verify(observer, never()).onComplete();
inOrder.verify(observer, times(1)).onNext("one");
inOrder.verify(observer, times(1)).onNext("two");
inOrder.verify(observer, times(1)).onNext("three");
inOrder.verify(observer, times(1)).onNext("four");
scheduler.advanceTimeTo(250, TimeUnit.MILLISECONDS);
inOrder.verify(observer, never()).onNext(anyString());
inOrder.verify(observer, times(1)).onComplete();
}
@Test
public void testSwitchWithComplete() {
Observable<Observable<String>> source = Observable.unsafeCreate(new ObservableSource<Observable<String>>() {
@Override
public void subscribe(Observer<? super Observable<String>> outerObserver) {
outerObserver.onSubscribe(Disposables.empty());
publishNext(outerObserver, 50, Observable.unsafeCreate(new ObservableSource<String>() {
@Override
public void subscribe(final Observer<? super String> innerObserver) {
innerObserver.onSubscribe(Disposables.empty());
publishNext(innerObserver, 60, "one");
publishNext(innerObserver, 100, "two");
}
}));
publishNext(outerObserver, 200, Observable.unsafeCreate(new ObservableSource<String>() {
@Override
public void subscribe(final Observer<? super String> innerObserver) {
innerObserver.onSubscribe(Disposables.empty());
publishNext(innerObserver, 0, "three");
publishNext(innerObserver, 100, "four");
}
}));
publishCompleted(outerObserver, 250);
}
});
Observable<String> sampled = Observable.switchOnNext(source);
sampled.subscribe(observer);
InOrder inOrder = inOrder(observer);
scheduler.advanceTimeTo(90, TimeUnit.MILLISECONDS);
inOrder.verify(observer, never()).onNext(anyString());
verify(observer, never()).onComplete();
verify(observer, never()).onError(any(Throwable.class));
scheduler.advanceTimeTo(125, TimeUnit.MILLISECONDS);
inOrder.verify(observer, times(1)).onNext("one");
verify(observer, never()).onComplete();
verify(observer, never()).onError(any(Throwable.class));
scheduler.advanceTimeTo(175, TimeUnit.MILLISECONDS);
inOrder.verify(observer, times(1)).onNext("two");
verify(observer, never()).onComplete();
verify(observer, never()).onError(any(Throwable.class));
scheduler.advanceTimeTo(225, TimeUnit.MILLISECONDS);
inOrder.verify(observer, times(1)).onNext("three");
verify(observer, never()).onComplete();
verify(observer, never()).onError(any(Throwable.class));
scheduler.advanceTimeTo(350, TimeUnit.MILLISECONDS);
inOrder.verify(observer, times(1)).onNext("four");
verify(observer, never()).onComplete();
verify(observer, never()).onError(any(Throwable.class));
}
@Test
public void testSwitchWithError() {
Observable<Observable<String>> source = Observable.unsafeCreate(new ObservableSource<Observable<String>>() {
@Override
public void subscribe(Observer<? super Observable<String>> outerObserver) {
outerObserver.onSubscribe(Disposables.empty());
publishNext(outerObserver, 50, Observable.unsafeCreate(new ObservableSource<String>() {
@Override
public void subscribe(final Observer<? super String> innerObserver) {
innerObserver.onSubscribe(Disposables.empty());
publishNext(innerObserver, 50, "one");
publishNext(innerObserver, 100, "two");
}
}));
publishNext(outerObserver, 200, Observable.unsafeCreate(new ObservableSource<String>() {
@Override
public void subscribe(Observer<? super String> innerObserver) {
innerObserver.onSubscribe(Disposables.empty());
publishNext(innerObserver, 0, "three");
publishNext(innerObserver, 100, "four");
}
}));
publishError(outerObserver, 250, new TestException());
}
});
Observable<String> sampled = Observable.switchOnNext(source);
sampled.subscribe(observer);
InOrder inOrder = inOrder(observer);
scheduler.advanceTimeTo(90, TimeUnit.MILLISECONDS);
inOrder.verify(observer, never()).onNext(anyString());
verify(observer, never()).onComplete();
verify(observer, never()).onError(any(Throwable.class));
scheduler.advanceTimeTo(125, TimeUnit.MILLISECONDS);
inOrder.verify(observer, times(1)).onNext("one");
verify(observer, never()).onComplete();
verify(observer, never()).onError(any(Throwable.class));
scheduler.advanceTimeTo(175, TimeUnit.MILLISECONDS);
inOrder.verify(observer, times(1)).onNext("two");
verify(observer, never()).onComplete();
verify(observer, never()).onError(any(Throwable.class));
scheduler.advanceTimeTo(225, TimeUnit.MILLISECONDS);
inOrder.verify(observer, times(1)).onNext("three");
verify(observer, never()).onComplete();
verify(observer, never()).onError(any(Throwable.class));
scheduler.advanceTimeTo(350, TimeUnit.MILLISECONDS);
inOrder.verify(observer, never()).onNext(anyString());
verify(observer, never()).onComplete();
verify(observer, times(1)).onError(any(TestException.class));
}
@Test
public void testSwitchWithSubsequenceComplete() {
Observable<Observable<String>> source = Observable.unsafeCreate(new ObservableSource<Observable<String>>() {
@Override
public void subscribe(Observer<? super Observable<String>> outerObserver) {
outerObserver.onSubscribe(Disposables.empty());
publishNext(outerObserver, 50, Observable.unsafeCreate(new ObservableSource<String>() {
@Override
public void subscribe(Observer<? super String> innerObserver) {
innerObserver.onSubscribe(Disposables.empty());
publishNext(innerObserver, 50, "one");
publishNext(innerObserver, 100, "two");
}
}));
publishNext(outerObserver, 130, Observable.unsafeCreate(new ObservableSource<String>() {
@Override
public void subscribe(Observer<? super String> innerObserver) {
innerObserver.onSubscribe(Disposables.empty());
publishCompleted(innerObserver, 0);
}
}));
publishNext(outerObserver, 150, Observable.unsafeCreate(new ObservableSource<String>() {
@Override
public void subscribe(Observer<? super String> innerObserver) {
innerObserver.onSubscribe(Disposables.empty());
publishNext(innerObserver, 50, "three");
}
}));
}
});
Observable<String> sampled = Observable.switchOnNext(source);
sampled.subscribe(observer);
InOrder inOrder = inOrder(observer);
scheduler.advanceTimeTo(90, TimeUnit.MILLISECONDS);
inOrder.verify(observer, never()).onNext(anyString());
verify(observer, never()).onComplete();
verify(observer, never()).onError(any(Throwable.class));
scheduler.advanceTimeTo(125, TimeUnit.MILLISECONDS);
inOrder.verify(observer, times(1)).onNext("one");
verify(observer, never()).onComplete();
verify(observer, never()).onError(any(Throwable.class));
scheduler.advanceTimeTo(250, TimeUnit.MILLISECONDS);
inOrder.verify(observer, times(1)).onNext("three");
verify(observer, never()).onComplete();
verify(observer, never()).onError(any(Throwable.class));
}
@Test
public void testSwitchWithSubsequenceError() {
Observable<Observable<String>> source = Observable.unsafeCreate(new ObservableSource<Observable<String>>() {
@Override
public void subscribe(Observer<? super Observable<String>> observer) {
observer.onSubscribe(Disposables.empty());
publishNext(observer, 50, Observable.unsafeCreate(new ObservableSource<String>() {
@Override
public void subscribe(Observer<? super String> observer) {
observer.onSubscribe(Disposables.empty());
publishNext(observer, 50, "one");
publishNext(observer, 100, "two");
}
}));
publishNext(observer, 130, Observable.unsafeCreate(new ObservableSource<String>() {
@Override
public void subscribe(Observer<? super String> observer) {
observer.onSubscribe(Disposables.empty());
publishError(observer, 0, new TestException());
}
}));
publishNext(observer, 150, Observable.unsafeCreate(new ObservableSource<String>() {
@Override
public void subscribe(Observer<? super String> observer) {
observer.onSubscribe(Disposables.empty());
publishNext(observer, 50, "three");
}
}));
}
});
Observable<String> sampled = Observable.switchOnNext(source);
sampled.subscribe(observer);
InOrder inOrder = inOrder(observer);
scheduler.advanceTimeTo(90, TimeUnit.MILLISECONDS);
inOrder.verify(observer, never()).onNext(anyString());
verify(observer, never()).onComplete();
verify(observer, never()).onError(any(Throwable.class));
scheduler.advanceTimeTo(125, TimeUnit.MILLISECONDS);
inOrder.verify(observer, times(1)).onNext("one");
verify(observer, never()).onComplete();
verify(observer, never()).onError(any(Throwable.class));
scheduler.advanceTimeTo(250, TimeUnit.MILLISECONDS);
inOrder.verify(observer, never()).onNext("three");
verify(observer, never()).onComplete();
verify(observer, times(1)).onError(any(TestException.class));
}
private <T> void publishCompleted(final Observer<T> observer, long delay) {
innerScheduler.schedule(new Runnable() {
@Override
public void run() {
observer.onComplete();
}
}, delay, TimeUnit.MILLISECONDS);
}
private <T> void publishError(final Observer<T> observer, long delay, final Throwable error) {
innerScheduler.schedule(new Runnable() {
@Override
public void run() {
observer.onError(error);
}
}, delay, TimeUnit.MILLISECONDS);
}
private <T> void publishNext(final Observer<T> observer, long delay, final T value) {
innerScheduler.schedule(new Runnable() {
@Override
public void run() {
observer.onNext(value);
}
}, delay, TimeUnit.MILLISECONDS);
}
@Test
public void testSwitchIssue737() {
// https://github.com/ReactiveX/RxJava/issues/737
Observable<Observable<String>> source = Observable.unsafeCreate(new ObservableSource<Observable<String>>() {
@Override
public void subscribe(Observer<? super Observable<String>> outerObserver) {
outerObserver.onSubscribe(Disposables.empty());
publishNext(outerObserver, 0, Observable.unsafeCreate(new ObservableSource<String>() {
@Override
public void subscribe(Observer<? super String> innerObserver) {
innerObserver.onSubscribe(Disposables.empty());
publishNext(innerObserver, 10, "1-one");
publishNext(innerObserver, 20, "1-two");
// The following events will be ignored
publishNext(innerObserver, 30, "1-three");
publishCompleted(innerObserver, 40);
}
}));
publishNext(outerObserver, 25, Observable.unsafeCreate(new ObservableSource<String>() {
@Override
public void subscribe(Observer<? super String> innerObserver) {
innerObserver.onSubscribe(Disposables.empty());
publishNext(innerObserver, 10, "2-one");
publishNext(innerObserver, 20, "2-two");
publishNext(innerObserver, 30, "2-three");
publishCompleted(innerObserver, 40);
}
}));
publishCompleted(outerObserver, 30);
}
});
Observable<String> sampled = Observable.switchOnNext(source);
sampled.subscribe(observer);
scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS);
InOrder inOrder = inOrder(observer);
inOrder.verify(observer, times(1)).onNext("1-one");
inOrder.verify(observer, times(1)).onNext("1-two");
inOrder.verify(observer, times(1)).onNext("2-one");
inOrder.verify(observer, times(1)).onNext("2-two");
inOrder.verify(observer, times(1)).onNext("2-three");
inOrder.verify(observer, times(1)).onComplete();
inOrder.verifyNoMoreInteractions();
}
@Test
public void testUnsubscribe() {
final AtomicBoolean isUnsubscribed = new AtomicBoolean();
Observable.switchOnNext(
Observable.unsafeCreate(new ObservableSource<Observable<Integer>>() {
@Override
public void subscribe(final Observer<? super Observable<Integer>> observer) {
Disposable bs = Disposables.empty();
observer.onSubscribe(bs);
observer.onNext(Observable.just(1));
isUnsubscribed.set(bs.isDisposed());
}
})
).take(1).subscribe();
assertTrue("Switch doesn't propagate 'unsubscribe'", isUnsubscribed.get());
}
/** The upstream producer hijacked the switch producer stopping the requests aimed at the inner observables. */
@Test
public void testIssue2654() {
Observable<String> oneItem = Observable.just("Hello").mergeWith(Observable.<String>never());
Observable<String> src = oneItem.switchMap(new Function<String, Observable<String>>() {
@Override
public Observable<String> apply(final String s) {
return Observable.just(s)
.mergeWith(Observable.interval(10, TimeUnit.MILLISECONDS)
.map(new Function<Long, String>() {
@Override
public String apply(Long i) {
return s + " " + i;
}
})).take(250);
}
})
.share()
;
TestObserver<String> ts = new TestObserver<String>() {
@Override
public void onNext(String t) {
super.onNext(t);
if (valueCount() == 250) {
onComplete();
dispose();
}
}
};
src.subscribe(ts);
ts.awaitTerminalEvent(10, TimeUnit.SECONDS);
System.out.println("> testIssue2654: " + ts.valueCount());
ts.assertTerminated();
ts.assertNoErrors();
Assert.assertEquals(250, ts.valueCount());
}
@Test
public void delayErrors() {
PublishSubject<ObservableSource<Integer>> source = PublishSubject.create();
TestObserver<Integer> ts = source.switchMapDelayError(Functions.<ObservableSource<Integer>>identity())
.test();
ts.assertNoValues()
.assertNoErrors()
.assertNotComplete();
source.onNext(Observable.just(1));
source.onNext(Observable.<Integer>error(new TestException("Forced failure 1")));
source.onNext(Observable.just(2, 3, 4));
source.onNext(Observable.<Integer>error(new TestException("Forced failure 2")));
source.onNext(Observable.just(5));
source.onError(new TestException("Forced failure 3"));
ts.assertValues(1, 2, 3, 4, 5)
.assertNotComplete()
.assertError(CompositeException.class);
List<Throwable> errors = ExceptionHelper.flatten(ts.errors().get(0));
TestHelper.assertError(errors, 0, TestException.class, "Forced failure 1");
TestHelper.assertError(errors, 1, TestException.class, "Forced failure 2");
TestHelper.assertError(errors, 2, TestException.class, "Forced failure 3");
}
@Test
public void switchOnNextDelayError() {
PublishSubject<Observable<Integer>> ps = PublishSubject.create();
TestObserver<Integer> ts = Observable.switchOnNextDelayError(ps).test();
ps.onNext(Observable.just(1));
ps.onNext(Observable.range(2, 4));
ps.onComplete();
ts.assertResult(1, 2, 3, 4, 5);
}
@Test
public void switchOnNextDelayErrorWithError() {
PublishSubject<Observable<Integer>> ps = PublishSubject.create();
TestObserver<Integer> ts = Observable.switchOnNextDelayError(ps).test();
ps.onNext(Observable.just(1));
ps.onNext(Observable.<Integer>error(new TestException()));
ps.onNext(Observable.range(2, 4));
ps.onComplete();
ts.assertFailure(TestException.class, 1, 2, 3, 4, 5);
}
@Test
public void switchOnNextDelayErrorBufferSize() {
PublishSubject<Observable<Integer>> ps = PublishSubject.create();
TestObserver<Integer> ts = Observable.switchOnNextDelayError(ps, 2).test();
ps.onNext(Observable.just(1));
ps.onNext(Observable.range(2, 4));
ps.onComplete();
ts.assertResult(1, 2, 3, 4, 5);
}
@Test
public void switchMapDelayErrorEmptySource() {
assertSame(Observable.empty(), Observable.<Object>empty()
.switchMapDelayError(new Function<Object, ObservableSource<Integer>>() {
@Override
public ObservableSource<Integer> apply(Object v) throws Exception {
return Observable.just(1);
}
}, 16));
}
@Test
public void switchMapDelayErrorJustSource() {
Observable.just(0)
.switchMapDelayError(new Function<Object, ObservableSource<Integer>>() {
@Override
public ObservableSource<Integer> apply(Object v) throws Exception {
return Observable.just(1);
}
}, 16)
.test()
.assertResult(1);
}
@Test
public void switchMapErrorEmptySource() {
assertSame(Observable.empty(), Observable.<Object>empty()
.switchMap(new Function<Object, ObservableSource<Integer>>() {
@Override
public ObservableSource<Integer> apply(Object v) throws Exception {
return Observable.just(1);
}
}, 16));
}
@Test
public void switchMapJustSource() {
Observable.just(0)
.switchMap(new Function<Object, ObservableSource<Integer>>() {
@Override
public ObservableSource<Integer> apply(Object v) throws Exception {
return Observable.just(1);
}
}, 16)
.test()
.assertResult(1);
}
@Test
public void switchMapInnerCancelled() {
PublishSubject<Integer> pp = PublishSubject.create();
TestObserver<Integer> ts = Observable.just(1)
.switchMap(Functions.justFunction(pp))
.test();
assertTrue(pp.hasObservers());
ts.cancel();
assertFalse(pp.hasObservers());
}
@Test
public void switchMapSingleJustSource() {
Observable.just(0)
.switchMapSingle(new Function<Object, SingleSource<Integer>>() {
@Override
public SingleSource<Integer> apply(Object v) throws Exception {
return Single.just(1);
}
})
.test()
.assertResult(1);
}
@Test
public void switchMapSingleMapperReturnsNull() {
Observable.just(0)
.switchMapSingle(new Function<Object, SingleSource<Integer>>() {
@Override
public SingleSource<Integer> apply(Object v) throws Exception {
return null;
}
})
.test()
.assertError(NullPointerException.class);
}
@Test(expected = NullPointerException.class)
public void switchMapSingleMapperIsNull() {
Observable.just(0)
.switchMapSingle(null);
}
@Test
public void switchMapSingleFunctionDoesntReturnSingle() {
Observable.just(0)
.switchMapSingle(new Function<Object, SingleSource<Integer>>() {
@Override
public SingleSource<Integer> apply(Object v) throws Exception {
return new SingleSource<Integer>() {
@Override
public void subscribe(SingleObserver<? super Integer> s) {
s.onSubscribe(Disposables.empty());
s.onSuccess(1);
}
};
}
})
.test()
.assertResult(1);
}
@Test
public void switchMapSingleDelayErrorJustSource() {
final AtomicBoolean completed = new AtomicBoolean();
Observable.just(0, 1)
.switchMapSingleDelayError(new Function<Integer, SingleSource<Integer>>() {
@Override
public SingleSource<Integer> apply(Integer v) throws Exception {
if (v == 0) {
return Single.error(new RuntimeException());
} else {
return Single.just(1).doOnSuccess(new Consumer<Integer>() {
@Override
public void accept(Integer n) throws Exception {
completed.set(true);
}});
}
}
})
.test()
.assertValue(1)
.assertError(RuntimeException.class);
assertTrue(completed.get());
}
@Test
public void scalarMap() {
Observable.switchOnNext(Observable.just(Observable.just(1)))
.test()
.assertResult(1);
}
@Test
public void scalarMapDelayError() {
Observable.switchOnNextDelayError(Observable.just(Observable.just(1)))
.test()
.assertResult(1);
}
@Test
public void dispose() {
TestHelper.checkDisposed(Observable.switchOnNext(
Observable.just(Observable.just(1)).hide()));
}
@Test
public void nextSourceErrorRace() {
for (int i = 0; i < 500; i++) {
List<Throwable> errors = TestHelper.trackPluginErrors();
try {
final PublishSubject<Integer> ps1 = PublishSubject.create();
final PublishSubject<Integer> ps2 = PublishSubject.create();
ps1.switchMap(new Function<Integer, ObservableSource<Integer>>() {
@Override
public ObservableSource<Integer> apply(Integer v) throws Exception {
if (v == 1) {
return ps2;
}
return Observable.never();
}
})
.test();
Runnable r1 = new Runnable() {
@Override
public void run() {
ps1.onNext(2);
}
};
final TestException ex = new TestException();
Runnable r2 = new Runnable() {
@Override
public void run() {
ps2.onError(ex);
}
};
TestHelper.race(r1, r2);
for (Throwable e : errors) {
assertTrue(e.toString(), e instanceof TestException);
}
} finally {
RxJavaPlugins.reset();
}
}
}
@Test
public void outerInnerErrorRace() {
for (int i = 0; i < 500; i++) {
List<Throwable> errors = TestHelper.trackPluginErrors();
try {
final PublishSubject<Integer> ps1 = PublishSubject.create();
final PublishSubject<Integer> ps2 = PublishSubject.create();
ps1.switchMap(new Function<Integer, ObservableSource<Integer>>() {
@Override
public ObservableSource<Integer> apply(Integer v) throws Exception {
if (v == 1) {
return ps2;
}
return Observable.never();
}
})
.test();
final TestException ex1 = new TestException();
Runnable r1 = new Runnable() {
@Override
public void run() {
ps1.onError(ex1);
}
};
final TestException ex2 = new TestException();
Runnable r2 = new Runnable() {
@Override
public void run() {
ps2.onError(ex2);
}
};
TestHelper.race(r1, r2);
for (Throwable e : errors) {
assertTrue(e.toString(), e instanceof TestException);
}
} finally {
RxJavaPlugins.reset();
}
}
}
@Test
public void nextCancelRace() {
for (int i = 0; i < 500; i++) {
final PublishSubject<Integer> ps1 = PublishSubject.create();
final TestObserver<Integer> to = ps1.switchMap(new Function<Integer, ObservableSource<Integer>>() {
@Override
public ObservableSource<Integer> apply(Integer v) throws Exception {
return Observable.never();
}
})
.test();
Runnable r1 = new Runnable() {
@Override
public void run() {
ps1.onNext(2);
}
};
Runnable r2 = new Runnable() {
@Override
public void run() {
to.cancel();
}
};
TestHelper.race(r1, r2);
}
}
@Test
public void mapperThrows() {
Observable.just(1).hide()
.switchMap(new Function<Integer, ObservableSource<Object>>() {
@Override
public ObservableSource<Object> apply(Integer v) throws Exception {
throw new TestException();
}
})
.test()
.assertFailure(TestException.class);
}
@Test
public void badMainSource() {
List<Throwable> errors = TestHelper.trackPluginErrors();
try {
new Observable<Integer>() {
@Override
protected void subscribeActual(Observer<? super Integer> observer) {
observer.onSubscribe(Disposables.empty());
observer.onComplete();
observer.onError(new TestException());
observer.onComplete();
}
}
.switchMap(Functions.justFunction(Observable.never()))
.test()
.assertResult();
TestHelper.assertUndeliverable(errors, 0, TestException.class);
} finally {
RxJavaPlugins.reset();
}
}
@Test
public void emptyInner() {
Observable.range(1, 5)
.switchMap(Functions.justFunction(Observable.empty()))
.test()
.assertResult();
}
@Test
public void justInner() {
Observable.range(1, 5)
.switchMap(Functions.justFunction(Observable.just(1)))
.test()
.assertResult(1, 1, 1, 1, 1);
}
@Test
public void badInnerSource() {
List<Throwable> errors = TestHelper.trackPluginErrors();
try {
Observable.just(1).hide()
.switchMap(Functions.justFunction(new Observable<Integer>() {
@Override
protected void subscribeActual(Observer<? super Integer> observer) {
observer.onSubscribe(Disposables.empty());
observer.onError(new TestException());
observer.onComplete();
observer.onError(new TestException());
observer.onComplete();
}
}))
.test()
.assertFailure(TestException.class);
TestHelper.assertUndeliverable(errors, 0, TestException.class);
} finally {
RxJavaPlugins.reset();
}
}
@Test
public void innerCompletesReentrant() {
final PublishSubject<Integer> ps = PublishSubject.create();
TestObserver<Integer> to = new TestObserver<Integer>() {
@Override
public void onNext(Integer t) {
super.onNext(t);
ps.onComplete();
}
};
Observable.just(1).hide()
.switchMap(Functions.justFunction(ps))
.subscribe(to);
ps.onNext(1);
to.assertResult(1);
}
@Test
public void innerErrorsReentrant() {
final PublishSubject<Integer> ps = PublishSubject.create();
TestObserver<Integer> to = new TestObserver<Integer>() {
@Override
public void onNext(Integer t) {
super.onNext(t);
ps.onError(new TestException());
}
};
Observable.just(1).hide()
.switchMap(Functions.justFunction(ps))
.subscribe(to);
ps.onNext(1);
to.assertFailure(TestException.class, 1);
}
}