/**
* 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);
}
}