/
githubmirror
/
RxJava
Обзор
Документация
Войти
/
githubmirror
/
RxJava
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
4.x
src/test/java/io/reactivex/rxjava4/flowable/FlowableSubscriberTest.java
699 строк
19 KB
David Karnok
4.x: Convert from JUnit 4 to JUnit 6 (#8202)
30 июн 2026, 12:01
Не верифицирован
30 июн 2026, 12:01
531388f
Код
Авторство
О чём код?
/* * 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 java.util.*; import java.util.concurrent.Flow.*; import java.util.concurrent.atomic.*; import org.junit.jupiter.api.Test; import io.reactivex.rxjava4.core.*; import io.reactivex.rxjava4.disposables.Disposable; import io.reactivex.rxjava4.exceptions.*; import io.reactivex.rxjava4.internal.functions.Functions; import io.reactivex.rxjava4.internal.subscribers.ForEachWhileSubscriber; import io.reactivex.rxjava4.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava4.plugins.RxJavaPlugins; import io.reactivex.rxjava4.processors.PublishProcessor; import io.reactivex.rxjava4.subscribers.*; import io.reactivex.rxjava4.testsupport.TestHelper; public class FlowableSubscriberTest { /** * Should request n for whatever the final Subscriber asks for. */ @Test public void requestFromFinalSubscribeWithRequestValue() { TestSubscriber<String> s = new TestSubscriber<>(0L); s.request(10); final AtomicLong r = new AtomicLong(); s.onSubscribe(new Subscription() /* NFI */ { @Override public void request(long n) { r.set(n); } @Override public void cancel() { } }); assertEquals(10, r.get()); } /** * Should request -1 for infinite. */ @Test public void requestFromFinalSubscribeWithoutRequestValue() { TestSubscriber<String> s = new TestSubscriber<>(); final AtomicLong r = new AtomicLong(); s.onSubscribe(new Subscription() /* NFI */ { @Override public void request(long n) { r.set(n); } @Override public void cancel() { } }); assertEquals(Long.MAX_VALUE, r.get()); } @Test public void requestFromChainedOperator() throws Throwable { TestSubscriber<String> s = new TestSubscriber<>(10L); FlowableOperator<String, String> o = s1 -> new FlowableSubscriber<>() /* NFI */ { @Override public void onSubscribe(Subscription a) { s1.onSubscribe(a); } @Override public void onComplete() { } @Override public void onError(Throwable e) { } @Override public void onNext(String t) { } }; Subscriber<? super String> ns = o.apply(s); final AtomicLong r = new AtomicLong(); // set the producer at the top of the chain (ns) and it should flow through the operator to the (s) subscriber // and then it should request up with the value set on the final Subscriber (s) ns.onSubscribe(new Subscription() /* NFI */ { @Override public void request(long n) { r.set(n); } @Override public void cancel() { } }); assertEquals(10, r.get()); } @Test public void requestFromDecoupledOperator() throws Throwable { TestSubscriber<String> s = new TestSubscriber<>(0L); FlowableOperator<String, String> o = s1 -> new FlowableSubscriber<>() /* NFI */ { @Override public void onSubscribe(Subscription a) { s1.onSubscribe(a); } @Override public void onComplete() { } @Override public void onError(Throwable e) { } @Override public void onNext(String t) { } }; s.request(10); Subscriber<? super String> ns = o.apply(s); final AtomicLong r = new AtomicLong(); // set the producer at the top of the chain (ns) and it should flow through the operator to the (s) subscriber // and then it should request up with the value set on the final Subscriber (s) ns.onSubscribe(new Subscription() /* NFI */ { @Override public void request(long n) { r.set(n); } @Override public void cancel() { } }); assertEquals(10, r.get()); } @Test public void requestFromDecoupledOperatorThatRequestsN() throws Throwable { TestSubscriber<String> s = new TestSubscriber<>(10L); final AtomicLong innerR = new AtomicLong(); FlowableOperator<String, String> o = child -> { // we want to decouple the chain so set our own Producer on the child instead of it coming from the parent child.onSubscribe(new Subscription() /* NFI */ { @Override public void request(long n) { innerR.set(n); } @Override public void cancel() { } }); var as = new ResourceSubscriber<String>() /* NFI */ { @Override protected void onStart() { // we request 99 up to the parent request(99); } @Override public void onComplete() { } @Override public void onError(Throwable e) { } @Override public void onNext(String t) { } }; return as; }; Subscriber<? super String> ns = o.apply(s); final AtomicLong r = new AtomicLong(); // set the producer at the top of the chain (ns) and it should flow through the operator to the (s) subscriber // and then it should request up with the value set on the final Subscriber (s) ns.onSubscribe(new Subscription() /* NFI */ { @Override public void request(long n) { r.set(n); } @Override public void cancel() { } }); assertEquals(99, r.get()); assertEquals(10, innerR.get()); } @Test public void requestToFlowable() { TestSubscriber<Integer> ts = new TestSubscriber<>(3L); final AtomicLong requested = new AtomicLong(); Flowable.<Integer>unsafeCreate(s -> s.onSubscribe(new Subscription() /* NFI */ { @Override public void request(long n) { requested.set(n); } @Override public void cancel() { } })).subscribe(ts); assertEquals(3, requested.get()); } @Test public void requestThroughMap() { TestSubscriber<Integer> ts = new TestSubscriber<>(0L); ts.request(3); final AtomicLong requested = new AtomicLong(); Flowable.<Integer>unsafeCreate(s -> s.onSubscribe(new Subscription() /* NFI */ { @Override public void request(long n) { requested.set(n); } @Override public void cancel() { } })).map(Functions.<Integer>identity()).subscribe(ts); assertEquals(3, requested.get()); } @Test public void requestThroughTakeThatReducesRequest() { TestSubscriber<Integer> ts = new TestSubscriber<>(0L); ts.request(3); final AtomicLong requested = new AtomicLong(); Flowable.<Integer>unsafeCreate(s -> s.onSubscribe(new Subscription() /* NFI */ { @Override public void request(long n) { requested.set(n); } @Override public void cancel() { } })).take(2).subscribe(ts); assertEquals(2, requested.get()); } @Test public void requestThroughTakeWhereRequestIsSmallerThanTake() { TestSubscriber<Integer> ts = new TestSubscriber<>(0L); ts.request(3); final AtomicLong requested = new AtomicLong(); Flowable.<Integer>unsafeCreate(s -> s.onSubscribe(new Subscription() /* NFI */ { @Override public void request(long n) { requested.set(n); } @Override public void cancel() { } })).take(10).subscribe(ts); assertEquals(3, requested.get()); } @Test public void onStartCalledOnceViaSubscribe() { final AtomicInteger c = new AtomicInteger(); Flowable.just(1, 2, 3, 4).take(2).subscribe(new DefaultSubscriber<>() /* NFI */ { @Override public void onStart() { c.incrementAndGet(); request(1); } @Override public void onComplete() { } @Override public void onError(Throwable e) { } @Override public void onNext(Integer t) { request(1); } }); assertEquals(1, c.get()); } @Test public void onStartCalledOnceViaUnsafeSubscribe() { final AtomicInteger c = new AtomicInteger(); Flowable.just(1, 2, 3, 4).take(2).subscribe(new DefaultSubscriber<>() /* NFI */ { @Override public void onStart() { c.incrementAndGet(); request(1); } @Override public void onComplete() { } @Override public void onError(Throwable e) { } @Override public void onNext(Integer t) { request(1); } }); assertEquals(1, c.get()); } @Test public void onStartCalledOnceViaLift() { final AtomicInteger c = new AtomicInteger(); Flowable.just(1, 2, 3, 4).lift(child -> new DefaultSubscriber<>() /* NFI */ { @Override public void onStart() { c.incrementAndGet(); request(1); } @Override public void onComplete() { child.onComplete(); } @Override public void onError(Throwable e) { child.onError(e); } @Override public void onNext(Integer t) { child.onNext(t); request(1); } }).subscribe(); assertEquals(1, c.get()); } @Test public void onStartRequestsAreAdditive() { final List<Integer> list = new ArrayList<>(); Flowable.just(1, 2, 3, 4, 5) .subscribe(new DefaultSubscriber<>() /* NFI */ { @Override public void onStart() { request(3); request(2); } @Override public void onComplete() { } @Override public void onError(Throwable e) { } @Override public void onNext(Integer t) { list.add(t); } }); assertEquals(Arrays.asList(1, 2, 3, 4, 5), list); } @Test public void onStartRequestsAreAdditiveAndOverflowBecomesMaxValue() { final List<Integer> list = new ArrayList<>(); Flowable.just(1, 2, 3, 4, 5).subscribe(new DefaultSubscriber<>() /* NFI */ { @Override public void onStart() { request(2); request(Long.MAX_VALUE - 1); } @Override public void onComplete() { } @Override public void onError(Throwable e) { } @Override public void onNext(Integer t) { list.add(t); } }); assertEquals(Arrays.asList(1, 2, 3, 4, 5), list); } @Test public void forEachWhile() { PublishProcessor<Integer> pp = PublishProcessor.create(); final List<Integer> list = new ArrayList<>(); Disposable d = pp.forEachWhile(v -> { list.add(v); return v < 3; }); assertFalse(d.isDisposed()); pp.onNext(1); pp.onNext(2); pp.onNext(3); assertFalse(pp.hasSubscribers()); assertEquals(Arrays.asList(1, 2, 3), list); } @Test public void doubleSubscribe() { ForEachWhileSubscriber<Integer> s = new ForEachWhileSubscriber<>(_ -> true, Functions.<Throwable>emptyConsumer(), Functions.EMPTY_ACTION); List<Throwable> list = TestHelper.trackPluginErrors(); try { s.onSubscribe(new BooleanSubscription()); BooleanSubscription bs = new BooleanSubscription(); s.onSubscribe(bs); assertTrue(bs.isCancelled()); TestHelper.assertError(list, 0, IllegalStateException.class, "Subscription already set!"); } finally { RxJavaPlugins.reset(); } } @Test public void suppressAfterCompleteEvents() { List<Throwable> errors = TestHelper.trackPluginErrors(); try { final TestSubscriber<Integer> ts = new TestSubscriber<>(); ts.onSubscribe(new BooleanSubscription()); ForEachWhileSubscriber<Integer> s = new ForEachWhileSubscriber<>(v -> { ts.onNext(v); return true; }, ts::onError, ts::onComplete); s.onComplete(); s.onNext(1); s.onError(new TestException()); s.onComplete(); ts.assertResult(); TestHelper.assertUndeliverable(errors, 0, TestException.class); } finally { RxJavaPlugins.reset(); } } @Test public void onNextCrashes() { final TestSubscriber<Integer> ts = new TestSubscriber<>(); ts.onSubscribe(new BooleanSubscription()); ForEachWhileSubscriber<Integer> s = new ForEachWhileSubscriber<>(_ -> { throw new TestException(); }, ts::onError, ts::onComplete); BooleanSubscription b = new BooleanSubscription(); s.onSubscribe(b); s.onNext(1); assertTrue(b.isCancelled()); ts.assertFailure(TestException.class); } @Test public void onErrorThrows() { ForEachWhileSubscriber<Integer> s = new ForEachWhileSubscriber<>(_ -> true, _ -> { throw new TestException("Inner"); }, () -> { }); List<Throwable> list = TestHelper.trackPluginErrors(); try { s.onSubscribe(new BooleanSubscription()); s.onError(new TestException("Outer")); TestHelper.assertError(list, 0, CompositeException.class); List<Throwable> cel = TestHelper.compositeList(list.getFirst()); TestHelper.assertError(cel, 0, TestException.class, "Outer"); TestHelper.assertError(cel, 1, TestException.class, "Inner"); } finally { RxJavaPlugins.reset(); } } @Test public void onCompleteThrows() { ForEachWhileSubscriber<Integer> s = new ForEachWhileSubscriber<>(_ -> true, _ -> { }, () -> { throw new TestException("Inner"); }); List<Throwable> list = TestHelper.trackPluginErrors(); try { s.onSubscribe(new BooleanSubscription()); s.onComplete(); TestHelper.assertUndeliverable(list, 0, TestException.class, "Inner"); } finally { RxJavaPlugins.reset(); } } @Test public void subscribeConsumerConsumerWithError() { final List<Integer> list = new ArrayList<>(); Flowable.<Integer>error(new TestException()).subscribe(list::add, _ -> list.add(100)); assertEquals(List.of(100), list); } @Test public void methodTestCancelled() { PublishProcessor<Integer> pp = PublishProcessor.create(); pp.test(Long.MAX_VALUE, true); assertFalse(pp.hasSubscribers()); } @Test public void safeSubscriberAlreadySafe() { TestSubscriber<Integer> ts = new TestSubscriber<>(); Flowable.just(1).safeSubscribe(new SafeSubscriber<>(ts)); ts.assertResult(1); } @Test public void methodTestNoCancel() { PublishProcessor<Integer> pp = PublishProcessor.create(); pp.test(Long.MAX_VALUE, false); assertTrue(pp.hasSubscribers()); } @Test public void subscribeConsumerConsumer() { final List<Integer> list = new ArrayList<>(); Flowable.just(1).subscribe(list::add, _ -> list.add(100)); assertEquals(List.of(1), list); } @Test public void pluginNull() { RxJavaPlugins.setOnFlowableSubscribe((_, _) -> null); try { try { Flowable.just(1).test(); fail("Should have thrown"); } catch (NullPointerException ex) { assertEquals("The RxJavaPlugins.onSubscribe hook returned a null FlowableSubscriber. " + "Please check the handler provided to RxJavaPlugins.setOnFlowableSubscribe for invalid null returns. " + "Further reading: https://github.com/ReactiveX/RxJava/wiki/Plugins", ex.getMessage()); } } finally { RxJavaPlugins.reset(); } } static final class BadFlowable extends Flowable<Integer> { @Override protected void subscribeActual(Subscriber<? super Integer> s) { throw new IllegalArgumentException(); } } @Test public void subscribeActualThrows() { List<Throwable> list = TestHelper.trackPluginErrors(); try { try { new BadFlowable().test(); fail("Should have thrown!"); } catch (NullPointerException ex) { if (!(ex.getCause() instanceof IllegalArgumentException)) { fail(ex.toString() + ": Should be NPE(IAE)"); } } TestHelper.assertError(list, 0, IllegalArgumentException.class); } finally { RxJavaPlugins.reset(); } } }