/** * 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.flowable; import static org.mockito.Mockito.*; import java.util.concurrent.*; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.reactivestreams.*; import io.reactivex.*; import io.reactivex.schedulers.Schedulers; import io.reactivex.subscribers.TestSubscriber; public class FlowableFromCallableTest { @SuppressWarnings("unchecked") @Test public void shouldNotInvokeFuncUntilSubscription() throws Exception { Callable<Object> func = mock(Callable.class); when(func.call()).thenReturn(new Object()); Flowable<Object> fromCallableFlowable = Flowable.fromCallable(func); verifyZeroInteractions(func); fromCallableFlowable.subscribe(); verify(func).call(); } @SuppressWarnings("unchecked") @Test public void shouldCallOnNextAndOnCompleted() throws Exception { Callable<String> func = mock(Callable.class); when(func.call()).thenReturn("test_value"); Flowable<String> fromCallableFlowable = Flowable.fromCallable(func); Subscriber<String> observer = TestHelper.mockSubscriber(); fromCallableFlowable.subscribe(observer); verify(observer).onNext("test_value"); verify(observer).onComplete(); verify(observer, never()).onError(any(Throwable.class)); } @SuppressWarnings("unchecked") @Test public void shouldCallOnError() throws Exception { Callable<Object> func = mock(Callable.class); Throwable throwable = new IllegalStateException("Test exception"); when(func.call()).thenThrow(throwable); Flowable<Object> fromCallableFlowable = Flowable.fromCallable(func); Subscriber<Object> observer = TestHelper.mockSubscriber(); fromCallableFlowable.subscribe(observer); verify(observer, never()).onNext(any()); verify(observer, never()).onComplete(); verify(observer).onError(throwable); } @SuppressWarnings("unchecked") @Test public void shouldNotDeliverResultIfSubscriberUnsubscribedBeforeEmission() throws Exception { Callable<String> func = mock(Callable.class); final CountDownLatch funcLatch = new CountDownLatch(1); final CountDownLatch observerLatch = new CountDownLatch(1); when(func.call()).thenAnswer(new Answer<String>() { @Override public String answer(InvocationOnMock invocation) throws Throwable { observerLatch.countDown(); try { funcLatch.await(); } catch (InterruptedException e) { // It's okay, unsubscription causes Thread interruption // Restoring interruption status of the Thread Thread.currentThread().interrupt(); } return "should_not_be_delivered"; } }); Flowable<String> fromCallableFlowable = Flowable.fromCallable(func); Subscriber<String> observer = TestHelper.mockSubscriber(); TestSubscriber<String> outer = new TestSubscriber<String>(observer); fromCallableFlowable .subscribeOn(Schedulers.computation()) .subscribe(outer); // Wait until func will be invoked observerLatch.await(); // Unsubscribing before emission outer.cancel(); // Emitting result funcLatch.countDown(); // func must be invoked verify(func).call(); // Observer must not be notified at all verify(observer).onSubscribe(any(Subscription.class)); verifyNoMoreInteractions(observer); } @Test public void shouldAllowToThrowCheckedException() { final Exception checkedException = new Exception("test exception"); Flowable<Object> fromCallableFlowable = Flowable.fromCallable(new Callable<Object>() { @Override public Object call() throws Exception { throw checkedException; } }); Subscriber<Object> observer = TestHelper.mockSubscriber(); fromCallableFlowable.subscribe(observer); verify(observer).onSubscribe(any(Subscription.class)); verify(observer).onError(checkedException); verifyNoMoreInteractions(observer); } }