/** * 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.single; import static org.junit.Assert.*; import java.util.List; import java.util.concurrent.Callable; import org.junit.Test; import io.reactivex.*; import io.reactivex.disposables.*; import io.reactivex.exceptions.*; import io.reactivex.functions.*; import io.reactivex.internal.functions.Functions; import io.reactivex.observers.TestObserver; import io.reactivex.plugins.RxJavaPlugins; import io.reactivex.processors.PublishProcessor; import io.reactivex.schedulers.Schedulers; public class SingleUsingTest { Function<Disposable, Single<Integer>> mapper = new Function<Disposable, Single<Integer>>() { @Override public Single<Integer> apply(Disposable d) throws Exception { return Single.just(1); } }; Function<Disposable, Single<Integer>> mapperThrows = new Function<Disposable, Single<Integer>>() { @Override public Single<Integer> apply(Disposable d) throws Exception { throw new TestException("Mapper"); } }; Consumer<Disposable> disposer = new Consumer<Disposable>() { @Override public void accept(Disposable d) throws Exception { d.dispose(); } }; Consumer<Disposable> disposerThrows = new Consumer<Disposable>() { @Override public void accept(Disposable d) throws Exception { throw new TestException("Disposer"); } }; @Test public void resourceSupplierThrows() { Single.using(new Callable<Integer>() { @Override public Integer call() throws Exception { throw new TestException(); } }, Functions.justFunction(Single.just(1)), Functions.emptyConsumer()) .test() .assertFailure(TestException.class); } @Test public void normalEager() { Single.using(Functions.justCallable(1), Functions.justFunction(Single.just(1)), Functions.emptyConsumer()) .test() .assertResult(1); } @Test public void normalNonEager() { Single.using(Functions.justCallable(1), Functions.justFunction(Single.just(1)), Functions.emptyConsumer(), false) .test() .assertResult(1); } @Test public void errorEager() { Single.using(Functions.justCallable(1), Functions.justFunction(Single.error(new TestException())), Functions.emptyConsumer()) .test() .assertFailure(TestException.class); } @Test public void errorNonEager() { Single.using(Functions.justCallable(1), Functions.justFunction(Single.error(new TestException())), Functions.emptyConsumer(), false) .test() .assertFailure(TestException.class); } @Test public void eagerMapperThrowsDisposerThrows() { TestObserver<Integer> ts = Single.using(Functions.justCallable(Disposables.empty()), mapperThrows, disposerThrows) .test() .assertFailure(CompositeException.class); List<Throwable> ce = TestHelper.compositeList(ts.errors().get(0)); TestHelper.assertError(ce, 0, TestException.class, "Mapper"); TestHelper.assertError(ce, 1, TestException.class, "Disposer"); } @Test public void noneagerMapperThrowsDisposerThrows() { List<Throwable> errors = TestHelper.trackPluginErrors(); try { Single.using(Functions.justCallable(Disposables.empty()), mapperThrows, disposerThrows, false) .test() .assertFailureAndMessage(TestException.class, "Mapper"); TestHelper.assertUndeliverable(errors, 0, TestException.class, "Disposer"); } finally { RxJavaPlugins.reset(); } } @Test public void resourceDisposedIfMapperCrashes() { Disposable d = Disposables.empty(); Single.using(Functions.justCallable(d), mapperThrows, disposer) .test() .assertFailure(TestException.class); assertTrue(d.isDisposed()); } @Test public void resourceDisposedIfMapperCrashesNonEager() { Disposable d = Disposables.empty(); Single.using(Functions.justCallable(d), mapperThrows, disposer, false) .test() .assertFailure(TestException.class); assertTrue(d.isDisposed()); } @Test public void dispose() { Disposable d = Disposables.empty(); Single.using(Functions.justCallable(d), mapper, disposer, false) .test(true); assertTrue(d.isDisposed()); } @Test public void disposerThrowsEager() { Single.using(Functions.justCallable(Disposables.empty()), mapper, disposerThrows) .test() .assertFailure(TestException.class); } @Test public void disposerThrowsNonEager() { List<Throwable> errors = TestHelper.trackPluginErrors(); try { Single.using(Functions.justCallable(Disposables.empty()), mapper, disposerThrows, false) .test() .assertResult(1); TestHelper.assertUndeliverable(errors, 0, TestException.class, "Disposer"); } finally { RxJavaPlugins.reset(); } } @Test public void errorAndDisposerThrowsEager() { TestObserver<Integer> ts = Single.using(Functions.justCallable(Disposables.empty()), new Function<Disposable, SingleSource<Integer>>() { @Override public SingleSource<Integer> apply(Disposable v) throws Exception { return Single.<Integer>error(new TestException("Mapper-run")); } }, disposerThrows) .test() .assertFailure(CompositeException.class); List<Throwable> ce = TestHelper.compositeList(ts.errors().get(0)); TestHelper.assertError(ce, 0, TestException.class, "Mapper-run"); TestHelper.assertError(ce, 1, TestException.class, "Disposer"); } @Test public void errorAndDisposerThrowsNonEager() { List<Throwable> errors = TestHelper.trackPluginErrors(); try { Single.using(Functions.justCallable(Disposables.empty()), new Function<Disposable, SingleSource<Integer>>() { @Override public SingleSource<Integer> apply(Disposable v) throws Exception { return Single.<Integer>error(new TestException("Mapper-run")); } }, disposerThrows, false) .test() .assertFailure(TestException.class); TestHelper.assertUndeliverable(errors, 0, TestException.class, "Disposer"); } finally { RxJavaPlugins.reset(); } } @Test public void successDisposeRace() { for (int i = 0; i < 500; i++) { final PublishProcessor<Integer> pp = PublishProcessor.create(); Disposable d = Disposables.empty(); final TestObserver<Integer> ts = Single.using(Functions.justCallable(d), new Function<Disposable, SingleSource<Integer>>() { @Override public SingleSource<Integer> apply(Disposable v) throws Exception { return pp.single(-99); } }, disposer) .test(); pp.onNext(1); Runnable r1 = new Runnable() { @Override public void run() { pp.onComplete(); } }; Runnable r2 = new Runnable() { @Override public void run() { ts.cancel(); } }; TestHelper.race(r1, r2, Schedulers.single()); assertTrue(d.isDisposed()); } } @Test public void doubleOnSubscribe() { List<Throwable> errors = TestHelper.trackPluginErrors(); try { Single.using(Functions.justCallable(1), new Function<Integer, SingleSource<Integer>>() { @Override public SingleSource<Integer> apply(Integer v) throws Exception { return new Single<Integer>() { @Override protected void subscribeActual(SingleObserver<? super Integer> observer) { observer.onSubscribe(Disposables.empty()); assertFalse(((Disposable)observer).isDisposed()); Disposable d = Disposables.empty(); observer.onSubscribe(d); assertTrue(d.isDisposed()); assertFalse(((Disposable)observer).isDisposed()); observer.onSuccess(1); assertTrue(((Disposable)observer).isDisposed()); } }; } }, Functions.emptyConsumer()) .test() .assertResult(1) ; TestHelper.assertError(errors, 0, IllegalStateException.class, "Disposable already set!"); } finally { RxJavaPlugins.reset(); } } @Test public void errorDisposeRace() { for (int i = 0; i < 500; i++) { final PublishProcessor<Integer> pp = PublishProcessor.create(); Disposable d = Disposables.empty(); final TestObserver<Integer> ts = Single.using(Functions.justCallable(d), new Function<Disposable, SingleSource<Integer>>() { @Override public SingleSource<Integer> apply(Disposable v) throws Exception { return pp.single(-99); } }, disposer) .test(); final TestException ex = new TestException(); Runnable r1 = new Runnable() { @Override public void run() { pp.onError(ex); } }; Runnable r2 = new Runnable() { @Override public void run() { ts.cancel(); } }; TestHelper.race(r1, r2, Schedulers.single()); assertTrue(d.isDisposed()); } } }