diff --git a/build.gradle b/build.gradle index 6aedbf1d045..afda85539fd 100644 --- a/build.gradle +++ b/build.gradle @@ -180,6 +180,7 @@ jmh { def isCI = System.getenv("CI") != null def testLoggingConfig = ["skipped", "failed"] def parallelism = Runtime.runtime.availableProcessors() +def heap = "1400m" if (!isCI) { testLoggingConfig = ["failed"] @@ -187,7 +188,7 @@ if (!isCI) { } test { - maxHeapSize = "1200m" + maxHeapSize = heap maxParallelForks = parallelism timeout = Duration.ofMinutes(30) @@ -206,7 +207,7 @@ tasks.register('testNG', Test) { // Tell it to use TestNG explicitly useTestNG() - maxHeapSize = "1200m" + maxHeapSize = heap maxParallelForks = parallelism timeout = Duration.ofMinutes(30) diff --git a/src/jmh/java/io/reactivex/rxjava4/core/OperatorFlatMapPerf.java b/src/jmh/java/io/reactivex/rxjava4/core/OperatorFlatMapPerf.java index 5d22eb99a7c..680ad48771f 100644 --- a/src/jmh/java/io/reactivex/rxjava4/core/OperatorFlatMapPerf.java +++ b/src/jmh/java/io/reactivex/rxjava4/core/OperatorFlatMapPerf.java @@ -49,7 +49,7 @@ public void flatMapIntPassthruAsync(Input input) throws InterruptedException { PerfSubscriber latchedObserver = input.newLatchedObserver(); input.flowable.flatMap((Function>) i -> Flowable.just(i).subscribeOn(Schedulers.computation())).subscribe(latchedObserver); if (input.size == 1) { - while (latchedObserver.latch.getCount() != 0) { } + while (latchedObserver.latch.getCount() != 0) { Thread.onSpinWait(); } } else { latchedObserver.latch.await(); } diff --git a/src/jmh/java/io/reactivex/rxjava4/core/OperatorMergePerf.java b/src/jmh/java/io/reactivex/rxjava4/core/OperatorMergePerf.java index 58631d56a67..627b28ea425 100644 --- a/src/jmh/java/io/reactivex/rxjava4/core/OperatorMergePerf.java +++ b/src/jmh/java/io/reactivex/rxjava4/core/OperatorMergePerf.java @@ -35,7 +35,7 @@ public void oneStreamOfNthatMergesIn1(final InputMillion input) throws Interrupt Flowable.merge(os).subscribe(o); if (input.size == 1) { - while (o.latch.getCount() != 0) { } + while (o.latch.getCount() != 0) { Thread.onSpinWait(); } } else { o.latch.await(); } @@ -49,7 +49,7 @@ public void merge1SyncStreamOfN(final InputMillion input) throws InterruptedExce Flowable.merge(os).subscribe(o); if (input.size == 1) { - while (o.latch.getCount() != 0) { } + while (o.latch.getCount() != 0) { Thread.onSpinWait(); } } else { o.latch.await(); } @@ -61,7 +61,7 @@ public void mergeNSyncStreamsOfN(final InputThousand input) throws InterruptedEx PerfSubscriber o = input.newLatchedObserver(); Flowable.merge(os).subscribe(o); if (input.size == 1) { - while (o.latch.getCount() != 0) { } + while (o.latch.getCount() != 0) { Thread.onSpinWait(); } } else { o.latch.await(); } @@ -73,7 +73,7 @@ public void mergeNAsyncStreamsOfN(final InputThousand input) throws InterruptedE PerfSubscriber o = input.newLatchedObserver(); Flowable.merge(os).subscribe(o); if (input.size == 1) { - while (o.latch.getCount() != 0) { } + while (o.latch.getCount() != 0) { Thread.onSpinWait(); } } else { o.latch.await(); } @@ -85,7 +85,7 @@ public void mergeTwoAsyncStreamsOfN(final InputThousand input) throws Interrupte Flowable ob = Flowable.range(0, input.size).subscribeOn(Schedulers.computation()); Flowable.merge(ob, ob).subscribe(o); if (input.size == 1) { - while (o.latch.getCount() != 0) { } + while (o.latch.getCount() != 0) { Thread.onSpinWait(); } } else { o.latch.await(); } @@ -96,7 +96,7 @@ public void mergeNSyncStreamsOf1(final InputForMergeN input) throws InterruptedE PerfSubscriber o = input.newLatchedObserver(); Flowable.merge(input.observables).subscribe(o); if (input.size == 1) { - while (o.latch.getCount() != 0) { } + while (o.latch.getCount() != 0) { Thread.onSpinWait(); } } else { o.latch.await(); } diff --git a/src/jmh/java/io/reactivex/rxjava4/core/PerfAsyncConsumer.java b/src/jmh/java/io/reactivex/rxjava4/core/PerfAsyncConsumer.java index 066dfbb483e..1ba98a94bd7 100644 --- a/src/jmh/java/io/reactivex/rxjava4/core/PerfAsyncConsumer.java +++ b/src/jmh/java/io/reactivex/rxjava4/core/PerfAsyncConsumer.java @@ -73,7 +73,7 @@ public void onComplete() { */ public PerfAsyncConsumer await(int count) { if (count <= 1000) { - while (getCount() != 0) { } + while (getCount() != 0) { Thread.onSpinWait(); } } else { try { await(); diff --git a/src/jmh/java/io/reactivex/rxjava4/core/RangePerf.java b/src/jmh/java/io/reactivex/rxjava4/core/RangePerf.java index 4f9d495a5cf..f6dc44d9c68 100644 --- a/src/jmh/java/io/reactivex/rxjava4/core/RangePerf.java +++ b/src/jmh/java/io/reactivex/rxjava4/core/RangePerf.java @@ -63,7 +63,7 @@ public void rangeAsync(Blackhole bh) throws Exception { rangeAsync.subscribe(lo); if (times == 1) { - while (lo.latch.getCount() != 0) { } + while (lo.latch.getCount() != 0) { Thread.onSpinWait(); } } else { lo.latch.await(); } @@ -76,7 +76,7 @@ public void rangePipeline(Blackhole bh) throws Exception { rangeAsyncPipeline.subscribe(lo); if (times == 1) { - while (lo.latch.getCount() != 0) { } + while (lo.latch.getCount() != 0) { Thread.onSpinWait(); } } else { lo.latch.await(); } diff --git a/src/jmh/java/io/reactivex/rxjava4/core/TakeUntilPerf.java b/src/jmh/java/io/reactivex/rxjava4/core/TakeUntilPerf.java index a1e36191426..186f547f7fd 100644 --- a/src/jmh/java/io/reactivex/rxjava4/core/TakeUntilPerf.java +++ b/src/jmh/java/io/reactivex/rxjava4/core/TakeUntilPerf.java @@ -48,13 +48,13 @@ public void setup() { flowable = Flowable.range(1, 1000 * 1000).takeUntil(Flowable.fromCallable((Callable) () -> { int c = count; - while (items < c) { } + while (items < c) { Thread.onSpinWait(); } return 1; }).subscribeOn(Schedulers.single())); observable = Observable.range(1, 1000 * 1000).takeUntil(Observable.fromCallable((Callable) () -> { int c = count; - while (items < c) { } + while (items < c) { Thread.onSpinWait(); } return 1; }).subscribeOn(Schedulers.single())); } @@ -65,7 +65,7 @@ public void flowable() { flowable.subscribe(this, Functions.emptyConsumer(), cdl::countDown); - while (cdl.getCount() != 0) { } + while (cdl.getCount() != 0) { Thread.onSpinWait(); } } @Benchmark @@ -74,6 +74,6 @@ public void observable() { observable.subscribe(this, Functions.emptyConsumer(), cdl::countDown); - while (cdl.getCount() != 0) { } + while (cdl.getCount() != 0) { Thread.onSpinWait(); } } } diff --git a/src/main/java/io/reactivex/rxjava4/core/Flowable.java b/src/main/java/io/reactivex/rxjava4/core/Flowable.java index 740aac94ae9..06d6048ab16 100644 --- a/src/main/java/io/reactivex/rxjava4/core/Flowable.java +++ b/src/main/java/io/reactivex/rxjava4/core/Flowable.java @@ -14526,7 +14526,7 @@ public final Flowable retryUntil(@NonNull BooleanSupplier stop) { * *

* Example: - * + *

* This retries 3 times, each time incrementing the number of seconds it waits. * *


diff --git a/src/main/java/io/reactivex/rxjava4/core/FlowableSubscriber.java b/src/main/java/io/reactivex/rxjava4/core/FlowableSubscriber.java
index c2bbbfd3bb1..a8ebbc71208 100644
--- a/src/main/java/io/reactivex/rxjava4/core/FlowableSubscriber.java
+++ b/src/main/java/io/reactivex/rxjava4/core/FlowableSubscriber.java
@@ -35,7 +35,7 @@ public interface FlowableSubscriber<@NonNull T> extends Subscriber {
      * calling {@link Subscription#request(long)}. In practice this means
      * no initialization should happen after the {@code request()} call and
      * additional behavior is thread safe in respect to {@code onNext}.
-     *
+     * 

* {@inheritDoc} */ @Override diff --git a/src/main/java/io/reactivex/rxjava4/core/Maybe.java b/src/main/java/io/reactivex/rxjava4/core/Maybe.java index e8b86e318ad..98715a67c9b 100644 --- a/src/main/java/io/reactivex/rxjava4/core/Maybe.java +++ b/src/main/java/io/reactivex/rxjava4/core/Maybe.java @@ -4358,7 +4358,7 @@ public final Maybe retryUntil(@NonNull BooleanSupplier stop) { * *

* Example: - * + *

* This retries 3 times, each time incrementing the number of seconds it waits. * *


@@ -5391,7 +5391,7 @@ public final Maybe unsubscribeOn(@NonNull Scheduler scheduler) {
     /**
      * Waits until this and the other {@link MaybeSource} signal a success value then applies the given {@link BiFunction}
      * to those values and emits the {@code BiFunction}'s resulting value to downstream.
-     *
+     * 

* * *

If either this or the other {@code MaybeSource} is empty or signals an error, the resulting {@code Maybe} will diff --git a/src/main/java/io/reactivex/rxjava4/exceptions/CompositeException.java b/src/main/java/io/reactivex/rxjava4/exceptions/CompositeException.java index 632ac682ecb..c961acf6707 100644 --- a/src/main/java/io/reactivex/rxjava4/exceptions/CompositeException.java +++ b/src/main/java/io/reactivex/rxjava4/exceptions/CompositeException.java @@ -21,14 +21,14 @@ /** * Represents an exception that is a composite of one or more other exceptions. A {@code CompositeException} * does not modify the structure of any exception it wraps, but at print-time it iterates through the list of - * Throwables contained in the composite in order to print them all. - * + * {@link Throwable}s contained in the composite in order to print them all. + *

* Its invariant is to contain an immutable, ordered (by insertion order), unique list of non-composite * exceptions. You can retrieve individual exceptions in this list with {@link #getExceptions()}. - * + *

* The {@link #printStackTrace()} implementation handles the StackTrace in a customized way instead of using * {@code getCause()} so that it can avoid circular references. - * + *

* If you invoke {@link #getCause()}, it will lazily create the causal chain but will stop if it finds any * Throwable in the chain that it has already seen. */ @@ -42,9 +42,9 @@ public final class CompositeException extends RuntimeException { private Throwable cause; /** - * Constructs a CompositeException with the given array of Throwables as the + * Constructs a CompositeException with the given array of {@link Throwable}s as the * list of suppressed exceptions. - * @param exceptions the Throwables to have as initially suppressed exceptions + * @param exceptions the {@code Throwable}s to have as initially suppressed exceptions * * @throws IllegalArgumentException if exceptions is empty. */ @@ -54,9 +54,9 @@ public CompositeException(@NonNull Throwable... exceptions) { } /** - * Constructs a CompositeException with the given array of Throwables as the + * Constructs a CompositeException with the given sequence of {@link Throwable}s as the * list of suppressed exceptions. - * @param errors the Throwables to have as initially suppressed exceptions + * @param errors the {@code Throwable}s to have as initially suppressed exceptions * * @throws IllegalArgumentException if errors is empty. */ @@ -64,14 +64,10 @@ public CompositeException(@NonNull Iterable errors) { Set deDupedExceptions = new LinkedHashSet<>(); if (errors != null) { for (Throwable ex : errors) { - if (ex instanceof CompositeException) { - deDupedExceptions.addAll(((CompositeException) ex).getExceptions()); + if (ex instanceof CompositeException ce) { + deDupedExceptions.addAll(ce.getExceptions()); } else - if (ex != null) { - deDupedExceptions.add(ex); - } else { - deDupedExceptions.add(new NullPointerException("Throwable was null!")); - } + deDupedExceptions.add(Objects.requireNonNullElseGet(ex, () -> new NullPointerException("Throwable was null!"))); } } else { deDupedExceptions.add(new NullPointerException("errors was null")); @@ -104,7 +100,7 @@ public String getMessage() { @NonNull public synchronized Throwable getCause() { // NOPMD if (cause == null) { - String separator = System.getProperty("line.separator"); + String separator = System.lineSeparator(); if (exceptions.size() > 1) { Map seenCauses = new IdentityHashMap<>(); @@ -164,9 +160,9 @@ public synchronized Throwable getCause() { // NOPMD } /** - * All of the following {@code printStackTrace} functionality is derived from JDK {@link Throwable} + * All the following {@code printStackTrace} functionality is derived from JDK {@link Throwable} * {@code printStackTrace}. In particular, the {@code PrintStreamOrWriter} abstraction is copied wholesale. - * + *

* Changes from the official JDK implementation:

    *
  • no infinite loop detection
  • *
  • smaller critical section holding {@link PrintStream} lock
  • diff --git a/src/main/java/io/reactivex/rxjava4/exceptions/Exceptions.java b/src/main/java/io/reactivex/rxjava4/exceptions/Exceptions.java index e112cd27da8..91eb82c245a 100644 --- a/src/main/java/io/reactivex/rxjava4/exceptions/Exceptions.java +++ b/src/main/java/io/reactivex/rxjava4/exceptions/Exceptions.java @@ -55,9 +55,9 @@ public static RuntimeException propagate(@NonNull Throwable t) { *
  • {@code LinkageError}
  • *
* This can be useful if you are writing an operator that calls user-supplied code, and you want to - * notify subscribers of errors encountered in that code by calling their {@code onError} methods, but only - * if the errors are not so catastrophic that such a call would be futile, in which case you simply want to - * rethrow the error. + * notify subscribers of errors encountered in that code by calling their {@code onError} methods. + * But only if the errors are not so catastrophic that such a call would be futile, in which case + * you simply want to rethrow the error. * * @param t * the {@code Throwable} to test and perhaps throw diff --git a/src/main/java/io/reactivex/rxjava4/exceptions/OnErrorNotImplementedException.java b/src/main/java/io/reactivex/rxjava4/exceptions/OnErrorNotImplementedException.java index 4f0463332db..29a819a660a 100644 --- a/src/main/java/io/reactivex/rxjava4/exceptions/OnErrorNotImplementedException.java +++ b/src/main/java/io/reactivex/rxjava4/exceptions/OnErrorNotImplementedException.java @@ -31,7 +31,7 @@ public final class OnErrorNotImplementedException extends RuntimeException { /** * Customizes the {@code Throwable} with a custom message and wraps it before it - * is signalled to the {@code RxJavaPlugins.onError()} handler as {@code OnErrorNotImplementedException}. + * is signaled to the {@code RxJavaPlugins.onError()} handler as {@code OnErrorNotImplementedException}. * * @param message * the message to assign to the {@code Throwable} to signal @@ -44,7 +44,7 @@ public OnErrorNotImplementedException(String message, @NonNull Throwable e) { /** * Wraps the {@code Throwable} before it - * is signalled to the {@code RxJavaPlugins.onError()} + * is signaled to the {@code RxJavaPlugins.onError()} * handler as {@code OnErrorNotImplementedException}. * * @param e diff --git a/src/main/java/io/reactivex/rxjava4/flowables/ConnectableFlowable.java b/src/main/java/io/reactivex/rxjava4/flowables/ConnectableFlowable.java index f64042f20ac..30e403f80d5 100644 --- a/src/main/java/io/reactivex/rxjava4/flowables/ConnectableFlowable.java +++ b/src/main/java/io/reactivex/rxjava4/flowables/ConnectableFlowable.java @@ -44,8 +44,8 @@ * {@code reset()} in this case. *

* Note that although {@link #connect()} and {@link #reset()} are safe to call from multiple threads, it is recommended - * a dedicated thread or business logic manages the connection or resetting of a {@code ConnectableFlowable} so that - * there is no unwanted signal loss due to early {@code connect()} or {@code reset()} calls while {@code Subscriber}s are + * a dedicated thread or business logic manages the connection or resetting of a {@code ConnectableFlowable}. + * This ensures there is no unwanted signal loss due to early {@code connect()} or {@code reset()} calls while {@code Subscriber}s are * still being subscribed to this {@code ConnectableFlowable} to receive signals from the get-go. *

* @see RxJava Wiki: Connectable Observable Operators @@ -279,7 +279,7 @@ public final Flowable refCount(int subscriberCount, long timeout, @NonNull Ti * during the lifetime of the returned {@code Flowable}. If this {@code ConnectableFlowable} * terminates, the connection is never renewed, no matter how {@code Subscriber}s come * and go. Use {@link #refCount()} to renew a connection or dispose an active - * connection when all {@code Subscriber}s have cancelled their {@link Subscription}s. + * connection when all {@code Subscriber}s have canceled their {@link Subscription}s. *

* This overload does not allow disconnecting the connection established via * {@link #connect(Consumer)}. Use the {@link #autoConnect(int, Consumer)} overload @@ -314,7 +314,7 @@ public Flowable autoConnect() { * during the lifetime of the returned {@code Flowable}. If this {@code ConnectableFlowable} * terminates, the connection is never renewed, no matter how {@code Subscriber}s come * and go. Use {@link #refCount()} to renew a connection or dispose an active - * connection when all {@code Subscriber}s have cancelled their {@link Subscription}s. + * connection when all {@code Subscriber}s have canceled their {@link Subscription}s. *

* This overload does not allow disconnecting the connection established via * {@link #connect(Consumer)}. Use the {@link #autoConnect(int, Consumer)} overload @@ -352,7 +352,7 @@ public Flowable autoConnect(int numberOfSubscribers) { * during the lifetime of the returned {@code Flowable}. If this {@code ConnectableFlowable} * terminates, the connection is never renewed, no matter how {@code Subscriber}s come * and go. Use {@link #refCount()} to renew a connection or dispose an active - * connection when all {@code Subscriber}s have cancelled their {@link Subscription}s. + * connection when all {@code Subscriber}s have canceled their {@link Subscription}s. *

*
Backpressure:
*
The operator itself doesn't interfere with backpressure which is determined by diff --git a/src/main/java/io/reactivex/rxjava4/internal/operators/maybe/MaybeMergeArray.java b/src/main/java/io/reactivex/rxjava4/internal/operators/maybe/MaybeMergeArray.java index f41c80cdda5..f8765c79edd 100644 --- a/src/main/java/io/reactivex/rxjava4/internal/operators/maybe/MaybeMergeArray.java +++ b/src/main/java/io/reactivex/rxjava4/internal/operators/maybe/MaybeMergeArray.java @@ -388,7 +388,7 @@ public boolean isEmpty() { @Override public void clear() { - while (poll() != null && !isEmpty()) { } + while (poll() != null && !isEmpty()) { Thread.onSpinWait(); } } @Override diff --git a/src/main/java/io/reactivex/rxjava4/internal/queue/MpscLinkedQueue.java b/src/main/java/io/reactivex/rxjava4/internal/queue/MpscLinkedQueue.java index 4bfb72bc232..66a020c7848 100644 --- a/src/main/java/io/reactivex/rxjava4/internal/queue/MpscLinkedQueue.java +++ b/src/main/java/io/reactivex/rxjava4/internal/queue/MpscLinkedQueue.java @@ -98,7 +98,7 @@ public T poll() { } else if (currConsumerNode != lvProducerNode()) { // spin, we are no longer wait free - while ((nextNode = currConsumerNode.lvNext()) == null) { } // NOPMD + while ((nextNode = currConsumerNode.lvNext()) == null) { Thread.onSpinWait(); } // NOPMD // got the next node... // we have to null out the value because we are going to hang on to the node @@ -120,7 +120,7 @@ public boolean offer(T v1, T v2) { @Override public void clear() { - while (poll() != null && !isEmpty()) { } // NOPMD + while (poll() != null && !isEmpty()) { Thread.onSpinWait(); } // NOPMD } LinkedQueueNode lvProducerNode() { return producerNode.get(); diff --git a/src/main/java/io/reactivex/rxjava4/internal/schedulers/BlockingCurrentThreadScheduler.java b/src/main/java/io/reactivex/rxjava4/internal/schedulers/BlockingCurrentThreadScheduler.java index 8bcee2a1816..8bfa154b523 100644 --- a/src/main/java/io/reactivex/rxjava4/internal/schedulers/BlockingCurrentThreadScheduler.java +++ b/src/main/java/io/reactivex/rxjava4/internal/schedulers/BlockingCurrentThreadScheduler.java @@ -259,7 +259,7 @@ public void run() throws Exception { } } } finally { - while (get() == INTERRUPTING) { } + while (get() == INTERRUPTING) { Thread.onSpinWait(); } if (get() == INTERRUPTED) { Thread.interrupted(); @@ -385,7 +385,7 @@ public void run() throws Exception { } } } finally { - while (get() == INTERRUPTING) { } + while (get() == INTERRUPTING) { Thread.onSpinWait(); } if (get() == INTERRUPTED) { Thread.interrupted(); diff --git a/src/main/java/io/reactivex/rxjava4/internal/subscriptions/EmptySubscription.java b/src/main/java/io/reactivex/rxjava4/internal/subscriptions/EmptySubscription.java index cf83a759f1c..09f6d26db68 100644 --- a/src/main/java/io/reactivex/rxjava4/internal/subscriptions/EmptySubscription.java +++ b/src/main/java/io/reactivex/rxjava4/internal/subscriptions/EmptySubscription.java @@ -87,7 +87,8 @@ public void clear() { @Override public int requestFusion(int mode) { - return mode & ASYNC; // accept async mode: an onComplete or onError will be signalled after anyway + // accept async mode: an onComplete or onError will be signaled after anyway + return mode & ASYNC; } @Override diff --git a/src/main/java/io/reactivex/rxjava4/internal/util/OpenHashSet.java b/src/main/java/io/reactivex/rxjava4/internal/util/OpenHashSet.java index 8b2f6bb2f5f..58607f6170f 100644 --- a/src/main/java/io/reactivex/rxjava4/internal/util/OpenHashSet.java +++ b/src/main/java/io/reactivex/rxjava4/internal/util/OpenHashSet.java @@ -171,4 +171,4 @@ public Object[] keys() { public int size() { return size; } -} +} \ No newline at end of file diff --git a/src/main/java/io/reactivex/rxjava4/observables/ConnectableObservable.java b/src/main/java/io/reactivex/rxjava4/observables/ConnectableObservable.java index 8c4948f2e9d..161032ca0ca 100644 --- a/src/main/java/io/reactivex/rxjava4/observables/ConnectableObservable.java +++ b/src/main/java/io/reactivex/rxjava4/observables/ConnectableObservable.java @@ -42,8 +42,8 @@ * {@link #reset()} in this case. *

* Note that although {@link #connect()} and {@link #reset()} are safe to call from multiple threads, it is recommended - * a dedicated thread or business logic manages the connection or resetting of a {@code ConnectableObservable} so that - * there is no unwanted signal loss due to early {@code connect()} or {@code reset()} calls while {@code Observer}s are + * a dedicated thread or business logic manages the connection or resetting of a {@code ConnectableObservable}. + * This ensures there is no unwanted signal loss due to early {@code connect()} or {@code reset()} calls while {@code Observer}s are * still being subscribed to this {@code ConnectableObservable} to receive signals from the get-go. * * @see RxJava Wiki: Connectable Observable Operators diff --git a/src/main/java/io/reactivex/rxjava4/observers/SafeObserver.java b/src/main/java/io/reactivex/rxjava4/observers/SafeObserver.java index 99f946ba778..accfcd5d575 100644 --- a/src/main/java/io/reactivex/rxjava4/observers/SafeObserver.java +++ b/src/main/java/io/reactivex/rxjava4/observers/SafeObserver.java @@ -116,23 +116,7 @@ public void onNext(@NonNull T t) { void onNextNoSubscription() { done = true; - Throwable ex = new NullPointerException("Subscription not set!"); - - try { - downstream.onSubscribe(EmptyDisposable.INSTANCE); - } catch (Throwable e) { - Exceptions.throwIfFatal(e); - // can't call onError because the actual's state may be corrupt at this point - RxJavaPlugins.onError(new CompositeException(ex, e)); - return; - } - try { - downstream.onError(ex); - } catch (Throwable e) { - Exceptions.throwIfFatal(e); - // if onError failed, all that's left is to report the error to plugins - RxJavaPlugins.onError(new CompositeException(ex, e)); - } + onCompleteNoSubscription(); } @Override @@ -200,7 +184,7 @@ public void onComplete() { void onCompleteNoSubscription() { - Throwable ex = new NullPointerException("Subscription not set!"); + var ex = new NullPointerException("Subscription not set!"); try { downstream.onSubscribe(EmptyDisposable.INSTANCE); diff --git a/src/main/java/io/reactivex/rxjava4/operators/SimpleQueue.java b/src/main/java/io/reactivex/rxjava4/operators/SimpleQueue.java index e75e754f4f4..5419457af2e 100644 --- a/src/main/java/io/reactivex/rxjava4/operators/SimpleQueue.java +++ b/src/main/java/io/reactivex/rxjava4/operators/SimpleQueue.java @@ -31,7 +31,7 @@ public interface SimpleQueue<@NonNull T> { * Atomically enqueue a single value. * @param value the value to enqueue, not null * @return true if successful, false if the value was not enqueued - * likely due to reaching the queue capacity) + * likely due to reaching the queue capacity */ boolean offer(@NonNull T value); @@ -40,7 +40,7 @@ public interface SimpleQueue<@NonNull T> { * @param v1 the first value to enqueue, not null * @param v2 the second value to enqueue, not null * @return true if successful, false if the value was not enqueued - * likely due to reaching the queue capacity) + * likely due to reaching the queue capacity */ boolean offer(@NonNull T v1, @NonNull T v2); diff --git a/src/main/java/io/reactivex/rxjava4/operators/SpscArrayQueue.java b/src/main/java/io/reactivex/rxjava4/operators/SpscArrayQueue.java index a0fba6ab154..6708aa77187 100644 --- a/src/main/java/io/reactivex/rxjava4/operators/SpscArrayQueue.java +++ b/src/main/java/io/reactivex/rxjava4/operators/SpscArrayQueue.java @@ -30,8 +30,8 @@ * This implementation is a mashup of the Fast Flow * algorithm with an optimization of the offer method taken from the BQueue algorithm (a variation on Fast - * Flow), and adjusted to comply with Queue.offer semantics regarding capacity.
- * For convenience the relevant papers are available in the resources folder:
+ * Flow), and adjusted to comply with {@link java.util.Queue#offer(Object)} semantics regarding capacity.
+ * For convenience the relevant papers are available in the {@code resources} folder:
* 2010 - Pisa - SPSC Queues on Shared Cache Multi-Core Systems.pdf
* 2012 - Junchang- BQueue- Efficient and Practical Queuing.pdf
*
This implementation is wait free. @@ -122,7 +122,9 @@ void soConsumerIndex(long newIndex) { @Override public void clear() { // we have to test isEmpty because of the weaker poll() guarantee - while (poll() != null || !isEmpty()) { } // NOPMD + while (poll() != null || !isEmpty()) { + Thread.onSpinWait(); + } // NOPMD } int calcElementOffset(long index, int mask) { diff --git a/src/main/java/io/reactivex/rxjava4/operators/SpscLinkedArrayQueue.java b/src/main/java/io/reactivex/rxjava4/operators/SpscLinkedArrayQueue.java index b83538225d4..d42521b5bb5 100644 --- a/src/main/java/io/reactivex/rxjava4/operators/SpscLinkedArrayQueue.java +++ b/src/main/java/io/reactivex/rxjava4/operators/SpscLinkedArrayQueue.java @@ -194,7 +194,9 @@ private T newBufferPeek(AtomicReferenceArray nextBuffer, final long inde @Override public void clear() { - while (poll() != null || !isEmpty()) { } // NOPMD + while (poll() != null || !isEmpty()) { + Thread.onSpinWait(); + } // NOPMD } /** diff --git a/src/test/java/io/reactivex/rxjava4/flowable/FlowableCovarianceTest.java b/src/test/java/io/reactivex/rxjava4/flowable/FlowableCovarianceTest.java index 4331b19dfb7..340c71e07e9 100644 --- a/src/test/java/io/reactivex/rxjava4/flowable/FlowableCovarianceTest.java +++ b/src/test/java/io/reactivex/rxjava4/flowable/FlowableCovarianceTest.java @@ -27,8 +27,8 @@ /** * Test super/extends of generics. - * - * See https://github.com/Netflix/RxJava/pull/331 + *

+ * See ... */ public class FlowableCovarianceTest extends RxJavaTest { diff --git a/src/test/java/io/reactivex/rxjava4/flowable/FlowableReduceTests.java b/src/test/java/io/reactivex/rxjava4/flowable/FlowableReduceTests.java index 446a5fa2b03..94effe73b5d 100644 --- a/src/test/java/io/reactivex/rxjava4/flowable/FlowableReduceTests.java +++ b/src/test/java/io/reactivex/rxjava4/flowable/FlowableReduceTests.java @@ -44,8 +44,8 @@ public void reduceWithObjectsFlowable() { /** * Reduce consumes and produces T so can't do covariance. - * - * https://github.com/ReactiveX/RxJava/issues/360#issuecomment-24203016 + *

+ * ... */ @Test public void reduceWithCovariantObjectsFlowable() { @@ -78,8 +78,8 @@ public void reduceWithObjects() { /** * Reduce consumes and produces T so can't do covariance. - * - * https://github.com/ReactiveX/RxJava/issues/360#issuecomment-24203016 + *

+ * ... */ @Test public void reduceWithCovariantObjects() { @@ -92,8 +92,8 @@ public void reduceWithCovariantObjects() { /** * Reduce consumes and produces T so can't do covariance. - * - * https://github.com/ReactiveX/RxJava/issues/360#issuecomment-24203016 + *

+ * ... */ @Test public void reduceCovariance() { diff --git a/src/test/java/io/reactivex/rxjava4/flowable/FlowableTests.java b/src/test/java/io/reactivex/rxjava4/flowable/FlowableTests.java index ac2e499e295..3743ba20fa5 100644 --- a/src/test/java/io/reactivex/rxjava4/flowable/FlowableTests.java +++ b/src/test/java/io/reactivex/rxjava4/flowable/FlowableTests.java @@ -265,8 +265,8 @@ public void reduceWithEmptyObservable() { /** * 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 + *

+ * This is confirmed at ... */ @Test public void reduceWithEmptyObservableAndSeed() { @@ -304,9 +304,9 @@ public void materializeDematerializeChaining() { /** * 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 */ @@ -356,7 +356,7 @@ public void onNext(String v) { /** * The error from the user provided Observer is handled by the subscribe try/catch because this is synchronous. - * + *

* Result: Passes */ @Test @@ -398,7 +398,7 @@ public void onNext(String v) { /** * The error from the user provided Observable is handled by the subscribe try/catch because this is synchronous. - * + *

* Result: Passes */ @Test diff --git a/src/test/java/io/reactivex/rxjava4/flowable/FlowableZipTests.java b/src/test/java/io/reactivex/rxjava4/flowable/FlowableZipTests.java index 141d3647e0b..7a3e280e38c 100644 --- a/src/test/java/io/reactivex/rxjava4/flowable/FlowableZipTests.java +++ b/src/test/java/io/reactivex/rxjava4/flowable/FlowableZipTests.java @@ -69,7 +69,7 @@ public void covarianceOfZip() { /** * Occasionally zip may be invoked with 0 observables. Test that we don't block indefinitely instead * of immediately invoking zip with 0 argument. - * + *

* We now expect an NoSuchElementException since last() requires at least one value and nothing will be emitted. */ @Test(expected = NoSuchElementException.class) diff --git a/src/test/java/io/reactivex/rxjava4/internal/jdk8/FlowableFromStreamTest.java b/src/test/java/io/reactivex/rxjava4/internal/jdk8/FlowableFromStreamTest.java index 660811d6ad7..8b20cefa23b 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/jdk8/FlowableFromStreamTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/jdk8/FlowableFromStreamTest.java @@ -416,13 +416,13 @@ public void onNext(Integer t) { AtomicInteger sync = new AtomicInteger(2); exec.submit(() -> { if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } upstream.request(1); }); if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } } @@ -496,7 +496,7 @@ public void closeCalledOnCancel() { public void closeCalledOnItemCrash() { AtomicInteger calls = new AtomicInteger(); AtomicInteger counter = new AtomicInteger(); - Flowable.fromStream(Stream.generate(() -> { + Flowable.fromStream(Stream.generate(() -> { int value = counter.getAndIncrement(); if (value == 1) { throw new TestException(); @@ -538,7 +538,7 @@ public void closeCalledOnCancelConditional() { public void closeCalledOnItemCrashConditional() { AtomicInteger calls = new AtomicInteger(); AtomicInteger counter = new AtomicInteger(); - Flowable.fromStream(Stream.generate(() -> { + Flowable.fromStream(Stream.generate(() -> { int value = counter.getAndIncrement(); if (value == 1) { throw new TestException(); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableBlockingTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableBlockingTest.java index b341f53fd0c..42972e7f16d 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableBlockingTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableBlockingTest.java @@ -298,7 +298,7 @@ public void blockingLastNormal() { } @Test - public void firstFgnoredCancelAndOnNext() { + public void firstIgnoredCancelAndOnNext() { Flowable source = Flowable.fromPublisher(s -> { s.onSubscribe(new BooleanSubscription()); s.onNext(1); @@ -407,7 +407,7 @@ protected void subscribeActual(Subscriber subscriber) { } @Test - public void blockinsSubscribeCancelAsync() { + public void blockingSubscribeCancelAsync() { for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { final TestSubscriber ts = new TestSubscriber<>(); @@ -421,13 +421,13 @@ public void blockinsSubscribeCancelAsync() { Schedulers.computation().scheduleDirect(() -> { c.decrementAndGet(); - while (c.get() != 0 && !pp.hasSubscribers()) { } + while (c.get() != 0 && !pp.hasSubscribers()) { Thread.onSpinWait(); } TestHelper.race(r1, r2); }); c.decrementAndGet(); - while (c.get() != 0) { } + while (c.get() != 0) { Thread.onSpinWait(); } pp .blockingSubscribe(ts); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableGroupByTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableGroupByTest.java index e26e5f70d2e..eb6e316f0d7 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableGroupByTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableGroupByTest.java @@ -985,12 +985,12 @@ public void onNext(Integer t) { /** * Issue #3425. - * + *

* The problem is that a request of 1 may create a new group, emit to the desired group * or emit to a completely different group. In this test, the merge requests N which * must be produced by the range, however it will create a bunch of groups before the actual * group receives a value. - * + *

* 12/03/2019: this test produces abandoned groups and as such keeps producing new groups * that have to be ready to be received by observeOn and merge. */ diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeTest.java index 482206e9419..e48ec8193a3 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeTest.java @@ -681,7 +681,7 @@ public void onNext(Integer t) { /** * This is the same as the upstreams ones, but now adds the downstream as well by using observeOn. - * + *

* This requires merge to also obey the {@link Subscription#request(long)} values coming from it's child subscriber. * @throws InterruptedException if the test is interrupted */ @@ -760,10 +760,10 @@ public void onNext(Integer t) { /** * Currently there is no solution to this ... we can't exert backpressure on the outer Flowable if we * can't know if the ones we've received so far are going to emit or not, otherwise we could starve the system. - * + *

* For example, 10,000 Flowables are being merged (bad use case to begin with, but ...) and it's only one of them * that will ever emit. If backpressure only allowed the first 1,000 to be sent, we would hang and never receive an event. - * + *

* Thus, we must allow all Flowables to be sent. The ScalarSynchronousFlowable use case is an exception to this since * we can grab the value synchronously. * diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableObserveOnTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableObserveOnTest.java index 2e178a9e07a..164971422dc 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableObserveOnTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableObserveOnTest.java @@ -228,7 +228,7 @@ public void observeOnWithThreadPoolScheduler() { * Attempts to confirm that when pauses exist between events, the ScheduledObserver * does not lose or reorder any events since the scheduler will not block, but will * be re-scheduled when it receives new events after each pause. - * + *

* * This is non-deterministic in proving success, but if it ever fails (non-deterministically) * it is a sign of potential issues as thread-races and scheduling should not affect output. @@ -509,12 +509,8 @@ public void onNext(Integer t) { assertEquals(1, errors.size()); System.out.println("Errors: " + errors); Throwable t = errors.getFirst(); - if (t instanceof QueueOverflowException) { - // success, we expect this - } else { - if (t.getCause() instanceof QueueOverflowException) { - // this is also okay - } else { + if (!(t instanceof QueueOverflowException)) { + if (!(t.getCause() instanceof QueueOverflowException)) { fail("Expecting QueueOverflowException"); } } @@ -534,7 +530,7 @@ public void onErrorCutsAheadOfOnNext() { final PublishProcessor processor = PublishProcessor.create(); final AtomicLong counter = new AtomicLong(); - TestSubscriberEx ts = new TestSubscriberEx<>(new DefaultSubscriber() /* NFI */ { + var ts = new TestSubscriberEx<>(new DefaultSubscriber() /* NFI */ { @Override public void onComplete() { diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReduceTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReduceTest.java index 2beee220680..a0edd4d9680 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReduceTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReduceTest.java @@ -313,7 +313,7 @@ public void reducerThrows() { /** * Make sure an asynchronous reduce with flatMap works. - * Original Reactor-Core test case: https://gist.github.com/jurna/353a2bd8ff83f0b24f0b5bc772077d61 + * Original Reactor-Core test case: ... */ @Test public void shouldReduceTo10Events() { @@ -335,7 +335,7 @@ public void shouldReduceTo10Events() { /** * Make sure an asynchronous reduce with flatMap works. - * Original Reactor-Core test case: https://gist.github.com/jurna/353a2bd8ff83f0b24f0b5bc772077d61 + * Original Reactor-Core test case: ... */ @Test public void shouldReduceTo10EventsFlowable() { diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableMergeTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableMergeTest.java index 0542ea12f42..dcfb284f787 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableMergeTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableMergeTest.java @@ -664,7 +664,7 @@ public void onNext(Integer t) { /** * This is the same as the upstreams ones, but now adds the downstream as well by using observeOn. - * + *

* This requires merge to also obey the {@link java.util.concurrent.Flow.Subscription#request(long)} values coming from its child Observer. * @throws InterruptedException if the test is interrupted */ @@ -711,10 +711,10 @@ public void onNext(Integer t) { /** * Currently there is no solution to this ... we can't exert backpressure on the outer Observable if we * can't know if the ones we've received so far are going to emit or not, otherwise we could starve the system. - * + *

* For example, 10,000 Observables are being merged (bad use case to begin with, but ...) and it's only one of them * that will ever emit. If backpressure only allowed the first 1,000 to be sent, we would hang and never receive an event. - * + *

* Thus, we must allow all Observables to be sent. The ScalarSynchronousObservable use case is an exception to this since * we can grab the value synchronously. * diff --git a/src/test/java/io/reactivex/rxjava4/internal/schedulers/ScheduledRunnableTest.java b/src/test/java/io/reactivex/rxjava4/internal/schedulers/ScheduledRunnableTest.java index 4a71677b085..a33bf34a57f 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/schedulers/ScheduledRunnableTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/schedulers/ScheduledRunnableTest.java @@ -247,10 +247,10 @@ public void syncWorkerCancelRace() { Runnable r0 = () -> { set.dispose(); if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } if (syncb.decrementAndGet() != 0) { - while (syncb.get() != 0) { } + while (syncb.get() != 0) { Thread.onSpinWait(); } } for (int j = 0; j < 1000; j++) { if (Thread.currentThread().isInterrupted()) { @@ -267,11 +267,11 @@ public void syncWorkerCancelRace() { Runnable r2 = () -> { if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } run.setFuture(ft); if (syncb.decrementAndGet() != 0) { - while (syncb.get() != 0) { } + while (syncb.get() != 0) { Thread.onSpinWait(); } } }; diff --git a/src/test/java/io/reactivex/rxjava4/internal/schedulers/TrampolineSchedulerInternalTest.java b/src/test/java/io/reactivex/rxjava4/internal/schedulers/TrampolineSchedulerInternalTest.java index 799fac8907f..61f0c9ec998 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/schedulers/TrampolineSchedulerInternalTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/schedulers/TrampolineSchedulerInternalTest.java @@ -187,12 +187,12 @@ public void submitAndDisposeNextTask() { Schedulers.single().scheduleDirect(() -> { if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } d.dispose(); }); if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } }); } diff --git a/src/test/java/io/reactivex/rxjava4/internal/subscribers/DeferredScalarSubscriberTest.java b/src/test/java/io/reactivex/rxjava4/internal/subscribers/DeferredScalarSubscriberTest.java index 347fb752664..6d4582d9518 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/subscribers/DeferredScalarSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/subscribers/DeferredScalarSubscriberTest.java @@ -317,13 +317,13 @@ public void emissionRequestRace() { w.schedule(() -> { ready.decrementAndGet(); - while (ready.get() != 0) { } + while (ready.get() != 0) { Thread.onSpinWait(); } ts.request(1); }); ready.decrementAndGet(); - while (ready.get() != 0) { } + while (ready.get() != 0) { Thread.onSpinWait(); } ds.onComplete(); @@ -358,20 +358,20 @@ public void emissionRequestRace2() { w.schedule(() -> { ready.decrementAndGet(); - while (ready.get() != 0) { } + while (ready.get() != 0) { Thread.onSpinWait(); } ts.request(1); }); w2.schedule(() -> { ready.decrementAndGet(); - while (ready.get() != 0) { } + while (ready.get() != 0) { Thread.onSpinWait(); } ts.request(1); }); ready.decrementAndGet(); - while (ready.get() != 0) { } + while (ready.get() != 0) { Thread.onSpinWait(); } ds.onComplete(); diff --git a/src/test/java/io/reactivex/rxjava4/internal/util/OperatorMatrixGenerator.java b/src/test/java/io/reactivex/rxjava4/internal/util/OperatorMatrixGenerator.java index 900458d6b2e..e35d8e81151 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/util/OperatorMatrixGenerator.java +++ b/src/test/java/io/reactivex/rxjava4/internal/util/OperatorMatrixGenerator.java @@ -23,7 +23,7 @@ /** * Generate a table of available operators across base classes in {@code Operator-Matrix.md}. - * + *

* Should be run with the main project directory as working directory where the {@code docs} * folder is. */ diff --git a/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualResumableTest.java b/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualResumableTest.java index ff3aae6835d..d2db18f50fc 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualResumableTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualResumableTest.java @@ -47,7 +47,7 @@ public void concurrentAwait() { var t = new Thread(ready1::await); t.start(); - while (ready1.get() == null) { } + while (ready1.get() == null) { Thread.onSpinWait(); } try { ready1.await(); } catch (IllegalStateException ex) { diff --git a/src/test/java/io/reactivex/rxjava4/observable/ObservableCovarianceTest.java b/src/test/java/io/reactivex/rxjava4/observable/ObservableCovarianceTest.java index c6334ec01b3..1a7994b9279 100644 --- a/src/test/java/io/reactivex/rxjava4/observable/ObservableCovarianceTest.java +++ b/src/test/java/io/reactivex/rxjava4/observable/ObservableCovarianceTest.java @@ -27,8 +27,8 @@ /** * Test super/extends of generics. - * - * See https://github.com/Netflix/RxJava/pull/331 + *

+ * See ... */ public class ObservableCovarianceTest extends RxJavaTest { diff --git a/src/test/java/io/reactivex/rxjava4/observable/ObservableReduceTests.java b/src/test/java/io/reactivex/rxjava4/observable/ObservableReduceTests.java index 94ca03792ca..52e7b739c51 100644 --- a/src/test/java/io/reactivex/rxjava4/observable/ObservableReduceTests.java +++ b/src/test/java/io/reactivex/rxjava4/observable/ObservableReduceTests.java @@ -44,8 +44,8 @@ public void reduceWithObjectsObservable() { /** * Reduce consumes and produces T so can't do covariance. - * - * https://github.com/ReactiveX/RxJava/issues/360#issuecomment-24203016 + *

+ * ... */ @Test public void reduceWithCovariantObjectsObservable() { @@ -78,8 +78,8 @@ public void reduceWithObjects() { /** * Reduce consumes and produces T so can't do covariance. - * - * https://github.com/ReactiveX/RxJava/issues/360#issuecomment-24203016 + *

+ * ... */ @Test public void reduceWithCovariantObjects() { @@ -92,8 +92,8 @@ public void reduceWithCovariantObjects() { /** * Reduce consumes and produces T so can't do covariance. - * - * https://github.com/ReactiveX/RxJava/issues/360#issuecomment-24203016 + *

+ * ... */ @Test public void reduceCovariance() { diff --git a/src/test/java/io/reactivex/rxjava4/observable/ObservableTest.java b/src/test/java/io/reactivex/rxjava4/observable/ObservableTest.java index 7cf03cb1423..53a30e63b42 100644 --- a/src/test/java/io/reactivex/rxjava4/observable/ObservableTest.java +++ b/src/test/java/io/reactivex/rxjava4/observable/ObservableTest.java @@ -261,8 +261,8 @@ public void reduceWithEmptyObservable() { /** * 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 + *

+ * This is confirmed at ... */ @Test public void reduceWithEmptyObservableAndSeed() { @@ -312,9 +312,9 @@ public void materializeDematerializeChaining() { /** * 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 */ @@ -364,7 +364,7 @@ public void onNext(String v) { /** * The error from the user provided Observer is handled by the subscribe try/catch because this is synchronous. - * + *

* Result: Passes */ @Test @@ -406,7 +406,7 @@ public void onNext(String v) { /** * The error from the user provided Observable is handled by the subscribe try/catch because this is synchronous. - * + *

* * Result: Passes */ diff --git a/src/test/java/io/reactivex/rxjava4/observable/ObservableZipTests.java b/src/test/java/io/reactivex/rxjava4/observable/ObservableZipTests.java index b60348bbda8..712579de5a9 100644 --- a/src/test/java/io/reactivex/rxjava4/observable/ObservableZipTests.java +++ b/src/test/java/io/reactivex/rxjava4/observable/ObservableZipTests.java @@ -74,7 +74,7 @@ public void covarianceOfZip() { /** * Occasionally zip may be invoked with 0 observables. Test that we don't block indefinitely instead * of immediately invoking zip with 0 argument. - * + *

* We now expect an NoSuchElementException since last() requires at least one value and nothing will be emitted. */ @Test(expected = NoSuchElementException.class) diff --git a/src/test/java/io/reactivex/rxjava4/observers/SerializedObserverTest.java b/src/test/java/io/reactivex/rxjava4/observers/SerializedObserverTest.java index 41a715db2d8..a27b04a9119 100644 --- a/src/test/java/io/reactivex/rxjava4/observers/SerializedObserverTest.java +++ b/src/test/java/io/reactivex/rxjava4/observers/SerializedObserverTest.java @@ -336,18 +336,18 @@ public void onNext(String t) { /** * Demonstrates thread starvation problem. - * - * No solution on this for now. Trade-off in this direction as per https://github.com/ReactiveX/RxJava/issues/998#issuecomment-38959474 + *

+ * No solution on this for now. Trade-off in this direction as per ... * Probably need backpressure for this to work - * + *

* When using SynchronizedSubscriber we get this output: - * + *

* {@code p1: 18 p2: 68 =>} should be close to each other unless we have thread starvation - * + *

* When using SerializedObserver we get: - * + *

* {@code p1: 1 p2: 2445261 =>} should be close to each other unless we have thread starvation - * + *

* This demonstrates how SynchronizedSubscriber balances back and forth better, and blocks emission. * The real issue in this example is the async buffer-bloat, so we need backpressure. * diff --git a/src/test/java/io/reactivex/rxjava4/operators/SimpleQueueTest.java b/src/test/java/io/reactivex/rxjava4/operators/SimpleQueueTest.java index a113b76c930..5adea09d297 100644 --- a/src/test/java/io/reactivex/rxjava4/operators/SimpleQueueTest.java +++ b/src/test/java/io/reactivex/rxjava4/operators/SimpleQueueTest.java @@ -117,7 +117,7 @@ public void mpscOfferPollRace() throws Exception { @Override public void run() { c.decrementAndGet(); - while (c.get() != 0) { } + while (c.get() != 0) { Thread.onSpinWait(); } while (i++ < 10000) { q.offer(i); @@ -131,7 +131,7 @@ public void run() { @Override public void run() { c.decrementAndGet(); - while (c.get() != 0) { } + while (c.get() != 0) { Thread.onSpinWait(); } while (i++ < 10000) { q.offer(i); @@ -145,7 +145,7 @@ public void run() { @Override public void run() { c.decrementAndGet(); - while (c.get() != 0) { } + while (c.get() != 0) { Thread.onSpinWait(); } while (--i > 0) { q.poll(); diff --git a/src/test/java/io/reactivex/rxjava4/processors/BehaviorProcessorTest.java b/src/test/java/io/reactivex/rxjava4/processors/BehaviorProcessorTest.java index 9263c9938d3..9bfe4e3aeb2 100644 --- a/src/test/java/io/reactivex/rxjava4/processors/BehaviorProcessorTest.java +++ b/src/test/java/io/reactivex/rxjava4/processors/BehaviorProcessorTest.java @@ -683,7 +683,9 @@ public void offerAsync() throws Exception { } for (int i = 1; i <= 10; i++) { - while (!pp.offer(i)) { } + while (!pp.offer(i)) { + Thread.onSpinWait(); + } } pp.onComplete(); }); @@ -740,7 +742,7 @@ public void subscriberCancelOfferRace() { Runnable r1 = () -> { for (int i1 = 0; i1 < 2; i1++) { - while (!pp.offer(i1)) { } + while (!pp.offer(i1)) { Thread.onSpinWait(); } } }; diff --git a/src/test/java/io/reactivex/rxjava4/processors/PublishProcessorTest.java b/src/test/java/io/reactivex/rxjava4/processors/PublishProcessorTest.java index c6990e10ce8..426bd607daa 100644 --- a/src/test/java/io/reactivex/rxjava4/processors/PublishProcessorTest.java +++ b/src/test/java/io/reactivex/rxjava4/processors/PublishProcessorTest.java @@ -588,7 +588,7 @@ public void offerAsync() throws Exception { } for (int i = 1; i <= 10; i++) { - while (!pp.offer(i)) { } + while (!pp.offer(i)) { Thread.onSpinWait(); } } pp.onComplete(); }); @@ -609,7 +609,7 @@ public void subscriberCancelOfferRace() { Runnable r1 = () -> { for (int i1 = 0; i1 < 2; i1++) { - while (!pp.offer(i1)) { } + while (!pp.offer(i1)) { Thread.onSpinWait(); } } }; diff --git a/src/test/java/io/reactivex/rxjava4/processors/ReplayProcessorBoundedConcurrencyTest.java b/src/test/java/io/reactivex/rxjava4/processors/ReplayProcessorBoundedConcurrencyTest.java index 5682ba5d0d6..f4bde664883 100644 --- a/src/test/java/io/reactivex/rxjava4/processors/ReplayProcessorBoundedConcurrencyTest.java +++ b/src/test/java/io/reactivex/rxjava4/processors/ReplayProcessorBoundedConcurrencyTest.java @@ -244,7 +244,7 @@ public void subscribeCompletionRaceCondition() { /** * Make sure emission-subscription races are handled correctly. - * https://github.com/ReactiveX/RxJava/issues/1147 + * ... */ @Test public void raceForTerminalState() { diff --git a/src/test/java/io/reactivex/rxjava4/processors/ReplayProcessorConcurrencyTest.java b/src/test/java/io/reactivex/rxjava4/processors/ReplayProcessorConcurrencyTest.java index b5d5cef41f6..8a0abeb8182 100644 --- a/src/test/java/io/reactivex/rxjava4/processors/ReplayProcessorConcurrencyTest.java +++ b/src/test/java/io/reactivex/rxjava4/processors/ReplayProcessorConcurrencyTest.java @@ -244,7 +244,7 @@ public void subscribeCompletionRaceCondition() { /** * Make sure emission-subscription races are handled correctly. - * https://github.com/ReactiveX/RxJava/issues/1147 + * ... */ @Test public void raceForTerminalState() { diff --git a/src/test/java/io/reactivex/rxjava4/schedulers/AbstractSchedulerConcurrencyTests.java b/src/test/java/io/reactivex/rxjava4/schedulers/AbstractSchedulerConcurrencyTests.java index d2c99bf76d9..276b9a648fb 100644 --- a/src/test/java/io/reactivex/rxjava4/schedulers/AbstractSchedulerConcurrencyTests.java +++ b/src/test/java/io/reactivex/rxjava4/schedulers/AbstractSchedulerConcurrencyTests.java @@ -27,16 +27,16 @@ /** * Base tests for schedulers that involve threads (concurrency). - * + *

* These can only run on Schedulers that launch threads since they expect async/concurrent behavior. - * + *

* The Current/Immediate schedulers will not work with these tests. */ public abstract class AbstractSchedulerConcurrencyTests extends AbstractSchedulerTests { /** * Make sure canceling through {@code subscribeOn} works. - * Bug report: https://github.com/ReactiveX/RxJava/issues/431 + * Bug report: ... * @throws InterruptedException if the test is interrupted */ @Test diff --git a/src/test/java/io/reactivex/rxjava4/schedulers/ExecutorSchedulerFairTest.java b/src/test/java/io/reactivex/rxjava4/schedulers/ExecutorSchedulerFairTest.java index adb8a707733..d7fd0ed6458 100644 --- a/src/test/java/io/reactivex/rxjava4/schedulers/ExecutorSchedulerFairTest.java +++ b/src/test/java/io/reactivex/rxjava4/schedulers/ExecutorSchedulerFairTest.java @@ -276,11 +276,11 @@ public void disposeRace() { w.schedule(() -> { c.decrementAndGet(); - while (c.get() != 0) { } + while (c.get() != 0) { Thread.onSpinWait(); } }); c.decrementAndGet(); - while (c.get() != 0) { } + while (c.get() != 0) { Thread.onSpinWait(); } w.dispose(); } } finally { diff --git a/src/test/java/io/reactivex/rxjava4/schedulers/ExecutorSchedulerInterruptibleTest.java b/src/test/java/io/reactivex/rxjava4/schedulers/ExecutorSchedulerInterruptibleTest.java index b37c48169a4..568abfe6897 100644 --- a/src/test/java/io/reactivex/rxjava4/schedulers/ExecutorSchedulerInterruptibleTest.java +++ b/src/test/java/io/reactivex/rxjava4/schedulers/ExecutorSchedulerInterruptibleTest.java @@ -273,11 +273,11 @@ public void disposeRace() { w.schedule(() -> { c.decrementAndGet(); - while (c.get() != 0) { } + while (c.get() != 0) { Thread.onSpinWait(); } }); c.decrementAndGet(); - while (c.get() != 0) { } + while (c.get() != 0) { Thread.onSpinWait(); } w.dispose(); } } finally { @@ -373,7 +373,7 @@ public void interruptibleDirectTask() throws Exception { Disposable d = scheduler.scheduleDirect(() -> { if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } try { Thread.sleep(1000); @@ -383,7 +383,7 @@ public void interruptibleDirectTask() throws Exception { }); if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } Thread.sleep(500); @@ -411,7 +411,7 @@ public void interruptibleWorkerTask() throws Exception { Disposable d = worker.schedule(() -> { if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } try { Thread.sleep(1000); @@ -421,7 +421,7 @@ public void interruptibleWorkerTask() throws Exception { }); if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } Thread.sleep(500); @@ -451,7 +451,7 @@ public void interruptibleDirectTaskScheduledExecutor() throws Exception { Disposable d = scheduler.scheduleDirect(() -> { if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } try { Thread.sleep(1000); @@ -461,7 +461,7 @@ public void interruptibleDirectTaskScheduledExecutor() throws Exception { }); if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } Thread.sleep(500); @@ -494,7 +494,7 @@ public void interruptibleWorkerTaskScheduledExecutor() throws Exception { Disposable d = worker.schedule(() -> { if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } try { Thread.sleep(1000); @@ -504,7 +504,7 @@ public void interruptibleWorkerTaskScheduledExecutor() throws Exception { }); if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } Thread.sleep(500); @@ -537,7 +537,7 @@ public void nonInterruptibleDirectTask() throws Exception { Disposable d = scheduler.scheduleDirect(() -> { if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } try { Thread.sleep(1000); @@ -547,7 +547,7 @@ public void nonInterruptibleDirectTask() throws Exception { }); if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } Thread.sleep(500); @@ -580,7 +580,7 @@ public void nonInterruptibleWorkerTask() throws Exception { Disposable d = worker.schedule(() -> { if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } try { Thread.sleep(1000); @@ -590,7 +590,7 @@ public void nonInterruptibleWorkerTask() throws Exception { }); if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } Thread.sleep(500); @@ -623,7 +623,7 @@ public void nonInterruptibleDirectTaskScheduledExecutor() throws Exception { Disposable d = scheduler.scheduleDirect(() -> { if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } try { Thread.sleep(1000); @@ -633,7 +633,7 @@ public void nonInterruptibleDirectTaskScheduledExecutor() throws Exception { }); if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } Thread.sleep(500); @@ -666,7 +666,7 @@ public void nonInterruptibleWorkerTaskScheduledExecutor() throws Exception { Disposable d = worker.schedule(() -> { if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } try { Thread.sleep(1000); @@ -676,7 +676,7 @@ public void nonInterruptibleWorkerTaskScheduledExecutor() throws Exception { }); if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } Thread.sleep(500); @@ -709,7 +709,7 @@ public void nonInterruptibleDirectTaskTimed() throws Exception { Disposable d = scheduler.scheduleDirect(() -> { if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } try { Thread.sleep(1000); @@ -719,7 +719,7 @@ public void nonInterruptibleDirectTaskTimed() throws Exception { }, 1, TimeUnit.MILLISECONDS); if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } Thread.sleep(500); @@ -752,7 +752,7 @@ public void nonInterruptibleWorkerTaskTimed() throws Exception { Disposable d = worker.schedule(() -> { if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } try { Thread.sleep(1000); @@ -762,7 +762,7 @@ public void nonInterruptibleWorkerTaskTimed() throws Exception { }, 1, TimeUnit.MILLISECONDS); if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } Thread.sleep(500); @@ -795,7 +795,7 @@ public void nonInterruptibleDirectTaskScheduledExecutorTimed() throws Exception Disposable d = scheduler.scheduleDirect(() -> { if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } try { Thread.sleep(1000); @@ -805,7 +805,7 @@ public void nonInterruptibleDirectTaskScheduledExecutorTimed() throws Exception }, 1, TimeUnit.MILLISECONDS); if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } Thread.sleep(500); @@ -838,7 +838,7 @@ public void nonInterruptibleWorkerTaskScheduledExecutorTimed() throws Exception Disposable d = worker.schedule(() -> { if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } try { Thread.sleep(1000); @@ -848,7 +848,7 @@ public void nonInterruptibleWorkerTaskScheduledExecutorTimed() throws Exception }, 1, TimeUnit.MILLISECONDS); if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } Thread.sleep(500); diff --git a/src/test/java/io/reactivex/rxjava4/schedulers/ExecutorSchedulerTest.java b/src/test/java/io/reactivex/rxjava4/schedulers/ExecutorSchedulerTest.java index 2b5fa42e003..abfc9179c43 100644 --- a/src/test/java/io/reactivex/rxjava4/schedulers/ExecutorSchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava4/schedulers/ExecutorSchedulerTest.java @@ -20,6 +20,7 @@ import java.util.concurrent.*; import java.util.concurrent.atomic.*; +import org.jspecify.annotations.NonNull; import org.junit.Test; import io.reactivex.rxjava4.core.Scheduler; @@ -152,7 +153,7 @@ public void cancelledTaskRetention() throws InterruptedException { static final class TestExecutor implements Executor { final ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue<>(); @Override - public void execute(Runnable command) { + public void execute(@NonNull Runnable command) { queue.offer(command); } public void executeOne() { @@ -354,11 +355,11 @@ public void disposeRace() { w.schedule(() -> { c.decrementAndGet(); - while (c.get() != 0) { } + while (c.get() != 0) { Thread.onSpinWait(); } }); c.decrementAndGet(); - while (c.get() != 0) { } + while (c.get() != 0) { Thread.onSpinWait(); } w.dispose(); } } finally { @@ -446,8 +447,7 @@ public void unwrapScheduleDirectTaskAfterDispose() { @Test public void interruptibleRunnableRunDisposeRace() { - ExecutorService exec = Executors.newSingleThreadExecutor(); - try { + try (var exec = Executors.newSingleThreadExecutor()) { Scheduler s = Schedulers.from(exec::execute, true); for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { SequentialDisposable sd = new SequentialDisposable(); @@ -457,8 +457,6 @@ public void interruptibleRunnableRunDisposeRace() { sd::dispose ); } - } finally { - exec.shutdown(); } } diff --git a/src/test/java/io/reactivex/rxjava4/subjects/ReplaySubjectBoundedConcurrencyTest.java b/src/test/java/io/reactivex/rxjava4/subjects/ReplaySubjectBoundedConcurrencyTest.java index 10a5d3a87dc..fa85b4fe3c8 100644 --- a/src/test/java/io/reactivex/rxjava4/subjects/ReplaySubjectBoundedConcurrencyTest.java +++ b/src/test/java/io/reactivex/rxjava4/subjects/ReplaySubjectBoundedConcurrencyTest.java @@ -248,7 +248,7 @@ public void subscribeCompletionRaceCondition() { /** * Make sure emission-subscription races are handled correctly. - * https://github.com/ReactiveX/RxJava/issues/1147 + * ... */ @Test public void raceForTerminalState() { diff --git a/src/test/java/io/reactivex/rxjava4/subjects/ReplaySubjectConcurrencyTest.java b/src/test/java/io/reactivex/rxjava4/subjects/ReplaySubjectConcurrencyTest.java index f6d464afee1..af64e308e64 100644 --- a/src/test/java/io/reactivex/rxjava4/subjects/ReplaySubjectConcurrencyTest.java +++ b/src/test/java/io/reactivex/rxjava4/subjects/ReplaySubjectConcurrencyTest.java @@ -248,7 +248,7 @@ public void subscribeCompletionRaceCondition() { /** * Make sure emission-subscription races are handled correctly. - * https://github.com/ReactiveX/RxJava/issues/1147 + * ... */ @Test public void raceForTerminalState() { diff --git a/src/test/java/io/reactivex/rxjava4/subscribers/SerializedSubscriberTest.java b/src/test/java/io/reactivex/rxjava4/subscribers/SerializedSubscriberTest.java index d8ebb4c7161..45f55fc4b1e 100644 --- a/src/test/java/io/reactivex/rxjava4/subscribers/SerializedSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava4/subscribers/SerializedSubscriberTest.java @@ -337,18 +337,18 @@ public void onNext(String t) { /** * Demonstrates thread starvation problem. - * - * No solution on this for now. Trade-off in this direction as per https://github.com/ReactiveX/RxJava/issues/998#issuecomment-38959474 + *

+ * No solution on this for now. Trade-off in this direction as per ... * Probably need backpressure for this to work - * + *

* When using SynchronizedSubscriber we get this output: - * + *

* {@code p1: 18 p2: 68 =>} should be close to each other unless we have thread starvation - * + *

* When using SerializedSubscriber we get: - * + *

* {@code p1: 1 p2: 2445261 =>} should be close to each other unless we have thread starvation - * + *

* This demonstrates how SynchronizedSubscriber balances back and forth better, and blocks emission. * The real issue in this example is the async buffer-bloat, so we need backpressure. * diff --git a/src/test/java/io/reactivex/rxjava4/subscribers/TestSubscriberTest.java b/src/test/java/io/reactivex/rxjava4/subscribers/TestSubscriberTest.java index fde2ae186ba..59af734a535 100644 --- a/src/test/java/io/reactivex/rxjava4/subscribers/TestSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava4/subscribers/TestSubscriberTest.java @@ -344,7 +344,7 @@ public void multipleErrors4() { ts.onError(new TestException()); ts.onError(new TestException()); try { - ts.assertError(Functions.alwaysTrue()); + ts.assertError(Functions.alwaysTrue()); } catch (AssertionError ex) { Throwable e = ex.getCause(); if (!(e instanceof CompositeException)) { @@ -403,7 +403,7 @@ public void differentError4() { TestSubscriber ts = new TestSubscriber<>(); ts.onError(new RuntimeException()); try { - ts.assertError(Functions.alwaysFalse()); + ts.assertError(Functions.alwaysFalse()); } catch (AssertionError ex) { // expected return; @@ -454,7 +454,7 @@ public void noError2() { public void noError3() { TestSubscriber ts = new TestSubscriber<>(); try { - ts.assertError(Functions.alwaysTrue()); + ts.assertError(Functions.alwaysTrue()); } catch (AssertionError ex) { // expected return; @@ -500,7 +500,7 @@ public void interruptTerminalEventAwaitTimed() { // expected } } finally { - Thread.interrupted(); // clear interrupted flag + IO.println(Thread.interrupted()); // clear flag w.dispose(); } } @@ -648,13 +648,13 @@ public void onComplete() { @Test public void onErrorCrashCountsDownLatch() { - TestSubscriber ts0 = new TestSubscriber() /* NFI */ { + var ts0 = new TestSubscriber() /* NFI */ { @Override public void onError(Throwable e) { throw new TestException(); } }; - TestSubscriber ts = new TestSubscriber<>(ts0); + var ts = new TestSubscriber<>(ts0); try { ts.onError(new RuntimeException()); @@ -732,7 +732,7 @@ public void assertError2() { } try { - ts.assertError(Functions.alwaysTrue()); + ts.assertError(Functions.alwaysTrue()); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected @@ -759,7 +759,7 @@ public void assertError2() { ts.assertError(TestException.class); - ts.assertError(Functions.alwaysTrue()); + ts.assertError(Functions.alwaysTrue()); ts.assertError(t -> t.getMessage() != null && t.getMessage().contains("Forced")); @@ -785,7 +785,7 @@ public void assertError2() { } try { - ts.assertError(Functions.alwaysFalse()); + ts.assertError(Functions.alwaysFalse()); throw new RuntimeException("Should have thrown"); } catch (AssertionError exc) { // expected @@ -1139,7 +1139,7 @@ public void assertValueSequence() { ts.onNext(2); try { - ts.assertValueSequence(Collections.emptyList()); + ts.assertValueSequence(Collections.emptyList()); throw new RuntimeException("Should have thrown"); } catch (AssertionError ex) { // expected @@ -1260,7 +1260,7 @@ public void completeWithoutOnSubscribe() { @Test public void completeDelegateThrows() throws Exception { - TestSubscriber ts = new TestSubscriber<>(new FlowableSubscriber() /* NFI */ { + var ts = new TestSubscriber<>(new FlowableSubscriber() /* NFI */ { @Override public void onSubscribe(Subscription s) { @@ -1296,7 +1296,7 @@ public void onComplete() { @Test public void errorDelegateThrows() throws Exception { - TestSubscriber ts = new TestSubscriber<>(new FlowableSubscriber() /* NFI */ { + var ts = new TestSubscriber<>(new FlowableSubscriber() /* NFI */ { @Override public void onSubscribe(Subscription s) { @@ -1350,14 +1350,15 @@ public void assertValuePredicateMatch() { ts.assertValue(o -> o == 1); } - static void assertThrowsWithMessage(String message, Class clazz, ThrowingRunnable run) { - assertEquals(message, assertThrows(clazz, run).getMessage()); + static void assertThrowsWithMessage(String message, + ThrowingRunnable run) { + assertEquals(message, assertThrows(AssertionError.class, run).getMessage()); } @Test public void assertValuePredicateNoMatch() { assertThrowsWithMessage("Value 1 (class: Integer) at position 0 did not pass the predicate " - + "(latch = 0, values = 1, errors = 0, completions = 1)", AssertionError.class, () -> { + + "(latch = 0, values = 1, errors = 0, completions = 1)", () -> { TestSubscriber ts = new TestSubscriber<>(); Flowable.just(1).subscribe(ts); @@ -1369,7 +1370,7 @@ public void assertValuePredicateNoMatch() { @Test public void assertValuePredicateMatchButMore() { assertThrowsWithMessage("The first value passed the predicate but this consumer received more than one value " - + "(latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + + "(latch = 0, values = 2, errors = 0, completions = 1)", () -> { TestSubscriber ts = new TestSubscriber<>(); Flowable.just(1, 2).subscribe(ts); @@ -1380,7 +1381,7 @@ public void assertValuePredicateMatchButMore() { @Test public void assertValueAtPredicateEmpty() { - assertThrowsWithMessage("No values (latch = 0, values = 0, errors = 0, completions = 1)", AssertionError.class, () -> { + assertThrowsWithMessage("No values (latch = 0, values = 0, errors = 0, completions = 1)", () -> { TestSubscriber ts = new TestSubscriber<>(); Flowable.empty().subscribe(ts); @@ -1401,7 +1402,7 @@ public void assertValueAtPredicateMatch() { @Test public void assertValueAtPredicateNoMatch() { assertThrowsWithMessage("Value 3 (class: Integer) at position 2 did not pass the predicate " - + "(latch = 0, values = 3, errors = 0, completions = 1)", AssertionError.class, () -> { + + "(latch = 0, values = 3, errors = 0, completions = 1)", () -> { TestSubscriber ts = new TestSubscriber<>(); Flowable.just(1, 2, 3).subscribe(ts); @@ -1412,7 +1413,7 @@ public void assertValueAtPredicateNoMatch() { @Test public void assertValueAtInvalidIndex() { - assertThrowsWithMessage("Index 2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + assertThrowsWithMessage("Index 2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", () -> { TestSubscriber ts = new TestSubscriber<>(); Flowable.just(1, 2).subscribe(ts); @@ -1423,7 +1424,7 @@ public void assertValueAtInvalidIndex() { @Test public void assertValueAtIndexInvalidIndex() { - assertThrowsWithMessage("Index 2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + assertThrowsWithMessage("Index 2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", () -> { TestSubscriber ts = new TestSubscriber<>(); Flowable.just(1, 2).subscribe(ts); @@ -1434,7 +1435,7 @@ public void assertValueAtIndexInvalidIndex() { @Test public void assertValueAtIndexInvalidIndexNegative() { - assertThrowsWithMessage("Index -2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + assertThrowsWithMessage("Index -2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", () -> { TestSubscriber ts = new TestSubscriber<>(); Flowable.just(1, 2).subscribe(ts); @@ -1445,7 +1446,7 @@ public void assertValueAtIndexInvalidIndexNegative() { @Test public void assertValueAtInvalidIndexNegative() { - assertThrowsWithMessage("Index -2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> { + assertThrowsWithMessage("Index -2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", () -> { TestSubscriber ts = new TestSubscriber<>(); Flowable.just(1, 2).subscribe(ts); @@ -1484,7 +1485,7 @@ public void withTag() { @Test public void timeoutIndicated() throws InterruptedException { - Thread.interrupted(); // clear flag + IO.println(Thread.interrupted()); // clear flag TestSubscriber ts = Flowable.never() .test(); @@ -1499,7 +1500,7 @@ public void timeoutIndicated() throws InterruptedException { } @Test - public void timeoutIndicated2() throws InterruptedException { + public void timeoutIndicated2() { try { Flowable.never() .test() @@ -1666,7 +1667,21 @@ public void awaitCountInterrupted() { Thread.currentThread().interrupt(); ts.awaitCount(1); } finally { - Thread.interrupted(); + IO.println(Thread.interrupted()); // clear flag } } + + @Test + public void assertValueAts() { + var ts = new TestSubscriber(); + ts.onSubscribe(new BooleanSubscription()); + ts.onNext(1); + ts.onNext(2); + + ts.assertValueAt(0, 1) + .assertValueAt(1, 2) + .assertValueAt(0, v -> v == 1) + .assertValueAt(1, v -> v == 2) + ; + } } diff --git a/src/test/java/io/reactivex/rxjava4/testsupport/TestHelper.java b/src/test/java/io/reactivex/rxjava4/testsupport/TestHelper.java index 7847f8eaeb2..21c78358b8f 100644 --- a/src/test/java/io/reactivex/rxjava4/testsupport/TestHelper.java +++ b/src/test/java/io/reactivex/rxjava4/testsupport/TestHelper.java @@ -265,37 +265,6 @@ public static void assertError(TestSubscriberEx ts, int index, Class the enum type - * @param e the enum class instance - */ - public static > void assertEmptyEnum(Class e) { - assertEquals(0, e.getEnumConstants().length); - - try { - try { - Method m0 = e.getDeclaredMethod("values"); - - Object[] a = (Object[])m0.invoke(null); - assertEquals(0, a.length); - - Method m = e.getDeclaredMethod("valueOf", String.class); - - m.invoke("INSTANCE"); - fail("Should have thrown!"); - } catch (InvocationTargetException ex) { - fail(ex.toString()); - } catch (IllegalAccessException ex) { - fail(ex.toString()); - } catch (IllegalArgumentException ex) { - // we expected this - } - } catch (NoSuchMethodException ex) { - fail(ex.toString()); - } - } - /** * Assert that by consuming the Publisher with a bad request amount, it is * reported to the plugin error handler promptly. @@ -359,7 +328,7 @@ public static void assertBadRequestReported(ParallelFlowable source) { try { final CountDownLatch cdl = new CountDownLatch(1); - var bad = new FlowableSubscriber() /* NFI */ { + var bad = new FlowableSubscriber<>() /* NFI */ { @Override public void onSubscribe(Subscription s) { @@ -440,7 +409,7 @@ public static void race(final Runnable r1, final Runnable r2, Scheduler s) { s.scheduleDirect(() -> { if (count.decrementAndGet() != 0) { - while (count.get() != 0) { } + while (count.get() != 0) { Thread.onSpinWait(); } } try { @@ -455,7 +424,7 @@ public static void race(final Runnable r1, final Runnable r2, Scheduler s) { }); if (count.decrementAndGet() != 0) { - while (count.get() != 0) { } + while (count.get() != 0) { Thread.onSpinWait(); } } try { @@ -483,7 +452,7 @@ public static void race(final Runnable r1, final Runnable r2, Scheduler s) { throw ExceptionHelper.wrapOrThrow(errors[1]); } - if (errors[0] != null && errors[1] != null) { + if (errors[0] != null) { throw new CompositeException(errors); } } @@ -958,7 +927,7 @@ public static void checkDoubleOnSubscribeMaybe(Function, ? exten final Boolean[] b = { null, null }; final CountDownLatch cdl = new CountDownLatch(1); - Maybe source = new Maybe() /* NFI */ { + var source = new Maybe() /* NFI */ { @Override protected void subscribeActual(MaybeObserver observer) { try { @@ -1012,7 +981,7 @@ public static void checkDoubleOnSubscribeMaybeToSingle(Function, final Boolean[] b = { null, null }; final CountDownLatch cdl = new CountDownLatch(1); - Maybe source = new Maybe() /* NFI */ { + var source = new Maybe() /* NFI */ { @Override protected void subscribeActual(MaybeObserver observer) { try { @@ -1066,7 +1035,7 @@ public static void checkDoubleOnSubscribeMaybeToObservable(Function source = new Maybe() /* NFI */ { + var source = new Maybe() /* NFI */ { @Override protected void subscribeActual(MaybeObserver observer) { try { @@ -1120,7 +1089,7 @@ public static void checkDoubleOnSubscribeMaybeToFlowable(Function source = new Maybe() /* NFI */ { + var source = new Maybe() /* NFI */ { @Override protected void subscribeActual(MaybeObserver observer) { try { @@ -1174,7 +1143,7 @@ public static void checkDoubleOnSubscribeSingleToMaybe(Function final Boolean[] b = { null, null }; final CountDownLatch cdl = new CountDownLatch(1); - Single source = new Single() /* NFI */ { + var source = new Single() /* NFI */ { @Override protected void subscribeActual(SingleObserver observer) { try { @@ -1228,7 +1197,7 @@ public static void checkDoubleOnSubscribeSingleToObservable(Function source = new Single() /* NFI */ { + var source = new Single() /* NFI */ { @Override protected void subscribeActual(SingleObserver observer) { try { @@ -1282,7 +1251,7 @@ public static void checkDoubleOnSubscribeSingleToFlowable(Function source = new Single() /* NFI */ { + var source = new Single() /* NFI */ { @Override protected void subscribeActual(SingleObserver observer) { try { @@ -1335,7 +1304,7 @@ public static void checkDoubleOnSubscribeMaybeToCompletable(Function source = new Maybe() /* NFI */ { + var source = new Maybe() /* NFI */ { @Override protected void subscribeActual(MaybeObserver observer) { try { @@ -1389,7 +1358,7 @@ public static void checkDoubleOnSubscribeSingle(Function, ? ext final Boolean[] b = { null, null }; final CountDownLatch cdl = new CountDownLatch(1); - Single source = new Single() /* NFI */ { + var source = new Single() /* NFI */ { @Override protected void subscribeActual(SingleObserver observer) { try { @@ -1443,7 +1412,7 @@ public static void checkDoubleOnSubscribeFlowable(Function, ? final Boolean[] b = { null, null }; final CountDownLatch cdl = new CountDownLatch(1); - Flowable source = new Flowable() /* NFI */ { + var source = new Flowable() /* NFI */ { @Override protected void subscribeActual(Subscriber subscriber) { try { @@ -1497,7 +1466,7 @@ public static void checkDoubleOnSubscribeParallel(Function source = new ParallelFlowable() /* NFI */ { + var source = new ParallelFlowable() /* NFI */ { @Override public void subscribe(Subscriber[] subscribers) { for (int i = 0; i < subscribers.length; i++) { @@ -1510,7 +1479,7 @@ public void subscribe(Subscriber[] subscribers) { subscribers[i].onSubscribe(bs2); - b[i * 2 + 0] = bs1.isCancelled(); + b[i * 2] = bs1.isCancelled(); b[i * 2 + 1] = bs2.isCancelled(); } finally { cdl.countDown(); @@ -3717,7 +3686,7 @@ public static void raceOther(Runnable run, CountDownLatch resume) { Schedulers.single().scheduleDirect(() -> { if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } run.run(); @@ -3726,7 +3695,7 @@ public static void raceOther(Runnable run, CountDownLatch resume) { }); if (sync.decrementAndGet() != 0) { - while (sync.get() != 0) { } + while (sync.get() != 0) { Thread.onSpinWait(); } } }