/
githubmirror
/
RxJava
Обзор
Документация
Войти
/
githubmirror
/
RxJava
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
4.x
src/test/java/io/reactivex/rxjava4/flowable/FlowableTests.java
972 строки
31 KB
David Karnok
4.x: Streamable + takeUntil + groupBy + refactor + helpers (#8215)
05 июл 2026, 01:45
Не верифицирован
05 июл 2026, 01:45
580b39c
Код
Авторство
О чём код?
/* * 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.rxjava4.flowable; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.Flow.Subscriber; import java.util.concurrent.atomic.*; import org.junit.jupiter.api.*; import org.mockito.InOrder; import io.reactivex.rxjava4.core.*; import io.reactivex.rxjava4.disposables.Disposable; import io.reactivex.rxjava4.exceptions.*; import io.reactivex.rxjava4.functions.Predicate; import io.reactivex.rxjava4.internal.functions.Functions; import io.reactivex.rxjava4.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava4.plugins.RxJavaPlugins; import io.reactivex.rxjava4.processors.*; import io.reactivex.rxjava4.schedulers.*; import io.reactivex.rxjava4.subscribers.*; import io.reactivex.rxjava4.testsupport.*; public class FlowableTests extends RxJavaTest { Subscriber<Number> w; SingleObserver<Number> wo; MaybeObserver<Number> wm; private static final Predicate<Integer> IS_EVEN = v -> v % 2 == 0; @BeforeEach public void before() { w = TestHelper.mockSubscriber(); wo = TestHelper.mockSingleObserver(); wm = TestHelper.mockMaybeObserver(); } @Test public void fromArray() { String[] items = new String[] { "one", "two", "three" }; assertEquals((Long)3L, Flowable.fromArray(items).count().blockingGet()); assertEquals("two", Flowable.fromArray(items).skip(1).take(1).blockingSingle()); assertEquals("three", Flowable.fromArray(items).takeLast(1).blockingSingle()); } @Test public void fromIterable() { ArrayList<String> items = new ArrayList<>(); items.add("one"); items.add("two"); items.add("three"); assertEquals((Long)3L, Flowable.fromIterable(items).count().blockingGet()); assertEquals("two", Flowable.fromIterable(items).skip(1).take(1).blockingSingle()); assertEquals("three", Flowable.fromIterable(items).takeLast(1).blockingSingle()); } @Test public void fromArityArgs3() { Flowable<String> items = Flowable.just("one", "two", "three"); assertEquals((Long)3L, items.count().blockingGet()); assertEquals("two", items.skip(1).take(1).blockingSingle()); assertEquals("three", items.takeLast(1).blockingSingle()); } @Test public void fromArityArgs1() { Flowable<String> items = Flowable.just("one"); assertEquals((Long)1L, items.count().blockingGet()); assertEquals("one", items.takeLast(1).blockingSingle()); } @Test public void create() { Flowable<String> flowable = Flowable.just("one", "two", "three"); Subscriber<String> subscriber = TestHelper.mockSubscriber(); flowable.subscribe(subscriber); verify(subscriber, times(1)).onNext("one"); verify(subscriber, times(1)).onNext("two"); verify(subscriber, times(1)).onNext("three"); verify(subscriber, never()).onError(any(Throwable.class)); verify(subscriber, times(1)).onComplete(); } @Test public void countAFewItemsFlowable() { Flowable<String> flowable = Flowable.just("a", "b", "c", "d"); flowable.count().toFlowable().subscribe(w); // we should be called only once verify(w).onNext(4L); verify(w, never()).onError(any(Throwable.class)); verify(w, times(1)).onComplete(); } @Test public void countZeroItemsFlowable() { Flowable<String> flowable = Flowable.empty(); flowable.count().toFlowable().subscribe(w); // we should be called only once verify(w).onNext(0L); verify(w, never()).onError(any(Throwable.class)); verify(w, times(1)).onComplete(); } @Test public void countErrorFlowable() { Flowable<String> f = Flowable.error(RuntimeException::new); f.count().toFlowable().subscribe(w); verify(w, never()).onNext(anyInt()); verify(w, never()).onComplete(); verify(w, times(1)).onError(any(RuntimeException.class)); } @Test public void countAFewItems() { Flowable<String> flowable = Flowable.just("a", "b", "c", "d"); flowable.count().subscribe(wo); // we should be called only once verify(wo).onSuccess(4L); verify(wo, never()).onError(any(Throwable.class)); } @Test public void countZeroItems() { Flowable<String> flowable = Flowable.empty(); flowable.count().subscribe(wo); // we should be called only once verify(wo).onSuccess(0L); verify(wo, never()).onError(any(Throwable.class)); } @Test public void countError() { Flowable<String> f = Flowable.error(RuntimeException::new); f.count().subscribe(wo); verify(wo, never()).onSuccess(anyInt()); verify(wo, times(1)).onError(any(RuntimeException.class)); } @Test public void takeFirstWithPredicateOfSome() { Flowable<Integer> flowable = Flowable.just(1, 3, 5, 4, 6, 3); flowable.filter(IS_EVEN).take(1).subscribe(w); verify(w, times(1)).onNext(anyInt()); verify(w).onNext(4); verify(w, times(1)).onComplete(); verify(w, never()).onError(any(Throwable.class)); } @Test public void takeFirstWithPredicateOfNoneMatchingThePredicate() { Flowable<Integer> flowable = Flowable.just(1, 3, 5, 7, 9, 7, 5, 3, 1); flowable.filter(IS_EVEN).take(1).subscribe(w); verify(w, never()).onNext(anyInt()); verify(w, times(1)).onComplete(); verify(w, never()).onError(any(Throwable.class)); } @Test public void takeFirstOfSome() { Flowable<Integer> flowable = Flowable.just(1, 2, 3); flowable.take(1).subscribe(w); verify(w, times(1)).onNext(anyInt()); verify(w).onNext(1); verify(w, times(1)).onComplete(); verify(w, never()).onError(any(Throwable.class)); } @Test public void takeFirstOfNone() { Flowable<Integer> flowable = Flowable.empty(); flowable.take(1).subscribe(w); verify(w, never()).onNext(anyInt()); verify(w, times(1)).onComplete(); verify(w, never()).onError(any(Throwable.class)); } @Test public void firstOfNoneFlowable() { Flowable<Integer> flowable = Flowable.empty(); flowable.firstElement().toFlowable().subscribe(w); verify(w, never()).onNext(anyInt()); verify(w).onComplete(); verify(w, never()).onError(any(Throwable.class)); } @Test public void firstWithPredicateOfNoneMatchingThePredicateFlowable() { Flowable<Integer> flowable = Flowable.just(1, 3, 5, 7, 9, 7, 5, 3, 1); flowable.filter(IS_EVEN).firstElement().toFlowable().subscribe(w); verify(w, never()).onNext(anyInt()); verify(w).onComplete(); verify(w, never()).onError(any(Throwable.class)); } @Test public void firstOfNone() { Flowable<Integer> flowable = Flowable.empty(); flowable.firstElement().subscribe(wm); verify(wm, never()).onSuccess(anyInt()); verify(wm).onComplete(); verify(wm, never()).onError(isA(NoSuchElementException.class)); } @Test public void firstWithPredicateOfNoneMatchingThePredicate() { Flowable<Integer> flowable = Flowable.just(1, 3, 5, 7, 9, 7, 5, 3, 1); flowable.filter(IS_EVEN).firstElement().subscribe(wm); verify(wm, never()).onSuccess(anyInt()); verify(wm, times(1)).onComplete(); verify(wm, never()).onError(isA(NoSuchElementException.class)); } @Test public void reduce() { Flowable<Integer> flowable = Flowable.just(1, 2, 3, 4); flowable.reduce(Integer::sum) .toFlowable() .subscribe(w); // we should be called only once verify(w, times(1)).onNext(anyInt()); verify(w).onNext(10); } @Test public void reduceWithEmptyObservable() { Flowable<Integer> flowable = Flowable.range(1, 0); flowable.reduce(Integer::sum) .toFlowable() .test() .assertResult(); } /** * A reduce on an empty Observable and a seed should just pass the seed through. * * This is confirmed at https://github.com/ReactiveX/RxJava/issues/423#issuecomment-27642456 */ @Test public void reduceWithEmptyObservableAndSeed() { Flowable<Integer> flowable = Flowable.range(1, 0); int value = flowable.reduce(1, Integer::sum) .blockingGet(); assertEquals(1, value); } @Test public void reduceWithInitialValue() { Flowable<Integer> flowable = Flowable.just(1, 2, 3, 4); flowable.reduce(50, Integer::sum) .subscribe(wo); // we should be called only once verify(wo, times(1)).onSuccess(anyInt()); verify(wo).onSuccess(60); } @Test public void materializeDematerializeChaining() { Flowable<Integer> obs = Flowable.just(1); Flowable<Integer> chained = obs.materialize() .dematerialize(Functions.<Notification<Integer>>identity()); Subscriber<Integer> subscriber = TestHelper.mockSubscriber(); chained.subscribe(subscriber); verify(subscriber, times(1)).onNext(1); verify(subscriber, times(1)).onComplete(); verify(subscriber, times(0)).onError(any(Throwable.class)); } /** * The error from the user provided Observer is not handled by the subscribe method try/catch. * * It is handled by the AtomicObserver that wraps the provided Observer. * * Result: Passes (if AtomicObserver functionality exists) * @throws InterruptedException if the test is interrupted */ @Test public void customObservableWithErrorInObserverAsynchronous() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); final AtomicInteger count = new AtomicInteger(); final AtomicReference<Throwable> error = new AtomicReference<>(); // FIXME custom built??? Flowable.just("1", "2", "three", "4") .subscribeOn(Schedulers.newThread()) .safeSubscribe(new DefaultSubscriber<>() /* NFI */ { @Override public void onComplete() { System.out.println("completed"); latch.countDown(); } @Override public void onError(Throwable e) { error.set(e); System.out.println("error"); e.printStackTrace(); latch.countDown(); } @Override public void onNext(String v) { int num = Integer.parseInt(v); System.out.println(num); // doSomething(num); count.incrementAndGet(); } }); // wait for async sequence to complete latch.await(); assertEquals(2, count.get()); assertNotNull(error.get()); if (!(error.get() instanceof NumberFormatException)) { fail("It should be a NumberFormatException"); } } /** * The error from the user provided Observer is handled by the subscribe try/catch because this is synchronous. * * Result: Passes */ @Test public void customObservableWithErrorInObserverSynchronous() { final AtomicInteger count = new AtomicInteger(); final AtomicReference<Throwable> error = new AtomicReference<>(); // FIXME custom built??? Flowable.just("1", "2", "three", "4") .safeSubscribe(new DefaultSubscriber<>() /* NFI */ { @Override public void onComplete() { System.out.println("completed"); } @Override public void onError(Throwable e) { error.set(e); System.out.println("error"); e.printStackTrace(); } @Override public void onNext(String v) { int num = Integer.parseInt(v); System.out.println(num); // doSomething(num); count.incrementAndGet(); } }); assertEquals(2, count.get()); assertNotNull(error.get()); if (!(error.get() instanceof NumberFormatException)) { fail("It should be a NumberFormatException"); } } /** * The error from the user provided Observable is handled by the subscribe try/catch because this is synchronous. * * Result: Passes */ @Test public void customObservableWithErrorInObservableSynchronous() { final AtomicInteger count = new AtomicInteger(); final AtomicReference<Throwable> error = new AtomicReference<>(); // FIXME custom built??? Flowable.just("1", "2").concatWith(Flowable.<String>error(NumberFormatException::new)) .subscribe(new DefaultSubscriber<>() /* NFI */ { @Override public void onComplete() { System.out.println("completed"); } @Override public void onError(Throwable e) { error.set(e); System.out.println("error"); e.printStackTrace(); } @Override public void onNext(String v) { System.out.println(v); count.incrementAndGet(); } }); assertEquals(2, count.get()); assertNotNull(error.get()); if (!(error.get() instanceof NumberFormatException)) { fail("It should be a NumberFormatException"); } } @Test public void publishLast() throws InterruptedException { final AtomicInteger count = new AtomicInteger(); ConnectableFlowable<String> connectable = Flowable.<String>unsafeCreate(subscriber -> { subscriber.onSubscribe(new BooleanSubscription()); count.incrementAndGet(); new Thread(() -> { subscriber.onNext("first"); subscriber.onNext("last"); subscriber.onComplete(); }).start(); }).takeLast(1).publish(); // subscribe once final CountDownLatch latch = new CountDownLatch(1); connectable.subscribe(value -> { assertEquals("last", value); latch.countDown(); }); // subscribe twice connectable.subscribe(); Disposable subscription = connectable.connect(); assertTrue(latch.await(1000, TimeUnit.MILLISECONDS)); assertEquals(1, count.get()); subscription.dispose(); } @Test public void replay() throws InterruptedException { final AtomicInteger counter = new AtomicInteger(); ConnectableFlowable<String> f = Flowable.<String>unsafeCreate(subscriber -> { subscriber.onSubscribe(new BooleanSubscription()); new Thread(() -> { counter.incrementAndGet(); subscriber.onNext("one"); subscriber.onComplete(); }).start(); }).replay(); // we connect immediately and it will emit the value Disposable connection = f.connect(); try { // we then expect the following 2 subscriptions to get that same value final CountDownLatch latch = new CountDownLatch(2); // subscribe once f.subscribe(v -> { assertEquals("one", v); latch.countDown(); }); // subscribe again f.subscribe(v -> { assertEquals("one", v); latch.countDown(); }); if (!latch.await(1000, TimeUnit.MILLISECONDS)) { fail("subscriptions did not receive values"); } assertEquals(1, counter.get()); } finally { connection.dispose(); } } @Test public void cache() throws InterruptedException { final AtomicInteger counter = new AtomicInteger(); Flowable<String> f = Flowable.<String>unsafeCreate(subscriber -> { subscriber.onSubscribe(new BooleanSubscription()); new Thread(() -> { counter.incrementAndGet(); subscriber.onNext("one"); subscriber.onComplete(); }).start(); }).cache(); // we then expect the following 2 subscriptions to get that same value final CountDownLatch latch = new CountDownLatch(2); // subscribe once f.subscribe(v -> { assertEquals("one", v); latch.countDown(); }); // subscribe again f.subscribe(v -> { assertEquals("one", v); latch.countDown(); }); if (!latch.await(1000, TimeUnit.MILLISECONDS)) { fail("subscriptions did not receive values"); } assertEquals(1, counter.get()); } @Test public void cacheWithCapacity() throws InterruptedException { final AtomicInteger counter = new AtomicInteger(); Flowable<String> f = Flowable.<String>unsafeCreate(subscriber -> { subscriber.onSubscribe(new BooleanSubscription()); new Thread(() -> { counter.incrementAndGet(); subscriber.onNext("one"); subscriber.onComplete(); }).start(); }).cacheWithInitialCapacity(1); // we then expect the following 2 subscriptions to get that same value final CountDownLatch latch = new CountDownLatch(2); // subscribe once f.subscribe(v -> { assertEquals("one", v); latch.countDown(); }); // subscribe again f.subscribe(v -> { assertEquals("one", v); latch.countDown(); }); if (!latch.await(1000, TimeUnit.MILLISECONDS)) { fail("subscriptions did not receive values"); } assertEquals(1, counter.get()); } @Test public void takeWithErrorInObserver() { final AtomicInteger count = new AtomicInteger(); final AtomicReference<Throwable> error = new AtomicReference<>(); Flowable.just("1", "2", "three", "4").take(3) .safeSubscribe(new DefaultSubscriber<>() /* NFI */ { @Override public void onComplete() { System.out.println("completed"); } @Override public void onError(Throwable e) { error.set(e); System.out.println("error"); e.printStackTrace(); } @Override public void onNext(String v) { int num = Integer.parseInt(v); System.out.println(num); // doSomething(num); count.incrementAndGet(); } }); assertEquals(2, count.get()); assertNotNull(error.get()); if (!(error.get() instanceof NumberFormatException)) { fail("It should be a NumberFormatException"); } } @Test public void ofType() { Flowable<String> flowable = Flowable.just(1, "abc", false, 2L).ofType(String.class); Subscriber<Object> subscriber = TestHelper.mockSubscriber(); flowable.subscribe(subscriber); verify(subscriber, never()).onNext(1); verify(subscriber, times(1)).onNext("abc"); verify(subscriber, never()).onNext(false); verify(subscriber, never()).onNext(2L); verify(subscriber, never()).onError(any(Throwable.class)); verify(subscriber, times(1)).onComplete(); } @Test public void ofTypeWithPolymorphism() { ArrayList<Integer> l1 = new ArrayList<>(); l1.add(1); LinkedList<Integer> l2 = new LinkedList<>(); l2.add(2); @SuppressWarnings("rawtypes") Flowable<List> flowable = Flowable.<Object> just(l1, l2, "123").ofType(List.class); Subscriber<Object> subscriber = TestHelper.mockSubscriber(); flowable.subscribe(subscriber); verify(subscriber, times(1)).onNext(l1); verify(subscriber, times(1)).onNext(l2); verify(subscriber, never()).onNext("123"); verify(subscriber, never()).onError(any(Throwable.class)); verify(subscriber, times(1)).onComplete(); } @Test public void containsFlowable() { Flowable<Boolean> flowable = Flowable.just("a", "b", "c").contains("b").toFlowable(); FlowableSubscriber<Boolean> subscriber = TestHelper.mockSubscriber(); flowable.subscribe(subscriber); verify(subscriber, times(1)).onNext(true); verify(subscriber, never()).onNext(false); verify(subscriber, never()).onError(any(Throwable.class)); verify(subscriber, times(1)).onComplete(); } @Test public void containsWithInexistenceFlowable() { Flowable<Boolean> flowable = Flowable.just("a", "b").contains("c").toFlowable(); Subscriber<Object> subscriber = TestHelper.mockSubscriber(); flowable.subscribe(subscriber); verify(subscriber, times(1)).onNext(false); verify(subscriber, never()).onNext(true); verify(subscriber, never()).onError(any(Throwable.class)); verify(subscriber, times(1)).onComplete(); } @Test public void containsWithEmptyObservableFlowable() { Flowable<Boolean> flowable = Flowable.<String> empty().contains("a").toFlowable(); FlowableSubscriber<Object> subscriber = TestHelper.mockSubscriber(); flowable.subscribe(subscriber); verify(subscriber, times(1)).onNext(false); verify(subscriber, never()).onNext(true); verify(subscriber, never()).onError(any(Throwable.class)); verify(subscriber, times(1)).onComplete(); } @Test public void contains() { Single<Boolean> single = Flowable.just("a", "b", "c").contains("b"); // FIXME nulls not allowed, changed to "c" SingleObserver<Boolean> observer = TestHelper.mockSingleObserver(); single.subscribe(observer); verify(observer, times(1)).onSuccess(true); verify(observer, never()).onSuccess(false); verify(observer, never()).onError( any(Throwable.class)); } @Test public void containsWithInexistence() { Single<Boolean> single = Flowable.just("a", "b").contains("c"); // FIXME null values are not allowed, removed SingleObserver<Boolean> observer = TestHelper.mockSingleObserver(); single.subscribe(observer); verify(observer, times(1)).onSuccess(false); verify(observer, never()).onSuccess(true); verify(observer, never()).onError( any(Throwable.class)); } @Test public void containsWithEmptyObservable() { Single<Boolean> single = Flowable.<String> empty().contains("a"); SingleObserver<Boolean> observer = TestHelper.mockSingleObserver(); single.subscribe(observer); verify(observer, times(1)).onSuccess(false); verify(observer, never()).onSuccess(true); verify(observer, never()).onError( any(Throwable.class)); } @Test public void ignoreElementsFlowable() { Flowable<Integer> flowable = Flowable.just(1, 2, 3).ignoreElements().toFlowable(); Subscriber<Object> subscriber = TestHelper.mockSubscriber(); flowable.subscribe(subscriber); verify(subscriber, never()).onNext(any(Integer.class)); verify(subscriber, never()).onError(any(Throwable.class)); verify(subscriber, times(1)).onComplete(); } @Test public void ignoreElements() { Completable completable = Flowable.just(1, 2, 3).ignoreElements(); CompletableObserver observer = TestHelper.mockCompletableObserver(); completable.subscribe(observer); verify(observer, never()).onError(any(Throwable.class)); verify(observer, times(1)).onComplete(); } @Test public void justWithScheduler() { TestScheduler scheduler = new TestScheduler(); Flowable<Integer> flowable = Flowable.fromArray(1, 2).subscribeOn(scheduler); Subscriber<Integer> subscriber = TestHelper.mockSubscriber(); flowable.subscribe(subscriber); scheduler.advanceTimeBy(1, TimeUnit.MILLISECONDS); InOrder inOrder = inOrder(subscriber); inOrder.verify(subscriber, times(1)).onNext(1); inOrder.verify(subscriber, times(1)).onNext(2); inOrder.verify(subscriber, times(1)).onComplete(); inOrder.verifyNoMoreInteractions(); } @Test public void startWithWithScheduler() { TestScheduler scheduler = new TestScheduler(); Flowable<Integer> flowable = Flowable.just(3, 4).startWithIterable(Arrays.asList(1, 2)).subscribeOn(scheduler); Subscriber<Integer> subscriber = TestHelper.mockSubscriber(); flowable.subscribe(subscriber); scheduler.advanceTimeBy(1, TimeUnit.MILLISECONDS); InOrder inOrder = inOrder(subscriber); inOrder.verify(subscriber, times(1)).onNext(1); inOrder.verify(subscriber, times(1)).onNext(2); inOrder.verify(subscriber, times(1)).onNext(3); inOrder.verify(subscriber, times(1)).onNext(4); inOrder.verify(subscriber, times(1)).onComplete(); inOrder.verifyNoMoreInteractions(); } @Test public void rangeWithScheduler() { TestScheduler scheduler = new TestScheduler(); Flowable<Integer> flowable = Flowable.range(3, 4).subscribeOn(scheduler); Subscriber<Integer> subscriber = TestHelper.mockSubscriber(); flowable.subscribe(subscriber); scheduler.advanceTimeBy(1, TimeUnit.MILLISECONDS); InOrder inOrder = inOrder(subscriber); inOrder.verify(subscriber, times(1)).onNext(3); inOrder.verify(subscriber, times(1)).onNext(4); inOrder.verify(subscriber, times(1)).onNext(5); inOrder.verify(subscriber, times(1)).onNext(6); inOrder.verify(subscriber, times(1)).onComplete(); inOrder.verifyNoMoreInteractions(); } @Test public void mergeWith() { TestSubscriber<Integer> ts = new TestSubscriber<>(); Flowable.just(1).mergeWith(Flowable.just(2)).subscribe(ts); ts.assertValues(1, 2); } @Test public void concatWith() { TestSubscriber<Integer> ts = new TestSubscriber<>(); Flowable.just(1).concatWith(Flowable.just(2)).subscribe(ts); ts.assertValues(1, 2); } @Test public void ambWith() { TestSubscriber<Integer> ts = new TestSubscriber<>(); Flowable.just(1).ambWith(Flowable.just(2)).subscribe(ts); ts.assertValue(1); } @Test public void takeWhileToList() { final int expectedCount = 3; final AtomicInteger count = new AtomicInteger(); for (int i = 0; i < expectedCount; i++) { Flowable .just(Boolean.TRUE, Boolean.FALSE) .takeWhile(v -> v) .toList() .doOnSuccess(_ -> count.incrementAndGet()) .subscribe(); } assertEquals(expectedCount, count.get()); } @Test public void compose() { TestSubscriberEx<String> ts = new TestSubscriberEx<>(); Flowable.just(1, 2, 3).compose(t1 -> t1.map(String::valueOf)) .subscribe(ts); ts.assertTerminated(); ts.assertNoErrors(); ts.assertValues("1", "2", "3"); } @Test public void errorThrownIssue1685() { List<Throwable> errors = TestHelper.trackPluginErrors(); try { FlowableProcessor<Object> processor = ReplayProcessor.create(); Flowable.error(new RuntimeException("oops")) .materialize() .delay(1, TimeUnit.SECONDS) .dematerialize(Functions.<Notification<Object>>identity()) .subscribe(processor); processor.subscribe(); processor.materialize().blockingFirst(); System.out.println("Done"); TestHelper.assertError(errors, 0, OnErrorNotImplementedException.class); } finally { RxJavaPlugins.reset(); } } @Test public void emptyIdentity() { assertEquals(Flowable.empty(), Flowable.empty()); } @Test public void emptyIsEmpty() { Flowable.<Integer>empty().subscribe(w); verify(w).onComplete(); verify(w, never()).onNext(any(Integer.class)); verify(w, never()).onError(any(Throwable.class)); } @Test public void extend() { final TestSubscriber<Object> subscriber = new TestSubscriber<>(); final Object value = new Object(); Object returned = Flowable.just(value).to(onSubscribe -> { onSubscribe.subscribe(subscriber); subscriber.assertNoErrors(); subscriber.assertComplete(); subscriber.assertValue(value); return subscriber.values().getFirst(); }); assertSame(returned, value); } @Test public void asExtend() { final TestSubscriber<Object> subscriber = new TestSubscriber<>(); final Object value = new Object(); Object returned = Flowable.just(value).to(onSubscribe -> { onSubscribe.subscribe(subscriber); subscriber.assertNoErrors(); subscriber.assertComplete(); subscriber.assertValue(value); return subscriber.values().getFirst(); }); assertSame(returned, value); } @Test public void as() { Flowable.just(1).to(Flowable::toObservable) .test() .assertResult(1); } @Test public void toObservableEmpty() { Flowable.empty().toObservable().test().assertResult(); } @Test public void toObservableJust() { Flowable.just(1).toObservable().test().assertResult(1); } @Test public void toObservableRange() { Flowable.range(1, 5).toObservable().test().assertResult(1, 2, 3, 4, 5); } @Test public void toObservableError() { Flowable.error(new TestException()).toObservable().test().assertFailure(TestException.class); } @Test public void zipIterableObject() { final List<Flowable<Integer>> flowables = Arrays.asList(Flowable.just(1, 2, 3), Flowable.just(1, 2, 3)); Flowable.zip(flowables, o -> { int sum = 0; for (Object i : o) { sum += (Integer) i; } return sum; }).test().assertResult(2, 4, 6); } @Test public void combineLatestObject() { final List<Flowable<Integer>> flowables = Arrays.asList(Flowable.just(1, 2, 3), Flowable.just(1, 2, 3)); Flowable.combineLatest(flowables, o -> { int sum = 1; for (Object i : o) { sum *= (Integer) i; } return sum; }).test().assertResult(3, 6, 9); } }