/** * 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.observers; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import java.io.IOException; import java.util.*; import java.util.concurrent.TimeUnit; import org.junit.*; import org.junit.rules.ExpectedException; import org.mockito.InOrder; import org.reactivestreams.Subscriber; import io.reactivex.*; import io.reactivex.Observable; import io.reactivex.Observer; import io.reactivex.disposables.*; import io.reactivex.exceptions.TestException; import io.reactivex.functions.*; import io.reactivex.internal.functions.Functions; import io.reactivex.internal.fuseable.QueueDisposable; import io.reactivex.internal.operators.observable.ObservableScalarXMap.ScalarDisposable; import io.reactivex.internal.subscriptions.EmptySubscription; import io.reactivex.processors.PublishProcessor; import io.reactivex.schedulers.Schedulers; import io.reactivex.subjects.UnicastSubject; import io.reactivex.subscribers.TestSubscriber; public class TestObserverTest { @Rule public ExpectedException thrown = ExpectedException.none(); @Test public void testAssert() { Flowable<Integer> oi = Flowable.fromIterable(Arrays.asList(1, 2)); TestSubscriber<Integer> o = new TestSubscriber<Integer>(); oi.subscribe(o); o.assertValues(1, 2); o.assertValueCount(2); o.assertTerminated(); } @Test public void testAssertNotMatchCount() { Flowable<Integer> oi = Flowable.fromIterable(Arrays.asList(1, 2)); TestSubscriber<Integer> o = new TestSubscriber<Integer>(); oi.subscribe(o); thrown.expect(AssertionError.class); // FIXME different message format // thrown.expectMessage("Number of items does not match. Provided: 1 Actual: 2"); o.assertValue(1); o.assertValueCount(2); o.assertTerminated(); } @Test public void testAssertNotMatchValue() { Flowable<Integer> oi = Flowable.fromIterable(Arrays.asList(1, 2)); TestSubscriber<Integer> o = new TestSubscriber<Integer>(); oi.subscribe(o); thrown.expect(AssertionError.class); // FIXME different message format // thrown.expectMessage("Value at index: 1 expected to be [3] (Integer) but was: [2] (Integer)"); o.assertValues(1, 3); o.assertValueCount(2); o.assertTerminated(); } @Test public void assertNeverAtNotMatchingValue() { Flowable<Integer> oi = Flowable.fromIterable(Arrays.asList(1, 2)); TestSubscriber<Integer> o = new TestSubscriber<Integer>(); oi.subscribe(o); o.assertNever(3); o.assertValueCount(2); o.assertTerminated(); } @Test public void assertNeverAtMatchingValue() { Flowable<Integer> oi = Flowable.fromIterable(Arrays.asList(1, 2)); TestSubscriber<Integer> o = new TestSubscriber<Integer>(); oi.subscribe(o); o.assertValues(1, 2); thrown.expect(AssertionError.class); o.assertNever(2); o.assertValueCount(2); o.assertTerminated(); } @Test public void assertNeverAtMatchingPredicate() { TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); Flowable.just(1, 2).subscribe(ts); ts.assertValues(1, 2); thrown.expect(AssertionError.class); ts.assertNever(new Predicate<Integer>() { @Override public boolean test(final Integer o) throws Exception { return o == 1; } }); } @Test public void assertNeverAtNotMatchingPredicate() { TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); Flowable.just(2, 3).subscribe(ts); ts.assertNever(new Predicate<Integer>() { @Override public boolean test(final Integer o) throws Exception { return o == 1; } }); } @Test public void testAssertTerminalEventNotReceived() { PublishProcessor<Integer> p = PublishProcessor.create(); TestSubscriber<Integer> o = new TestSubscriber<Integer>(); p.subscribe(o); p.onNext(1); p.onNext(2); thrown.expect(AssertionError.class); // FIXME different message format // thrown.expectMessage("No terminal events received."); o.assertValues(1, 2); o.assertValueCount(2); o.assertTerminated(); } @Test public void testWrappingMock() { Flowable<Integer> oi = Flowable.fromIterable(Arrays.asList(1, 2)); Subscriber<Integer> mockObserver = TestHelper.mockSubscriber(); oi.subscribe(new TestSubscriber<Integer>(mockObserver)); InOrder inOrder = inOrder(mockObserver); inOrder.verify(mockObserver, times(1)).onNext(1); inOrder.verify(mockObserver, times(1)).onNext(2); inOrder.verify(mockObserver, times(1)).onComplete(); inOrder.verifyNoMoreInteractions(); } @Test public void testWrappingMockWhenUnsubscribeInvolved() { Flowable<Integer> oi = Flowable.fromIterable(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9)).take(2); Subscriber<Integer> mockObserver = TestHelper.mockSubscriber(); oi.subscribe(new TestSubscriber<Integer>(mockObserver)); InOrder inOrder = inOrder(mockObserver); inOrder.verify(mockObserver, times(1)).onNext(1); inOrder.verify(mockObserver, times(1)).onNext(2); inOrder.verify(mockObserver, times(1)).onComplete(); inOrder.verifyNoMoreInteractions(); } @Test public void testErrorSwallowed() { Flowable.error(new RuntimeException()).subscribe(new TestSubscriber<Object>()); } @Test public void testGetEvents() { TestSubscriber<Integer> to = new TestSubscriber<Integer>(); to.onSubscribe(EmptySubscription.INSTANCE); to.onNext(1); to.onNext(2); assertEquals(Arrays.<Object>asList(Arrays.asList(1, 2), Collections.emptyList(), Collections.emptyList()), to.getEvents()); to.onComplete(); assertEquals(Arrays.<Object>asList(Arrays.asList(1, 2), Collections.emptyList(), Collections.singletonList(Notification.createOnComplete())), to.getEvents()); TestException ex = new TestException(); TestSubscriber<Integer> to2 = new TestSubscriber<Integer>(); to2.onSubscribe(EmptySubscription.INSTANCE); to2.onNext(1); to2.onNext(2); assertEquals(Arrays.<Object>asList(Arrays.asList(1, 2), Collections.emptyList(), Collections.emptyList()), to2.getEvents()); to2.onError(ex); assertEquals(Arrays.<Object>asList( Arrays.asList(1, 2), Collections.singletonList(ex), Collections.emptyList()), to2.getEvents()); } @Test public void testNullExpected() { TestSubscriber<Integer> to = new TestSubscriber<Integer>(); to.onNext(1); try { to.assertValue((Integer) null); } catch (AssertionError ex) { // this is expected return; } fail("Null element check assertion didn't happen!"); } @Test public void testNullActual() { TestSubscriber<Integer> to = new TestSubscriber<Integer>(); to.onNext(null); try { to.assertValue(1); } catch (AssertionError ex) { // this is expected return; } fail("Null element check assertion didn't happen!"); } @Test public void testTerminalErrorOnce() { TestSubscriber<Integer> to = new TestSubscriber<Integer>(); to.onError(new TestException()); to.onError(new TestException()); try { to.assertTerminated(); } catch (AssertionError ex) { // this is expected return; } fail("Failed to report multiple onError terminal events!"); } @Test public void testTerminalCompletedOnce() { TestSubscriber<Integer> to = new TestSubscriber<Integer>(); to.onComplete(); to.onComplete(); try { to.assertTerminated(); } catch (AssertionError ex) { // this is expected return; } fail("Failed to report multiple onComplete terminal events!"); } @Test public void testTerminalOneKind() { TestSubscriber<Integer> to = new TestSubscriber<Integer>(); to.onError(new TestException()); to.onComplete(); try { to.assertTerminated(); } catch (AssertionError ex) { // this is expected return; } fail("Failed to report multiple kinds of events!"); } @Test public void createDelegate() { TestObserver<Integer> ts1 = TestObserver.create(); TestObserver<Integer> ts = TestObserver.create(ts1); ts.assertNotSubscribed(); assertFalse(ts.hasSubscription()); ts.onSubscribe(Disposables.empty()); try { ts.assertNotSubscribed(); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } assertTrue(ts.hasSubscription()); assertFalse(ts.isDisposed()); ts.onNext(1); ts.onError(new TestException()); ts.onComplete(); ts1.assertValue(1).assertError(TestException.class).assertComplete(); ts.dispose(); assertTrue(ts.isDisposed()); assertTrue(ts.isTerminated()); assertSame(Thread.currentThread(), ts.lastThread()); try { ts.assertNoValues(); throw new RuntimeException("Should have thrown"); } catch (AssertionError exc) { // expected } try { ts.assertValueCount(0); throw new RuntimeException("Should have thrown"); } catch (AssertionError exc) { // expected } ts.assertValueSequence(Collections.singletonList(1)); try { ts.assertValueSequence(Collections.singletonList(2)); throw new RuntimeException("Should have thrown"); } catch (AssertionError exc) { // expected } ts.assertValueSet(Collections.singleton(1)); try { ts.assertValueSet(Collections.singleton(2)); throw new RuntimeException("Should have thrown"); } catch (AssertionError exc) { // expected } } @Test public void assertError() { TestObserver<Integer> ts = TestObserver.create(); try { ts.assertError(TestException.class); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } try { ts.assertError(new TestException()); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } try { ts.assertError(Functions.<Throwable>alwaysTrue()); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } try { ts.assertErrorMessage(""); throw new RuntimeException("Should have thrown"); } catch (AssertionError exc) { // expected } try { ts.assertSubscribed(); throw new RuntimeException("Should have thrown"); } catch (AssertionError exc) { // expected } try { ts.assertTerminated(); throw new RuntimeException("Should have thrown"); } catch (AssertionError exc) { // expected } ts.onSubscribe(Disposables.empty()); ts.assertSubscribed(); ts.assertNoErrors(); TestException ex = new TestException("Forced failure"); ts.onError(ex); ts.assertError(ex); ts.assertError(TestException.class); ts.assertError(Functions.<Throwable>alwaysTrue()); ts.assertError(new Predicate<Throwable>() { @Override public boolean test(Throwable t) throws Exception { return t.getMessage() != null && t.getMessage().contains("Forced"); } }); ts.assertErrorMessage("Forced failure"); try { ts.assertErrorMessage(""); throw new RuntimeException("Should have thrown"); } catch (AssertionError exc) { // expected } try { ts.assertError(new RuntimeException()); throw new RuntimeException("Should have thrown"); } catch (AssertionError exc) { // expected } try { ts.assertError(IOException.class); throw new RuntimeException("Should have thrown"); } catch (AssertionError exc) { // expected } try { ts.assertError(Functions.<Throwable>alwaysFalse()); throw new RuntimeException("Should have thrown"); } catch (AssertionError exc) { // expected } try { ts.assertNoErrors(); throw new RuntimeException("Should have thrown"); } catch (AssertionError exc) { // expected } ts.assertTerminated(); ts.assertValueCount(0); ts.assertNoValues(); } @Test public void emptyObserverEnum() { assertEquals(1, TestObserver.EmptyObserver.values().length); assertNotNull(TestObserver.EmptyObserver.valueOf("INSTANCE")); } @Test public void valueAndClass() { assertEquals("null", TestObserver.valueAndClass(null)); assertEquals("1 (class: Integer)", TestObserver.valueAndClass(1)); } @Test public void assertFailure() { TestObserver<Integer> ts = TestObserver.create(); ts.onSubscribe(Disposables.empty()); ts.onError(new TestException("Forced failure")); ts.assertFailure(TestException.class); ts.assertFailure(Functions.<Throwable>alwaysTrue()); ts.assertFailureAndMessage(TestException.class, "Forced failure"); ts.onNext(1); ts.assertFailure(TestException.class, 1); ts.assertFailure(Functions.<Throwable>alwaysTrue(), 1); ts.assertFailureAndMessage(TestException.class, "Forced failure", 1); } @Test public void assertFuseable() { TestObserver<Integer> ts = TestObserver.create(); ts.onSubscribe(Disposables.empty()); ts.assertNotFuseable(); try { ts.assertFuseable(); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } try { ts.assertFusionMode(QueueDisposable.SYNC); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } ts = TestObserver.create(); ts.setInitialFusionMode(QueueDisposable.ANY); ts.onSubscribe(new ScalarDisposable<Integer>(ts, 1)); ts.assertFuseable(); ts.assertFusionMode(QueueDisposable.SYNC); try { ts.assertFusionMode(QueueDisposable.NONE); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } try { ts.assertNotFuseable(); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } } @Test public void assertTerminated() { TestObserver<Integer> ts = TestObserver.create(); ts.assertNotTerminated(); ts.onError(null); try { ts.assertNotTerminated(); throw new RuntimeException("Should have thrown!"); } catch (AssertionError ex) { // expected } } @Test public void assertOf() { TestObserver<Integer> ts = TestObserver.create(); ts.assertOf(new Consumer<TestObserver<Integer>>() { @Override public void accept(TestObserver<Integer> f) throws Exception { f.assertNotSubscribed(); } }); try { ts.assertOf(new Consumer<TestObserver<Integer>>() { @Override public void accept(TestObserver<Integer> f) throws Exception { f.assertSubscribed(); } }); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } try { ts.assertOf(new Consumer<TestObserver<Integer>>() { @Override public void accept(TestObserver<Integer> f) throws Exception { throw new IllegalArgumentException(); } }); throw new RuntimeException("Should have thrown"); } catch (IllegalArgumentException ex) { // expected } } @Test public void assertResult() { TestObserver<Integer> ts = TestObserver.create(); ts.onSubscribe(Disposables.empty()); ts.onComplete(); ts.assertResult(); try { ts.assertResult(1); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } ts.onNext(1); ts.assertResult(1); try { ts.assertResult(2); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } try { ts.assertResult(); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } } @Test(timeout = 5000) public void await() throws Exception { TestObserver<Integer> ts = TestObserver.create(); ts.onSubscribe(Disposables.empty()); assertFalse(ts.await(100, TimeUnit.MILLISECONDS)); ts.awaitDone(100, TimeUnit.MILLISECONDS); assertTrue(ts.isDisposed()); assertFalse(ts.awaitTerminalEvent(100, TimeUnit.MILLISECONDS)); assertEquals(0, ts.completions()); assertEquals(0, ts.errorCount()); ts.onComplete(); assertTrue(ts.await(100, TimeUnit.MILLISECONDS)); ts.await(); ts.awaitDone(5, TimeUnit.SECONDS); assertEquals(1, ts.completions()); assertEquals(0, ts.errorCount()); assertTrue(ts.awaitTerminalEvent()); final TestObserver<Integer> ts1 = TestObserver.create(); ts1.onSubscribe(Disposables.empty()); Schedulers.single().scheduleDirect(new Runnable() { @Override public void run() { ts1.onComplete(); } }, 200, TimeUnit.MILLISECONDS); ts1.await(); ts1.assertValueSet(Collections.<Integer>emptySet()); } @Test public void errors() { TestObserver<Integer> ts = TestObserver.create(); ts.onSubscribe(Disposables.empty()); assertEquals(0, ts.errors().size()); ts.onError(new TestException()); assertEquals(1, ts.errors().size()); TestHelper.assertError(ts.errors(), 0, TestException.class); } @SuppressWarnings("unchecked") @Test public void onNext() { TestObserver<Integer> ts = TestObserver.create(); ts.onSubscribe(Disposables.empty()); assertEquals(0, ts.valueCount()); assertEquals(Collections.emptyList(), ts.values()); ts.onNext(1); assertEquals(Collections.singletonList(1), ts.values()); ts.cancel(); assertTrue(ts.isCancelled()); assertTrue(ts.isDisposed()); ts.assertValue(1); assertEquals(Arrays.asList(Collections.singletonList(1), Collections.emptyList(), Collections.emptyList()), ts.getEvents()); ts.onComplete(); assertEquals(Arrays.asList(Collections.singletonList(1), Collections.emptyList(), Collections.singletonList(Notification.createOnComplete())), ts.getEvents()); } @Test public void fusionModeToString() { assertEquals("NONE", TestObserver.fusionModeToString(QueueDisposable.NONE)); assertEquals("SYNC", TestObserver.fusionModeToString(QueueDisposable.SYNC)); assertEquals("ASYNC", TestObserver.fusionModeToString(QueueDisposable.ASYNC)); assertEquals("Unknown(100)", TestObserver.fusionModeToString(100)); } @Test public void multipleTerminals() { TestObserver<Integer> ts = TestObserver.create(); ts.onSubscribe(Disposables.empty()); ts.assertNotComplete(); ts.onComplete(); try { ts.assertNotComplete(); throw new RuntimeException("Should have thrown"); } catch (Throwable ex) { // expected } ts.assertTerminated(); ts.onComplete(); try { ts.assertComplete(); throw new RuntimeException("Should have thrown"); } catch (Throwable ex) { // expected } try { ts.assertTerminated(); throw new RuntimeException("Should have thrown"); } catch (Throwable ex) { // expected } try { ts.assertNotComplete(); throw new RuntimeException("Should have thrown"); } catch (Throwable ex) { // expected } } @Test public void assertValue() { TestObserver<Integer> ts = TestObserver.create(); ts.onSubscribe(Disposables.empty()); try { ts.assertValue(1); throw new RuntimeException("Should have thrown"); } catch (Throwable ex) { // expected } ts.onNext(1); ts.assertValue(1); try { ts.assertValue(2); throw new RuntimeException("Should have thrown"); } catch (Throwable ex) { // expected } ts.onNext(2); try { ts.assertValue(1); throw new RuntimeException("Should have thrown"); } catch (Throwable ex) { // expected } } @Test public void onNextMisbehave() { TestObserver<Integer> ts = TestObserver.create(); ts.onNext(1); ts.assertError(IllegalStateException.class); ts = TestObserver.create(); ts.onSubscribe(Disposables.empty()); ts.onNext(null); ts.assertFailure(NullPointerException.class, (Integer)null); } @Test public void awaitTerminalEventInterrupt() { final TestObserver<Integer> ts = TestObserver.create(); ts.onSubscribe(Disposables.empty()); Thread.currentThread().interrupt(); ts.awaitTerminalEvent(); assertTrue(Thread.interrupted()); Thread.currentThread().interrupt(); ts.awaitTerminalEvent(5, TimeUnit.SECONDS); assertTrue(Thread.interrupted()); } @Test public void assertTerminated2() { TestObserver<Integer> ts = TestObserver.create(); ts.onSubscribe(Disposables.empty()); assertFalse(ts.isTerminated()); ts.onError(new TestException()); ts.onError(new IOException()); assertTrue(ts.isTerminated()); try { ts.assertTerminated(); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } try { ts.assertError(TestException.class); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } ts = TestObserver.create(); ts.onSubscribe(Disposables.empty()); ts.onError(new TestException()); ts.onComplete(); try { ts.assertTerminated(); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } } @Test public void onSubscribe() { TestObserver<Integer> ts = TestObserver.create(); ts.onSubscribe(null); ts.assertError(NullPointerException.class); ts = TestObserver.create(); ts.onSubscribe(Disposables.empty()); Disposable d1 = Disposables.empty(); ts.onSubscribe(d1); assertTrue(d1.isDisposed()); ts.assertError(IllegalStateException.class); ts = TestObserver.create(); ts.dispose(); d1 = Disposables.empty(); ts.onSubscribe(d1); assertTrue(d1.isDisposed()); } @Test public void assertValueSequence() { TestObserver<Integer> ts = TestObserver.create(); ts.onSubscribe(Disposables.empty()); ts.onNext(1); ts.onNext(2); try { ts.assertValueSequence(Collections.<Integer>emptyList()); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } try { ts.assertValueSequence(Collections.singletonList(1)); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } ts.assertValueSequence(Arrays.asList(1, 2)); try { ts.assertValueSequence(Arrays.asList(1, 2, 3)); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected } } @Test public void assertEmpty() { TestObserver<Integer> ts = new TestObserver<Integer>(); try { ts.assertEmpty(); throw new RuntimeException("Should have thrown!"); } catch (AssertionError ex) { // expected } ts.onSubscribe(Disposables.empty()); ts.assertEmpty(); ts.onNext(1); try { ts.assertEmpty(); throw new RuntimeException("Should have thrown!"); } catch (AssertionError ex) { // expected } } @Test public void awaitDoneTimed() { TestObserver<Integer> ts = new TestObserver<Integer>(); Thread.currentThread().interrupt(); try { ts.awaitDone(5, TimeUnit.SECONDS); } catch (RuntimeException ex) { assertTrue(ex.toString(), ex.getCause() instanceof InterruptedException); } } @Test public void assertNotSubscribed() { TestObserver<Integer> ts = new TestObserver<Integer>(); ts.assertNotSubscribed(); ts.errors().add(new TestException()); try { ts.assertNotSubscribed(); throw new RuntimeException("Should have thrown!"); } catch (AssertionError ex) { // expected } } @Test public void assertErrorMultiple() { TestObserver<Integer> ts = new TestObserver<Integer>(); TestException e = new TestException(); ts.errors().add(e); ts.errors().add(new TestException()); try { ts.assertError(TestException.class); throw new RuntimeException("Should have thrown!"); } catch (AssertionError ex) { // expected } try { ts.assertError(e); throw new RuntimeException("Should have thrown!"); } catch (AssertionError ex) { // expected } try { ts.assertError(Functions.<Throwable>alwaysTrue()); throw new RuntimeException("Should have thrown!"); } catch (AssertionError ex) { // expected } try { ts.assertErrorMessage(""); throw new RuntimeException("Should have thrown!"); } catch (AssertionError ex) { // expected } } @Test public void testErrorInPredicate() { TestObserver<Object> ts = new TestObserver<Object>(); ts.onError(new RuntimeException()); try { ts.assertError(new Predicate<Throwable>() { @Override public boolean test(Throwable throwable) throws Exception { throw new TestException(); } }); } catch (TestException ex) { // expected return; } fail("Error in predicate but not thrown!"); } @Test public void assertComplete() { TestObserver<Integer> ts = new TestObserver<Integer>(); ts.onSubscribe(Disposables.empty()); try { ts.assertComplete(); throw new RuntimeException("Should have thrown!"); } catch (AssertionError ex) { // expected } ts.onComplete(); ts.assertComplete(); ts.onComplete(); try { ts.assertComplete(); throw new RuntimeException("Should have thrown!"); } catch (AssertionError ex) { // expected } } @Test public void completeWithoutOnSubscribe() { TestObserver<Integer> ts = new TestObserver<Integer>(); ts.onComplete(); ts.assertError(IllegalStateException.class); } @Test public void completeDelegateThrows() { TestObserver<Integer> ts = new TestObserver<Integer>(new Observer<Integer>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(Integer value) { } @Override public void onError(Throwable e) { throw new TestException(); } @Override public void onComplete() { throw new TestException(); } }); ts.onSubscribe(Disposables.empty()); try { ts.onComplete(); throw new RuntimeException("Should have thrown!"); } catch (TestException ex) { assertTrue(ts.isTerminated()); } } @Test public void errorDelegateThrows() { TestObserver<Integer> ts = new TestObserver<Integer>(new Observer<Integer>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(Integer value) { } @Override public void onError(Throwable e) { throw new TestException(); } @Override public void onComplete() { throw new TestException(); } }); ts.onSubscribe(Disposables.empty()); try { ts.onError(new IOException()); throw new RuntimeException("Should have thrown!"); } catch (TestException ex) { assertTrue(ts.isTerminated()); } } @Test public void syncQueueThrows() { TestObserver<Object> ts = new TestObserver<Object>(); ts.setInitialFusionMode(QueueDisposable.SYNC); Observable.range(1, 5) .map(new Function<Integer, Object>() { @Override public Object apply(Integer v) throws Exception { throw new TestException(); } }) .subscribe(ts); ts.assertSubscribed() .assertFuseable() .assertFusionMode(QueueDisposable.SYNC) .assertFailure(TestException.class); } @Test public void asyncQueueThrows() { TestObserver<Object> ts = new TestObserver<Object>(); ts.setInitialFusionMode(QueueDisposable.ANY); UnicastSubject<Integer> up = UnicastSubject.create(); up .map(new Function<Integer, Object>() { @Override public Object apply(Integer v) throws Exception { throw new TestException(); } }) .subscribe(ts); up.onNext(1); ts.assertSubscribed() .assertFuseable() .assertFusionMode(QueueDisposable.ASYNC) .assertFailure(TestException.class); } @Test public void completedMeansDisposed() { // 2.0.2 - a terminated TestObserver no longer reports isDisposed assertFalse(Observable.just(1) .test() .assertResult(1).isDisposed()); } @Test public void errorMeansDisposed() { // 2.0.2 - a terminated TestObserver no longer reports isDisposed assertFalse(Observable.error(new TestException()) .test() .assertFailure(TestException.class).isDisposed()); } @Test public void asyncFusion() { TestObserver<Object> ts = new TestObserver<Object>(); ts.setInitialFusionMode(QueueDisposable.ANY); UnicastSubject<Integer> up = UnicastSubject.create(); up .subscribe(ts); up.onNext(1); up.onComplete(); ts.assertSubscribed() .assertFuseable() .assertFusionMode(QueueDisposable.ASYNC) .assertResult(1); } @Test public void assertValuePredicateEmpty() { TestObserver<Object> ts = new TestObserver<Object>(); Observable.empty().subscribe(ts); thrown.expect(AssertionError.class); thrown.expectMessage("No values"); ts.assertValue(new Predicate<Object>() { @Override public boolean test(final Object o) throws Exception { return false; } }); } @Test public void assertValuePredicateMatch() { TestObserver<Integer> ts = new TestObserver<Integer>(); Observable.just(1).subscribe(ts); ts.assertValue(new Predicate<Integer>() { @Override public boolean test(final Integer o) throws Exception { return o == 1; } }); } @Test public void assertValuePredicateNoMatch() { TestObserver<Integer> ts = new TestObserver<Integer>(); Observable.just(1).subscribe(ts); thrown.expect(AssertionError.class); thrown.expectMessage("Value not present"); ts.assertValue(new Predicate<Integer>() { @Override public boolean test(final Integer o) throws Exception { return o != 1; } }); } @Test public void assertValuePredicateMatchButMore() { TestObserver<Integer> ts = new TestObserver<Integer>(); Observable.just(1, 2).subscribe(ts); thrown.expect(AssertionError.class); thrown.expectMessage("Value present but other values as well"); ts.assertValue(new Predicate<Integer>() { @Override public boolean test(final Integer o) throws Exception { return o == 1; } }); } @Test public void assertValueAtPredicateEmpty() { TestObserver<Object> ts = new TestObserver<Object>(); Observable.empty().subscribe(ts); thrown.expect(AssertionError.class); thrown.expectMessage("No values"); ts.assertValueAt(0, new Predicate<Object>() { @Override public boolean test(final Object o) throws Exception { return false; } }); } @Test public void assertValueAtPredicateMatch() { TestObserver<Integer> ts = new TestObserver<Integer>(); Observable.just(1, 2).subscribe(ts); ts.assertValueAt(1, new Predicate<Integer>() { @Override public boolean test(final Integer o) throws Exception { return o == 2; } }); } @Test public void assertValueAtPredicateNoMatch() { TestObserver<Integer> ts = new TestObserver<Integer>(); Observable.just(1, 2, 3).subscribe(ts); thrown.expect(AssertionError.class); thrown.expectMessage("Value not present"); ts.assertValueAt(2, new Predicate<Integer>() { @Override public boolean test(final Integer o) throws Exception { return o != 3; } }); } @Test public void assertValueAtInvalidIndex() { TestObserver<Integer> ts = new TestObserver<Integer>(); Observable.just(1, 2).subscribe(ts); thrown.expect(AssertionError.class); thrown.expectMessage("Invalid index: 2 (latch = 0, values = 2, errors = 0, completions = 1)"); ts.assertValueAt(2, new Predicate<Integer>() { @Override public boolean test(final Integer o) throws Exception { return o == 1; } }); } @Test public void withTag() { try { for (int i = 1; i < 3; i++) { Observable.just(i) .test() .withTag("testing with item=" + i) .assertResult(1) ; } fail("Should have thrown!"); } catch (AssertionError ex) { assertTrue(ex.toString(), ex.toString().contains("testing with item=2")); } } }