/** * 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.subscribers; import io.reactivex.Flowable; import io.reactivex.functions.*; import io.reactivex.internal.fuseable.*; /** * Utility methods that return functional interfaces to support assertions regarding fusion * in a TestSubscriber. * <p>Don't move this class as it needs package-private access to TestSubscriber's internals. */ public enum SubscriberFusion { ; /** * Returns a function that takes a Flowable and returns a TestSubscriber that * is set up according to the parameters and is subscribed to the Flowable. * <p> * Use this as follows: * <pre> * source * .to(SubscriberFusion.test(0, QueueSubscription.ANY, false)) * .assertResult(0); * </pre> * @param <T> the value type * @param initialRequest the initial request amount, non-negative * @param mode the fusion mode to request, see {@link QueueSubscription} constants. * @param cancelled should the TestSubscriber cancelled before the subscription even happens? * @return the new Function instance */ public static <T> Function<Flowable<T>, TestSubscriber<T>> test( final long initialRequest, final int mode, final boolean cancelled) { return new TestFusionCheckFunction<T>(mode, cancelled, initialRequest); } /** * Returns a Consumer that asserts on its TestSubscriber parameter that * the upstream is Fuseable (sent a QueueDisposable subclass in onSubscribe). * <p> * Use this as follows: * <pre> * source * .to(ObserverFusion.test(0, QueueDisposable.ANY, false)) * .assertOf(ObserverFusion.assertFuseable()); * </pre> * @param <T> the value type * @return the new Consumer instance */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static <T> Consumer<TestSubscriber<T>> assertFuseable() { return (Consumer)AssertFuseable.INSTANCE; } static final class AssertFusionConsumer<T> implements Consumer<TestSubscriber<T>> { private final int mode; AssertFusionConsumer(int mode) { this.mode = mode; } @Override public void accept(TestSubscriber<T> ts) throws Exception { ts.assertFusionMode(mode); } } static final class TestFusionCheckFunction<T> implements Function<Flowable<T>, TestSubscriber<T>> { private final int mode; private final boolean cancelled; private final long initialRequest; TestFusionCheckFunction(int mode, boolean cancelled, long initialRequest) { this.mode = mode; this.cancelled = cancelled; this.initialRequest = initialRequest; } @Override public TestSubscriber<T> apply(Flowable<T> t) throws Exception { TestSubscriber<T> ts = new TestSubscriber<T>(initialRequest); ts.setInitialFusionMode(mode); if (cancelled) { ts.cancel(); } t.subscribe(ts); return ts; } } enum AssertFuseable implements Consumer<TestSubscriber<Object>> { INSTANCE; @Override public void accept(TestSubscriber<Object> ts) throws Exception { ts.assertFuseable(); } } /** * Returns a Consumer that asserts on its TestSubscriber parameter that * the upstream is not Fuseable (didn't sent a QueueDisposable subclass in onSubscribe). * <p> * Use this as follows: * <pre> * source * .to(ObserverFusion.test(0, QueueDisposable.ANY, false)) * .assertOf(ObserverFusion.assertNotFuseable()); * </pre> * @param <T> the value type * @return the new Consumer instance */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static <T> Consumer<TestSubscriber<T>> assertNotFuseable() { return (Consumer)AssertNotFuseable.INSTANCE; } enum AssertNotFuseable implements Consumer<TestSubscriber<Object>> { INSTANCE; @Override public void accept(TestSubscriber<Object> ts) throws Exception { ts.assertNotFuseable(); } } /** * Returns a Consumer that asserts on its TestSubscriber parameter that * the upstream is Fuseable (sent a QueueSubscription subclass in onSubscribe) * and the established the given fusion mode. * <p> * Use this as follows: * <pre> * source * .to(SubscriberFusion.test(0, QueueSubscription.ANY, false)) * .assertOf(SubscriberFusion.assertFusionMode(QueueSubscription.SYNC)); * </pre> * @param <T> the value type * @param mode the expected established fusion mode, see {@link QueueSubscription} constants. * @return the new Consumer instance */ public static <T> Consumer<TestSubscriber<T>> assertFusionMode(final int mode) { return new AssertFusionConsumer<T>(mode); } /** * Constructs a TestSubscriber with the given initial request and required fusion mode. * @param <T> the value type * @param initialRequest the initial request, non-negative * @param mode the requested fusion mode, see {@link QueueSubscription} constants * @return the new TestSubscriber */ public static <T> TestSubscriber<T> newTest(long initialRequest, int mode) { TestSubscriber<T> ts = new TestSubscriber<T>(initialRequest); ts.setInitialFusionMode(mode); return ts; } /** * Constructs a TestSubscriber with the given required fusion mode. * @param <T> the value type * @param mode the requested fusion mode, see {@link QueueSubscription} constants * @return the new TestSubscriber */ public static <T> TestSubscriber<T> newTest(int mode) { TestSubscriber<T> ts = new TestSubscriber<T>(); ts.setInitialFusionMode(mode); return ts; } /** * Assert that the TestSubscriber received a fuseabe QueueSubscription and * is in the given fusion mode. * @param <T> the value type * @param ts the TestSubscriber instance * @param mode the expected mode * @return the TestSubscriber */ public static <T> TestSubscriber<T> assertFusion(TestSubscriber<T> ts, int mode) { return ts.assertOf(SubscriberFusion.<T>assertFuseable()) .assertOf(SubscriberFusion.<T>assertFusionMode(mode)); } }