From 1c66113ece291932235ef2ec2b0c4a3ae1dd58bc Mon Sep 17 00:00:00 2001 From: Pedro Viegas Date: Mon, 4 Nov 2013 10:43:51 +0530 Subject: [PATCH 1/2] creating test classes on test source folder --- ...estSchedulers.java => SchedulersTest.java} | 65 +++++++++---------- .../CurrentThreadSchedulerTest.java | 7 ++ .../concurrency/ImmediateSchedulerTest.java | 7 ++ .../observables/BlockingObservableTest.java | 7 ++ .../java/rx/operators/OperationAllTest.java | 7 ++ .../java/rx/operators/OperationAnyTest.java | 7 ++ .../rx/operators/OperationAverageTest.java | 7 ++ .../rx/operators/OperationBufferTest.java | 7 ++ .../java/rx/operators/OperationCacheTest.java | 7 ++ .../java/rx/operators/OperationCastTest.java | 7 ++ .../operators/OperationCombineLatestTest.java | 7 ++ .../rx/operators/OperationConcatTest.java | 7 ++ .../rx/operators/OperationDebounceTest.java | 7 ++ .../OperationDefaultIfEmptyTest.java | 7 ++ .../java/rx/operators/OperationDeferTest.java | 7 ++ .../operators/OperationDematerializeTest.java | 7 ++ .../rx/operators/OperationDistinctTest.java | 7 ++ .../OperationDistinctUntilChangedTest.java | 7 ++ .../rx/operators/OperationElementAtTest.java | 7 ++ .../rx/operators/OperationFilterTest.java | 7 ++ .../rx/operators/OperationFinallyTest.java | 7 ++ .../OperationFirstOrDefaultTest.java | 7 ++ .../rx/operators/OperationGroupByTest.java | 7 ++ .../rx/operators/OperationIntervalTest.java | 7 ++ .../java/rx/operators/OperationMapTest.java | 7 ++ .../operators/OperationMaterializeTest.java | 7 ++ .../OperationMergeDelayErrorTest.java | 7 ++ .../java/rx/operators/OperationMergeTest.java | 7 ++ .../rx/operators/OperationMostRecentTest.java | 7 ++ .../rx/operators/OperationMulticastTest.java | 7 ++ .../java/rx/operators/OperationNextTest.java | 7 ++ .../rx/operators/OperationObserveOnTest.java | 7 ++ ...ationOnErrorResumeNextViaFunctionTest.java | 7 ++ ...ionOnErrorResumeNextViaObservableTest.java | 7 ++ .../operators/OperationOnErrorReturnTest.java | 7 ++ ...nExceptionResumeNextViaObservableTest.java | 7 ++ .../rx/operators/OperationParallelTest.java | 7 ++ .../java/rx/operators/OperationRetryTest.java | 7 ++ .../rx/operators/OperationSampleTest.java | 7 ++ .../java/rx/operators/OperationScanTest.java | 7 ++ .../rx/operators/OperationSkipLastTest.java | 7 ++ .../java/rx/operators/OperationSkipTest.java | 7 ++ .../rx/operators/OperationSkipWhileTest.java | 7 ++ .../operators/OperationSubscribeOnTest.java | 7 ++ .../java/rx/operators/OperationSumTest.java | 7 ++ .../rx/operators/OperationSwitchTest.java | 7 ++ .../operators/OperationSynchronizeTest.java | 7 ++ .../rx/operators/OperationTakeLastTest.java | 7 ++ .../java/rx/operators/OperationTakeTest.java | 7 ++ .../rx/operators/OperationTakeUntilTest.java | 7 ++ .../operators/OperationThrottleFirstTest.java | 7 ++ .../OperationToObservableFutureTest.java | 7 ++ .../OperationToObservableIterableTest.java | 7 ++ .../OperationToObservableListTest.java | 7 ++ .../OperationToObservableSortedListTest.java | 7 ++ .../rx/operators/OperationWindowTest.java | 7 ++ .../java/rx/operators/OperationZipTest.java | 7 ++ .../java/rx/operators/OperatorTesterTest.java | 7 ++ .../SafeObservableSubscriptionTest.java | 7 ++ .../operators/SynchronizedObserverTest.java | 7 ++ .../test/java/rx/operators/TakeWhileTest.java | 7 ++ .../operators/TimeIntervalObserverTest.java | 7 ++ .../java/rx/plugins/RxJavaPluginsTest.java | 7 ++ .../java/rx/subjects/AsyncSubjectTest.java | 7 ++ .../java/rx/subjects/BehaviorSubjectTest.java | 7 ++ .../java/rx/subjects/PublishSubjectTest.java | 7 ++ .../java/rx/subjects/ReplaySubjectTest.java | 7 ++ .../CompositeSubscriptionTest.java | 7 ++ .../rx/subscriptions/SubscriptionsTest.java | 7 ++ .../src/test/java/rx/util/RangeTest.java | 7 ++ 70 files changed, 514 insertions(+), 34 deletions(-) rename rxjava-core/src/test/java/rx/{concurrency/TestSchedulers.java => SchedulersTest.java} (95%) create mode 100644 rxjava-core/src/test/java/rx/concurrency/CurrentThreadSchedulerTest.java create mode 100644 rxjava-core/src/test/java/rx/concurrency/ImmediateSchedulerTest.java create mode 100644 rxjava-core/src/test/java/rx/observables/BlockingObservableTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationAllTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationAnyTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationAverageTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationBufferTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationCacheTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationCastTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationCombineLatestTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationConcatTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationDebounceTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationDefaultIfEmptyTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationDeferTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationDematerializeTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationDistinctTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationDistinctUntilChangedTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationElementAtTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationFilterTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationFinallyTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationFirstOrDefaultTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationGroupByTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationIntervalTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationMapTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationMaterializeTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationMergeDelayErrorTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationMergeTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationMostRecentTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationMulticastTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationNextTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationObserveOnTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationOnErrorResumeNextViaFunctionTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationOnErrorResumeNextViaObservableTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationOnErrorReturnTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationOnExceptionResumeNextViaObservableTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationParallelTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationRetryTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationSampleTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationScanTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationSkipLastTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationSkipTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationSkipWhileTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationSubscribeOnTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationSumTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationSwitchTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationSynchronizeTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationTakeLastTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationTakeTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationTakeUntilTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationThrottleFirstTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationToObservableFutureTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationToObservableIterableTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationToObservableListTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationToObservableSortedListTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationWindowTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationZipTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperatorTesterTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/SafeObservableSubscriptionTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/SynchronizedObserverTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/TakeWhileTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/TimeIntervalObserverTest.java create mode 100644 rxjava-core/src/test/java/rx/plugins/RxJavaPluginsTest.java create mode 100644 rxjava-core/src/test/java/rx/subjects/AsyncSubjectTest.java create mode 100644 rxjava-core/src/test/java/rx/subjects/BehaviorSubjectTest.java create mode 100644 rxjava-core/src/test/java/rx/subjects/PublishSubjectTest.java create mode 100644 rxjava-core/src/test/java/rx/subjects/ReplaySubjectTest.java create mode 100644 rxjava-core/src/test/java/rx/subscriptions/CompositeSubscriptionTest.java create mode 100644 rxjava-core/src/test/java/rx/subscriptions/SubscriptionsTest.java create mode 100644 rxjava-core/src/test/java/rx/util/RangeTest.java diff --git a/rxjava-core/src/test/java/rx/concurrency/TestSchedulers.java b/rxjava-core/src/test/java/rx/SchedulersTest.java similarity index 95% rename from rxjava-core/src/test/java/rx/concurrency/TestSchedulers.java rename to rxjava-core/src/test/java/rx/SchedulersTest.java index e1df828237..d2ac58e61f 100644 --- a/rxjava-core/src/test/java/rx/concurrency/TestSchedulers.java +++ b/rxjava-core/src/test/java/rx/SchedulersTest.java @@ -1,36 +1,24 @@ /** * Copyright 2013 Netflix, Inc. - * + * * 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 rx.concurrency; - -import static org.junit.Assert.*; - -import java.util.Date; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; +package rx; import org.junit.Test; - -import rx.Observable; import rx.Observable.OnSubscribeFunc; -import rx.Observer; -import rx.Scheduler; -import rx.Subscription; +import rx.concurrency.Schedulers; +import rx.concurrency.TestScheduler; import rx.subscriptions.BooleanSubscription; import rx.subscriptions.Subscriptions; import rx.util.functions.Action0; @@ -38,7 +26,16 @@ import rx.util.functions.Func1; import rx.util.functions.Func2; -public class TestSchedulers { +import java.util.Date; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.Assert.*; + +public class SchedulersTest { @Test public void testComputationThreadPool1() { @@ -447,18 +444,18 @@ public void testSubscribeOnNestedConcurrency() throws InterruptedException { Observable o = Observable.from("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten") .mapMany(new Func1>() { - @Override - public Observable call(final String v) { - return Observable.create(new OnSubscribeFunc() { - - @Override - public Subscription onSubscribe(final Observer observer) { - observer.onNext("value_after_map-" + v); - observer.onCompleted(); - return Subscriptions.empty(); - } - }).subscribeOn(Schedulers.newThread()); // subscribe on a new thread - } + @Override + public Observable call(final String v) { + return Observable.create(new OnSubscribeFunc() { + + @Override + public Subscription onSubscribe(final Observer observer) { + observer.onNext("value_after_map-" + v); + observer.onCompleted(); + return Subscriptions.empty(); + } + }).subscribeOn(Schedulers.newThread()); // subscribe on a new thread + } }); ConcurrentObserverValidator observer = new ConcurrentObserverValidator(); @@ -474,7 +471,7 @@ public Subscription onSubscribe(final Observer observer) { fail("Error: " + observer.error.get().getMessage()); } } - + @Test public void testRecursion() { TestScheduler s = new TestScheduler(); @@ -494,11 +491,11 @@ public void call(Action0 self) { subscription.unsubscribe(); assertEquals(0, counter.get()); } - + /** * Used to determine if onNext is being invoked concurrently. - * + * * @param */ private static class ConcurrentObserverValidator implements Observer { diff --git a/rxjava-core/src/test/java/rx/concurrency/CurrentThreadSchedulerTest.java b/rxjava-core/src/test/java/rx/concurrency/CurrentThreadSchedulerTest.java new file mode 100644 index 0000000000..b9a9b1a1c2 --- /dev/null +++ b/rxjava-core/src/test/java/rx/concurrency/CurrentThreadSchedulerTest.java @@ -0,0 +1,7 @@ +package rx.concurrency; + +import org.junit.Ignore; + +@Ignore("WIP") +public class CurrentThreadSchedulerTest { +} diff --git a/rxjava-core/src/test/java/rx/concurrency/ImmediateSchedulerTest.java b/rxjava-core/src/test/java/rx/concurrency/ImmediateSchedulerTest.java new file mode 100644 index 0000000000..036103e540 --- /dev/null +++ b/rxjava-core/src/test/java/rx/concurrency/ImmediateSchedulerTest.java @@ -0,0 +1,7 @@ +package rx.concurrency; + +import org.junit.Ignore; + +@Ignore("WIP") +public class ImmediateSchedulerTest { +} diff --git a/rxjava-core/src/test/java/rx/observables/BlockingObservableTest.java b/rxjava-core/src/test/java/rx/observables/BlockingObservableTest.java new file mode 100644 index 0000000000..aa38f711ad --- /dev/null +++ b/rxjava-core/src/test/java/rx/observables/BlockingObservableTest.java @@ -0,0 +1,7 @@ +package rx.observables; + +import org.junit.Ignore; + +@Ignore("WIP") +public class BlockingObservableTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationAllTest.java b/rxjava-core/src/test/java/rx/operators/OperationAllTest.java new file mode 100644 index 0000000000..ffb0b56798 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationAllTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationAllTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationAnyTest.java b/rxjava-core/src/test/java/rx/operators/OperationAnyTest.java new file mode 100644 index 0000000000..98d6e72fa5 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationAnyTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationAnyTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationAverageTest.java b/rxjava-core/src/test/java/rx/operators/OperationAverageTest.java new file mode 100644 index 0000000000..6fa01dfc92 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationAverageTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationAverageTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationBufferTest.java b/rxjava-core/src/test/java/rx/operators/OperationBufferTest.java new file mode 100644 index 0000000000..d096cd666a --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationBufferTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationBufferTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationCacheTest.java b/rxjava-core/src/test/java/rx/operators/OperationCacheTest.java new file mode 100644 index 0000000000..4a754528e5 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationCacheTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationCacheTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationCastTest.java b/rxjava-core/src/test/java/rx/operators/OperationCastTest.java new file mode 100644 index 0000000000..36bab268ff --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationCastTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationCastTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationCombineLatestTest.java b/rxjava-core/src/test/java/rx/operators/OperationCombineLatestTest.java new file mode 100644 index 0000000000..b154ce1223 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationCombineLatestTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationCombineLatestTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationConcatTest.java b/rxjava-core/src/test/java/rx/operators/OperationConcatTest.java new file mode 100644 index 0000000000..1380ffcaef --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationConcatTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationConcatTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationDebounceTest.java b/rxjava-core/src/test/java/rx/operators/OperationDebounceTest.java new file mode 100644 index 0000000000..a1f6d4c237 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationDebounceTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationDebounceTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationDefaultIfEmptyTest.java b/rxjava-core/src/test/java/rx/operators/OperationDefaultIfEmptyTest.java new file mode 100644 index 0000000000..241c8790c3 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationDefaultIfEmptyTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationDefaultIfEmptyTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationDeferTest.java b/rxjava-core/src/test/java/rx/operators/OperationDeferTest.java new file mode 100644 index 0000000000..344cbee450 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationDeferTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationDeferTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationDematerializeTest.java b/rxjava-core/src/test/java/rx/operators/OperationDematerializeTest.java new file mode 100644 index 0000000000..f0433032fb --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationDematerializeTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationDematerializeTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationDistinctTest.java b/rxjava-core/src/test/java/rx/operators/OperationDistinctTest.java new file mode 100644 index 0000000000..1704b644fc --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationDistinctTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationDistinctTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationDistinctUntilChangedTest.java b/rxjava-core/src/test/java/rx/operators/OperationDistinctUntilChangedTest.java new file mode 100644 index 0000000000..cdb4eb7203 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationDistinctUntilChangedTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationDistinctUntilChangedTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationElementAtTest.java b/rxjava-core/src/test/java/rx/operators/OperationElementAtTest.java new file mode 100644 index 0000000000..b17efa3cd3 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationElementAtTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationElementAtTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationFilterTest.java b/rxjava-core/src/test/java/rx/operators/OperationFilterTest.java new file mode 100644 index 0000000000..19e15ea81a --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationFilterTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationFilterTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationFinallyTest.java b/rxjava-core/src/test/java/rx/operators/OperationFinallyTest.java new file mode 100644 index 0000000000..0e46ce1cb2 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationFinallyTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationFinallyTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationFirstOrDefaultTest.java b/rxjava-core/src/test/java/rx/operators/OperationFirstOrDefaultTest.java new file mode 100644 index 0000000000..39a60a03c5 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationFirstOrDefaultTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationFirstOrDefaultTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationGroupByTest.java b/rxjava-core/src/test/java/rx/operators/OperationGroupByTest.java new file mode 100644 index 0000000000..222085a96f --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationGroupByTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationGroupByTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationIntervalTest.java b/rxjava-core/src/test/java/rx/operators/OperationIntervalTest.java new file mode 100644 index 0000000000..60b2ad7789 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationIntervalTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationIntervalTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationMapTest.java b/rxjava-core/src/test/java/rx/operators/OperationMapTest.java new file mode 100644 index 0000000000..3c3ee5813c --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationMapTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationMapTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationMaterializeTest.java b/rxjava-core/src/test/java/rx/operators/OperationMaterializeTest.java new file mode 100644 index 0000000000..24f67b432c --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationMaterializeTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationMaterializeTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationMergeDelayErrorTest.java b/rxjava-core/src/test/java/rx/operators/OperationMergeDelayErrorTest.java new file mode 100644 index 0000000000..1e3c763573 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationMergeDelayErrorTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationMergeDelayErrorTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationMergeTest.java b/rxjava-core/src/test/java/rx/operators/OperationMergeTest.java new file mode 100644 index 0000000000..ef50b179e6 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationMergeTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationMergeTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationMostRecentTest.java b/rxjava-core/src/test/java/rx/operators/OperationMostRecentTest.java new file mode 100644 index 0000000000..1f5806b310 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationMostRecentTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationMostRecentTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationMulticastTest.java b/rxjava-core/src/test/java/rx/operators/OperationMulticastTest.java new file mode 100644 index 0000000000..dd2ba06360 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationMulticastTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationMulticastTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationNextTest.java b/rxjava-core/src/test/java/rx/operators/OperationNextTest.java new file mode 100644 index 0000000000..bad26bbcb1 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationNextTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationNextTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationObserveOnTest.java b/rxjava-core/src/test/java/rx/operators/OperationObserveOnTest.java new file mode 100644 index 0000000000..9f439949a8 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationObserveOnTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationObserveOnTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationOnErrorResumeNextViaFunctionTest.java b/rxjava-core/src/test/java/rx/operators/OperationOnErrorResumeNextViaFunctionTest.java new file mode 100644 index 0000000000..8a98b35dd2 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationOnErrorResumeNextViaFunctionTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationOnErrorResumeNextViaFunctionTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationOnErrorResumeNextViaObservableTest.java b/rxjava-core/src/test/java/rx/operators/OperationOnErrorResumeNextViaObservableTest.java new file mode 100644 index 0000000000..b0ec9f3211 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationOnErrorResumeNextViaObservableTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationOnErrorResumeNextViaObservableTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationOnErrorReturnTest.java b/rxjava-core/src/test/java/rx/operators/OperationOnErrorReturnTest.java new file mode 100644 index 0000000000..0fe50a7f04 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationOnErrorReturnTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationOnErrorReturnTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationOnExceptionResumeNextViaObservableTest.java b/rxjava-core/src/test/java/rx/operators/OperationOnExceptionResumeNextViaObservableTest.java new file mode 100644 index 0000000000..4e8a7c1586 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationOnExceptionResumeNextViaObservableTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationOnExceptionResumeNextViaObservableTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationParallelTest.java b/rxjava-core/src/test/java/rx/operators/OperationParallelTest.java new file mode 100644 index 0000000000..fee3816e98 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationParallelTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationParallelTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationRetryTest.java b/rxjava-core/src/test/java/rx/operators/OperationRetryTest.java new file mode 100644 index 0000000000..768d1f5f9c --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationRetryTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationRetryTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationSampleTest.java b/rxjava-core/src/test/java/rx/operators/OperationSampleTest.java new file mode 100644 index 0000000000..a718adbc0a --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationSampleTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationSampleTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationScanTest.java b/rxjava-core/src/test/java/rx/operators/OperationScanTest.java new file mode 100644 index 0000000000..aa3d7d6f9e --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationScanTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationScanTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationSkipLastTest.java b/rxjava-core/src/test/java/rx/operators/OperationSkipLastTest.java new file mode 100644 index 0000000000..9604c718c7 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationSkipLastTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationSkipLastTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationSkipTest.java b/rxjava-core/src/test/java/rx/operators/OperationSkipTest.java new file mode 100644 index 0000000000..1d74ed6302 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationSkipTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationSkipTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationSkipWhileTest.java b/rxjava-core/src/test/java/rx/operators/OperationSkipWhileTest.java new file mode 100644 index 0000000000..d9347d907e --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationSkipWhileTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationSkipWhileTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationSubscribeOnTest.java b/rxjava-core/src/test/java/rx/operators/OperationSubscribeOnTest.java new file mode 100644 index 0000000000..495cbc6713 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationSubscribeOnTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationSubscribeOnTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationSumTest.java b/rxjava-core/src/test/java/rx/operators/OperationSumTest.java new file mode 100644 index 0000000000..c89121e207 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationSumTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationSumTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationSwitchTest.java b/rxjava-core/src/test/java/rx/operators/OperationSwitchTest.java new file mode 100644 index 0000000000..d91bb804bf --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationSwitchTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationSwitchTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationSynchronizeTest.java b/rxjava-core/src/test/java/rx/operators/OperationSynchronizeTest.java new file mode 100644 index 0000000000..2dce4a7d32 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationSynchronizeTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationSynchronizeTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationTakeLastTest.java b/rxjava-core/src/test/java/rx/operators/OperationTakeLastTest.java new file mode 100644 index 0000000000..234e70d543 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationTakeLastTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationTakeLastTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationTakeTest.java b/rxjava-core/src/test/java/rx/operators/OperationTakeTest.java new file mode 100644 index 0000000000..eaa1bdf1d4 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationTakeTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationTakeTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationTakeUntilTest.java b/rxjava-core/src/test/java/rx/operators/OperationTakeUntilTest.java new file mode 100644 index 0000000000..22cd5eb078 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationTakeUntilTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationTakeUntilTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationThrottleFirstTest.java b/rxjava-core/src/test/java/rx/operators/OperationThrottleFirstTest.java new file mode 100644 index 0000000000..66301abfca --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationThrottleFirstTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationThrottleFirstTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationToObservableFutureTest.java b/rxjava-core/src/test/java/rx/operators/OperationToObservableFutureTest.java new file mode 100644 index 0000000000..3f58b63911 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationToObservableFutureTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationToObservableFutureTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationToObservableIterableTest.java b/rxjava-core/src/test/java/rx/operators/OperationToObservableIterableTest.java new file mode 100644 index 0000000000..1805e1cbcd --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationToObservableIterableTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationToObservableIterableTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationToObservableListTest.java b/rxjava-core/src/test/java/rx/operators/OperationToObservableListTest.java new file mode 100644 index 0000000000..49c7409e86 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationToObservableListTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationToObservableListTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationToObservableSortedListTest.java b/rxjava-core/src/test/java/rx/operators/OperationToObservableSortedListTest.java new file mode 100644 index 0000000000..62efef680d --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationToObservableSortedListTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationToObservableSortedListTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationWindowTest.java b/rxjava-core/src/test/java/rx/operators/OperationWindowTest.java new file mode 100644 index 0000000000..0e602254f5 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationWindowTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationWindowTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationZipTest.java b/rxjava-core/src/test/java/rx/operators/OperationZipTest.java new file mode 100644 index 0000000000..3e027193ab --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationZipTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperationZipTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/OperatorTesterTest.java b/rxjava-core/src/test/java/rx/operators/OperatorTesterTest.java new file mode 100644 index 0000000000..f5a4161708 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperatorTesterTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class OperatorTesterTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/SafeObservableSubscriptionTest.java b/rxjava-core/src/test/java/rx/operators/SafeObservableSubscriptionTest.java new file mode 100644 index 0000000000..c5b7e6d590 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/SafeObservableSubscriptionTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class SafeObservableSubscriptionTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/SynchronizedObserverTest.java b/rxjava-core/src/test/java/rx/operators/SynchronizedObserverTest.java new file mode 100644 index 0000000000..5b4b301590 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/SynchronizedObserverTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class SynchronizedObserverTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/TakeWhileTest.java b/rxjava-core/src/test/java/rx/operators/TakeWhileTest.java new file mode 100644 index 0000000000..c81169eac2 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/TakeWhileTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class TakeWhileTest { +} diff --git a/rxjava-core/src/test/java/rx/operators/TimeIntervalObserverTest.java b/rxjava-core/src/test/java/rx/operators/TimeIntervalObserverTest.java new file mode 100644 index 0000000000..6f073696f0 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/TimeIntervalObserverTest.java @@ -0,0 +1,7 @@ +package rx.operators; + +import org.junit.Ignore; + +@Ignore("WIP") +public class TimeIntervalObserverTest { +} diff --git a/rxjava-core/src/test/java/rx/plugins/RxJavaPluginsTest.java b/rxjava-core/src/test/java/rx/plugins/RxJavaPluginsTest.java new file mode 100644 index 0000000000..1def236246 --- /dev/null +++ b/rxjava-core/src/test/java/rx/plugins/RxJavaPluginsTest.java @@ -0,0 +1,7 @@ +package rx.plugins; + +import org.junit.Ignore; + +@Ignore("WIP") +public class RxJavaPluginsTest { +} diff --git a/rxjava-core/src/test/java/rx/subjects/AsyncSubjectTest.java b/rxjava-core/src/test/java/rx/subjects/AsyncSubjectTest.java new file mode 100644 index 0000000000..bfe0aa0bb0 --- /dev/null +++ b/rxjava-core/src/test/java/rx/subjects/AsyncSubjectTest.java @@ -0,0 +1,7 @@ +package rx.subjects; + +import org.junit.Ignore; + +@Ignore("WIP") +public class AsyncSubjectTest { +} diff --git a/rxjava-core/src/test/java/rx/subjects/BehaviorSubjectTest.java b/rxjava-core/src/test/java/rx/subjects/BehaviorSubjectTest.java new file mode 100644 index 0000000000..ffee087158 --- /dev/null +++ b/rxjava-core/src/test/java/rx/subjects/BehaviorSubjectTest.java @@ -0,0 +1,7 @@ +package rx.subjects; + +import org.junit.Ignore; + +@Ignore("WIP") +public class BehaviorSubjectTest { +} diff --git a/rxjava-core/src/test/java/rx/subjects/PublishSubjectTest.java b/rxjava-core/src/test/java/rx/subjects/PublishSubjectTest.java new file mode 100644 index 0000000000..25cebbf510 --- /dev/null +++ b/rxjava-core/src/test/java/rx/subjects/PublishSubjectTest.java @@ -0,0 +1,7 @@ +package rx.subjects; + +import org.junit.Ignore; + +@Ignore("WIP") +public class PublishSubjectTest { +} diff --git a/rxjava-core/src/test/java/rx/subjects/ReplaySubjectTest.java b/rxjava-core/src/test/java/rx/subjects/ReplaySubjectTest.java new file mode 100644 index 0000000000..1e722e5e5e --- /dev/null +++ b/rxjava-core/src/test/java/rx/subjects/ReplaySubjectTest.java @@ -0,0 +1,7 @@ +package rx.subjects; + +import org.junit.Ignore; + +@Ignore("WIP") +public class ReplaySubjectTest { +} diff --git a/rxjava-core/src/test/java/rx/subscriptions/CompositeSubscriptionTest.java b/rxjava-core/src/test/java/rx/subscriptions/CompositeSubscriptionTest.java new file mode 100644 index 0000000000..43830564ce --- /dev/null +++ b/rxjava-core/src/test/java/rx/subscriptions/CompositeSubscriptionTest.java @@ -0,0 +1,7 @@ +package rx.subscriptions; + +import org.junit.Ignore; + +@Ignore("WIP") +public class CompositeSubscriptionTest { +} diff --git a/rxjava-core/src/test/java/rx/subscriptions/SubscriptionsTest.java b/rxjava-core/src/test/java/rx/subscriptions/SubscriptionsTest.java new file mode 100644 index 0000000000..17bb5b4619 --- /dev/null +++ b/rxjava-core/src/test/java/rx/subscriptions/SubscriptionsTest.java @@ -0,0 +1,7 @@ +package rx.subscriptions; + +import org.junit.Ignore; + +@Ignore("WIP") +public class SubscriptionsTest { +} diff --git a/rxjava-core/src/test/java/rx/util/RangeTest.java b/rxjava-core/src/test/java/rx/util/RangeTest.java new file mode 100644 index 0000000000..640678b5c3 --- /dev/null +++ b/rxjava-core/src/test/java/rx/util/RangeTest.java @@ -0,0 +1,7 @@ +package rx.util; + +import org.junit.Ignore; + +@Ignore("WIP") +public class RangeTest { +} From cc7958d90f40090cd2f57038f7de95a3d4be69c5 Mon Sep 17 00:00:00 2001 From: Pedro Viegas Date: Mon, 4 Nov 2013 12:10:47 +0530 Subject: [PATCH 2/2] moving tests to test source folder #439 --- rxjava-core/src/main/java/rx/Scheduler.java | 59 +- .../concurrency/CurrentThreadScheduler.java | 136 +-- .../rx/concurrency/ImmediateScheduler.java | 103 +-- .../rx/observables/BlockingObservable.java | 258 +----- .../main/java/rx/operators/OperationAll.java | 83 +- .../main/java/rx/operators/OperationAny.java | 183 +--- .../java/rx/operators/OperationAverage.java | 100 --- .../java/rx/operators/OperationBuffer.java | 344 +------ .../java/rx/operators/OperationCache.java | 70 +- .../main/java/rx/operators/OperationCast.java | 41 - .../rx/operators/OperationCombineLatest.java | 631 +------------ .../java/rx/operators/OperationConcat.java | 547 +---------- .../java/rx/operators/OperationDebounce.java | 146 +-- .../rx/operators/OperationDefaultIfEmpty.java | 44 - .../java/rx/operators/OperationDefer.java | 43 - .../rx/operators/OperationDematerialize.java | 53 -- .../java/rx/operators/OperationDistinct.java | 182 +--- .../OperationDistinctUntilChanged.java | 181 +--- .../java/rx/operators/OperationElementAt.java | 114 +-- .../java/rx/operators/OperationFilter.java | 30 - .../java/rx/operators/OperationFinally.java | 32 - .../rx/operators/OperationFirstOrDefault.java | 79 +- .../java/rx/operators/OperationGroupBy.java | 331 +------ .../java/rx/operators/OperationInterval.java | 174 +--- .../main/java/rx/operators/OperationMap.java | 273 ------ .../rx/operators/OperationMaterialize.java | 144 --- .../java/rx/operators/OperationMerge.java | 456 +--------- .../operators/OperationMergeDelayError.java | 500 +---------- .../rx/operators/OperationMostRecent.java | 61 +- .../java/rx/operators/OperationMulticast.java | 93 -- .../main/java/rx/operators/OperationNext.java | 298 +----- .../java/rx/operators/OperationObserveOn.java | 68 -- ...OperationOnErrorResumeNextViaFunction.java | 165 +--- ...erationOnErrorResumeNextViaObservable.java | 127 +-- .../rx/operators/OperationOnErrorReturn.java | 128 +-- ...ionOnExceptionResumeNextViaObservable.java | 224 +---- .../java/rx/operators/OperationParallel.java | 44 +- .../java/rx/operators/OperationRetry.java | 110 +-- .../java/rx/operators/OperationSample.java | 92 +- .../main/java/rx/operators/OperationScan.java | 95 -- .../main/java/rx/operators/OperationSkip.java | 44 +- .../java/rx/operators/OperationSkipLast.java | 106 +-- .../java/rx/operators/OperationSkipWhile.java | 101 +-- .../rx/operators/OperationSubscribeOn.java | 32 - .../main/java/rx/operators/OperationSum.java | 104 --- .../java/rx/operators/OperationSwitch.java | 368 -------- .../rx/operators/OperationSynchronize.java | 199 ---- .../main/java/rx/operators/OperationTake.java | 225 +---- .../java/rx/operators/OperationTakeLast.java | 107 +-- .../java/rx/operators/OperationTakeUntil.java | 160 ---- .../java/rx/operators/OperationTakeWhile.java | 216 +---- .../rx/operators/OperationThrottleFirst.java | 116 +-- .../rx/operators/OperationTimeInterval.java | 57 -- .../OperationToObservableFuture.java | 49 +- .../OperationToObservableIterable.java | 26 - .../operators/OperationToObservableList.java | 55 +- .../OperationToObservableSortedList.java | 54 +- .../java/rx/operators/OperationWindow.java | 308 +------ .../main/java/rx/operators/OperationZip.java | 596 +----------- .../java/rx/operators/OperatorTester.java | 97 -- .../operators/SafeObservableSubscription.java | 17 +- .../rx/operators/SynchronizedObserver.java | 756 ---------------- .../main/java/rx/plugins/RxJavaPlugins.java | 79 +- .../main/java/rx/subjects/AsyncSubject.java | 145 +-- .../java/rx/subjects/BehaviorSubject.java | 146 +-- .../main/java/rx/subjects/PublishSubject.java | 377 +------- .../main/java/rx/subjects/ReplaySubject.java | 184 +--- .../subscriptions/CompositeSubscription.java | 70 +- .../java/rx/subscriptions/Subscriptions.java | 21 +- rxjava-core/src/main/java/rx/util/Range.java | 49 - .../src/test/java/rx/SchedulersTest.java | 850 +++++++++--------- .../CurrentThreadSchedulerTest.java | 126 ++- .../concurrency/ImmediateSchedulerTest.java | 56 +- .../observables/BlockingObservableTest.java | 245 ++++- .../java/rx/operators/OperationAllTest.java | 81 +- .../java/rx/operators/OperationAnyTest.java | 179 +++- .../rx/operators/OperationAverageTest.java | 108 ++- .../rx/operators/OperationBufferTest.java | 347 ++++++- .../java/rx/operators/OperationCacheTest.java | 69 +- .../java/rx/operators/OperationCastTest.java | 37 +- .../operators/OperationCombineLatestTest.java | 616 ++++++++++++- .../rx/operators/OperationConcatTest.java | 541 ++++++++++- .../rx/operators/OperationDebounceTest.java | 143 ++- .../OperationDefaultIfEmptyTest.java | 41 +- .../java/rx/operators/OperationDeferTest.java | 44 +- .../operators/OperationDematerializeTest.java | 55 +- .../rx/operators/OperationDistinctTest.java | 179 +++- .../OperationDistinctUntilChangedTest.java | 182 +++- .../rx/operators/OperationElementAtTest.java | 110 ++- .../rx/operators/OperationFilterTest.java | 32 +- .../rx/operators/OperationFinallyTest.java | 35 +- .../OperationFirstOrDefaultTest.java | 75 +- .../rx/operators/OperationGroupByTest.java | 328 ++++++- .../rx/operators/OperationIntervalTest.java | 173 +++- .../java/rx/operators/OperationMapTest.java | 273 +++++- .../operators/OperationMaterializeTest.java | 147 ++- .../OperationMergeDelayErrorTest.java | 497 +++++++++- .../java/rx/operators/OperationMergeTest.java | 455 +++++++++- .../rx/operators/OperationMostRecentTest.java | 56 +- .../rx/operators/OperationMulticastTest.java | 94 +- .../java/rx/operators/OperationNextTest.java | 278 +++++- .../rx/operators/OperationObserveOnTest.java | 65 +- ...ationOnErrorResumeNextViaFunctionTest.java | 165 +++- ...ionOnErrorResumeNextViaObservableTest.java | 124 ++- .../operators/OperationOnErrorReturnTest.java | 127 ++- ...nExceptionResumeNextViaObservableTest.java | 221 ++++- .../rx/operators/OperationParallelTest.java | 42 +- .../java/rx/operators/OperationRetryTest.java | 111 ++- .../rx/operators/OperationSampleTest.java | 88 +- .../java/rx/operators/OperationScanTest.java | 99 +- .../rx/operators/OperationSkipLastTest.java | 95 +- .../java/rx/operators/OperationSkipTest.java | 39 +- .../rx/operators/OperationSkipWhileTest.java | 101 ++- .../operators/OperationSubscribeOnTest.java | 37 +- .../java/rx/operators/OperationSumTest.java | 110 ++- .../rx/operators/OperationSwitchTest.java | 365 +++++++- .../operators/OperationSynchronizeTest.java | 200 ++++- .../rx/operators/OperationTakeLastTest.java | 94 +- .../java/rx/operators/OperationTakeTest.java | 210 ++++- .../rx/operators/OperationTakeUntilTest.java | 161 +++- .../rx/operators/OperationTakeWhileTest.java | 204 +++++ .../operators/OperationThrottleFirstTest.java | 111 ++- .../operators/OperationTimeIntervalTest.java | 60 ++ .../OperationToObservableFutureTest.java | 44 +- .../OperationToObservableIterableTest.java | 27 +- .../OperationToObservableListTest.java | 50 +- .../OperationToObservableSortedListTest.java | 47 +- .../rx/operators/OperationWindowTest.java | 312 ++++++- .../java/rx/operators/OperationZipTest.java | 579 +++++++++++- .../SafeObservableSubscriptionTest.java | 16 +- .../operators/SynchronizedObserverTest.java | 748 ++++++++++++++- .../java/rx/plugins/RxJavaPluginsTest.java | 74 +- .../java/rx/subjects/AsyncSubjectTest.java | 132 ++- .../java/rx/subjects/BehaviorSubjectTest.java | 132 ++- .../java/rx/subjects/PublishSubjectTest.java | 361 +++++++- .../java/rx/subjects/ReplaySubjectTest.java | 166 +++- .../CompositeSubscriptionTest.java | 67 +- .../rx/subscriptions/SubscriptionsTest.java | 17 +- .../src/test/java/rx/test/OperatorTester.java | 94 ++ .../src/test/java/rx/util/RangeTest.java | 47 +- 140 files changed, 11833 insertions(+), 12067 deletions(-) delete mode 100644 rxjava-core/src/main/java/rx/operators/OperatorTester.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationTakeWhileTest.java create mode 100644 rxjava-core/src/test/java/rx/operators/OperationTimeIntervalTest.java create mode 100644 rxjava-core/src/test/java/rx/test/OperatorTester.java diff --git a/rxjava-core/src/main/java/rx/Scheduler.java b/rxjava-core/src/main/java/rx/Scheduler.java index cb3430c1f3..3da38f41f2 100644 --- a/rxjava-core/src/main/java/rx/Scheduler.java +++ b/rxjava-core/src/main/java/rx/Scheduler.java @@ -15,26 +15,17 @@ */ package rx; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.Date; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.Mockito; - -import rx.concurrency.TestScheduler; import rx.subscriptions.CompositeSubscription; import rx.subscriptions.MultipleAssignmentSubscription; import rx.subscriptions.Subscriptions; import rx.util.functions.Action0; import rx.util.functions.Action1; -import rx.util.functions.Func1; import rx.util.functions.Func2; +import java.util.Date; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + /** * Represents an object that schedules units of work. *

@@ -264,46 +255,4 @@ public long now() { public int degreeOfParallelism() { return Runtime.getRuntime().availableProcessors(); } - - public static class UnitTest { - @SuppressWarnings("unchecked") - // mocking is unchecked, unfortunately - @Test - public void testPeriodicScheduling() { - final Func1 calledOp = mock(Func1.class); - - final TestScheduler scheduler = new TestScheduler(); - Subscription subscription = scheduler.schedulePeriodically(new Action0() { - @Override - public void call() { - System.out.println(scheduler.now()); - calledOp.call(scheduler.now()); - } - }, 1, 2, TimeUnit.SECONDS); - - verify(calledOp, never()).call(anyLong()); - - InOrder inOrder = Mockito.inOrder(calledOp); - - scheduler.advanceTimeBy(999L, TimeUnit.MILLISECONDS); - inOrder.verify(calledOp, never()).call(anyLong()); - - scheduler.advanceTimeBy(1L, TimeUnit.MILLISECONDS); - inOrder.verify(calledOp, times(1)).call(1000L); - - scheduler.advanceTimeBy(1999L, TimeUnit.MILLISECONDS); - inOrder.verify(calledOp, never()).call(3000L); - - scheduler.advanceTimeBy(1L, TimeUnit.MILLISECONDS); - inOrder.verify(calledOp, times(1)).call(3000L); - - scheduler.advanceTimeBy(5L, TimeUnit.SECONDS); - inOrder.verify(calledOp, times(1)).call(5000L); - inOrder.verify(calledOp, times(1)).call(7000L); - - subscription.unsubscribe(); - scheduler.advanceTimeBy(11L, TimeUnit.SECONDS); - inOrder.verify(calledOp, never()).call(anyLong()); - } - } } diff --git a/rxjava-core/src/main/java/rx/concurrency/CurrentThreadScheduler.java b/rxjava-core/src/main/java/rx/concurrency/CurrentThreadScheduler.java index 455b49d04c..a096ef06e2 100644 --- a/rxjava-core/src/main/java/rx/concurrency/CurrentThreadScheduler.java +++ b/rxjava-core/src/main/java/rx/concurrency/CurrentThreadScheduler.java @@ -15,20 +15,14 @@ */ package rx.concurrency; -import static org.mockito.Mockito.*; +import rx.Scheduler; +import rx.Subscription; +import rx.util.functions.Func2; import java.util.PriorityQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import org.junit.Test; -import org.mockito.InOrder; - -import rx.Scheduler; -import rx.Subscription; -import rx.util.functions.Action0; -import rx.util.functions.Func2; - /** * Schedules work on the current thread but does not execute immediately. Work is put in a queue and executed after the current unit of work is completed. */ @@ -41,7 +35,7 @@ public static CurrentThreadScheduler getInstance() { private static final ThreadLocal> QUEUE = new ThreadLocal>(); - private CurrentThreadScheduler() { + CurrentThreadScheduler() { } private final AtomicInteger counter = new AtomicInteger(0); @@ -102,126 +96,4 @@ public int compareTo(TimedAction that) { return result; } } - - public static class UnitTest { - - @Test - public void testNestedActions() { - final CurrentThreadScheduler scheduler = new CurrentThreadScheduler(); - - final Action0 firstStepStart = mock(Action0.class); - final Action0 firstStepEnd = mock(Action0.class); - - final Action0 secondStepStart = mock(Action0.class); - final Action0 secondStepEnd = mock(Action0.class); - - final Action0 thirdStepStart = mock(Action0.class); - final Action0 thirdStepEnd = mock(Action0.class); - - final Action0 firstAction = new Action0() { - @Override - public void call() { - firstStepStart.call(); - firstStepEnd.call(); - } - }; - final Action0 secondAction = new Action0() { - @Override - public void call() { - secondStepStart.call(); - scheduler.schedule(firstAction); - secondStepEnd.call(); - - } - }; - final Action0 thirdAction = new Action0() { - @Override - public void call() { - thirdStepStart.call(); - scheduler.schedule(secondAction); - thirdStepEnd.call(); - } - }; - - InOrder inOrder = inOrder(firstStepStart, firstStepEnd, secondStepStart, secondStepEnd, thirdStepStart, thirdStepEnd); - - scheduler.schedule(thirdAction); - - inOrder.verify(thirdStepStart, times(1)).call(); - inOrder.verify(thirdStepEnd, times(1)).call(); - inOrder.verify(secondStepStart, times(1)).call(); - inOrder.verify(secondStepEnd, times(1)).call(); - inOrder.verify(firstStepStart, times(1)).call(); - inOrder.verify(firstStepEnd, times(1)).call(); - } - - @Test - public void testSequenceOfActions() { - final CurrentThreadScheduler scheduler = new CurrentThreadScheduler(); - - final Action0 first = mock(Action0.class); - final Action0 second = mock(Action0.class); - - scheduler.schedule(first); - scheduler.schedule(second); - - verify(first, times(1)).call(); - verify(second, times(1)).call(); - - } - - @Test - public void testSequenceOfDelayedActions() { - final CurrentThreadScheduler scheduler = new CurrentThreadScheduler(); - - final Action0 first = mock(Action0.class); - final Action0 second = mock(Action0.class); - - scheduler.schedule(new Action0() { - @Override - public void call() { - scheduler.schedule(first, 30, TimeUnit.MILLISECONDS); - scheduler.schedule(second, 10, TimeUnit.MILLISECONDS); - } - }); - - InOrder inOrder = inOrder(first, second); - - inOrder.verify(second, times(1)).call(); - inOrder.verify(first, times(1)).call(); - - - } - - @Test - public void testMixOfDelayedAndNonDelayedActions() { - final CurrentThreadScheduler scheduler = new CurrentThreadScheduler(); - - final Action0 first = mock(Action0.class); - final Action0 second = mock(Action0.class); - final Action0 third = mock(Action0.class); - final Action0 fourth = mock(Action0.class); - - scheduler.schedule(new Action0() { - @Override - public void call() { - scheduler.schedule(first); - scheduler.schedule(second, 300, TimeUnit.MILLISECONDS); - scheduler.schedule(third, 100, TimeUnit.MILLISECONDS); - scheduler.schedule(fourth); - } - }); - - InOrder inOrder = inOrder(first, second, third, fourth); - - inOrder.verify(first, times(1)).call(); - inOrder.verify(fourth, times(1)).call(); - inOrder.verify(third, times(1)).call(); - inOrder.verify(second, times(1)).call(); - - - } - - } - } diff --git a/rxjava-core/src/main/java/rx/concurrency/ImmediateScheduler.java b/rxjava-core/src/main/java/rx/concurrency/ImmediateScheduler.java index f3f4353bb7..d1d00355f4 100644 --- a/rxjava-core/src/main/java/rx/concurrency/ImmediateScheduler.java +++ b/rxjava-core/src/main/java/rx/concurrency/ImmediateScheduler.java @@ -1,12 +1,12 @@ /** * Copyright 2013 Netflix, Inc. - * + * * 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. @@ -15,96 +15,35 @@ */ package rx.concurrency; -import static org.mockito.Mockito.*; - -import java.util.concurrent.TimeUnit; - -import org.junit.Test; -import org.mockito.InOrder; - import rx.Scheduler; import rx.Subscription; -import rx.util.functions.Action0; import rx.util.functions.Func2; +import java.util.concurrent.TimeUnit; + /** * Executes work immediately on the current thread. */ public final class ImmediateScheduler extends Scheduler { - private static final ImmediateScheduler INSTANCE = new ImmediateScheduler(); - - public static ImmediateScheduler getInstance() { - return INSTANCE; - } - - private ImmediateScheduler() { - } - - @Override - public Subscription schedule(T state, Func2 action) { - return action.call(this, state); - } - - @Override - public Subscription schedule(T state, Func2 action, long dueTime, TimeUnit unit) { - // since we are executing immediately on this thread we must cause this thread to sleep - long execTime = now() + unit.toMillis(dueTime); - - return schedule(state, new SleepingAction(action, this, execTime)); - } - - public static class UnitTest { - - @Test - public void testNestedActions() { - final ImmediateScheduler scheduler = new ImmediateScheduler(); - - final Action0 firstStepStart = mock(Action0.class); - final Action0 firstStepEnd = mock(Action0.class); - - final Action0 secondStepStart = mock(Action0.class); - final Action0 secondStepEnd = mock(Action0.class); - - final Action0 thirdStepStart = mock(Action0.class); - final Action0 thirdStepEnd = mock(Action0.class); - - final Action0 firstAction = new Action0() { - @Override - public void call() { - firstStepStart.call(); - firstStepEnd.call(); - } - }; - final Action0 secondAction = new Action0() { - @Override - public void call() { - secondStepStart.call(); - scheduler.schedule(firstAction); - secondStepEnd.call(); - - } - }; - final Action0 thirdAction = new Action0() { - @Override - public void call() { - thirdStepStart.call(); - scheduler.schedule(secondAction); - thirdStepEnd.call(); - } - }; + private static final ImmediateScheduler INSTANCE = new ImmediateScheduler(); - InOrder inOrder = inOrder(firstStepStart, firstStepEnd, secondStepStart, secondStepEnd, thirdStepStart, thirdStepEnd); + public static ImmediateScheduler getInstance() { + return INSTANCE; + } - scheduler.schedule(thirdAction); + ImmediateScheduler() { + } - inOrder.verify(thirdStepStart, times(1)).call(); - inOrder.verify(secondStepStart, times(1)).call(); - inOrder.verify(firstStepStart, times(1)).call(); - inOrder.verify(firstStepEnd, times(1)).call(); - inOrder.verify(secondStepEnd, times(1)).call(); - inOrder.verify(thirdStepEnd, times(1)).call(); - } + @Override + public Subscription schedule(T state, Func2 action) { + return action.call(this, state); + } - } + @Override + public Subscription schedule(T state, Func2 action, long dueTime, TimeUnit unit) { + // since we are executing immediately on this thread we must cause this thread to sleep + long execTime = now() + unit.toMillis(dueTime); + return schedule(state, new SleepingAction(action, this, execTime)); + } } diff --git a/rxjava-core/src/main/java/rx/observables/BlockingObservable.java b/rxjava-core/src/main/java/rx/observables/BlockingObservable.java index 32e2db7400..b59f34d78c 100644 --- a/rxjava-core/src/main/java/rx/observables/BlockingObservable.java +++ b/rxjava-core/src/main/java/rx/observables/BlockingObservable.java @@ -15,33 +15,18 @@ */ package rx.observables; -import static org.junit.Assert.*; - -import java.util.Iterator; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicReference; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - import rx.Observable; -import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; -import rx.operators.OperationMostRecent; -import rx.operators.OperationNext; -import rx.operators.OperationToFuture; -import rx.operators.OperationToIterator; -import rx.operators.SafeObservableSubscription; -import rx.operators.SafeObserver; -import rx.subscriptions.BooleanSubscription; -import rx.subscriptions.Subscriptions; +import rx.operators.*; import rx.util.functions.Action1; import rx.util.functions.Func1; +import java.util.Iterator; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicReference; + /** * An extension of {@link Observable} that provides blocking operators. *

@@ -367,235 +352,4 @@ public Iterator iterator() { } }; } - - public static class UnitTest { - - @Mock - Observer w; - - @Before - public void before() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testLast() { - BlockingObservable obs = BlockingObservable.from(Observable.from("one", "two", "three")); - - assertEquals("three", obs.last()); - } - - @Test - public void testLastEmptyObservable() { - BlockingObservable obs = BlockingObservable.from(Observable.empty()); - - assertNull(obs.last()); - } - - @Test - public void testLastOrDefault() { - BlockingObservable observable = BlockingObservable.from(Observable.from(1, 0, -1)); - int last = observable.lastOrDefault(-100, new Func1() { - @Override - public Boolean call(Integer args) { - return args >= 0; - } - }); - assertEquals(0, last); - } - - @Test - public void testLastOrDefault1() { - BlockingObservable observable = BlockingObservable.from(Observable.from("one", "two", "three")); - assertEquals("three", observable.lastOrDefault("default")); - } - - @Test - public void testLastOrDefault2() { - BlockingObservable observable = BlockingObservable.from(Observable.empty()); - assertEquals("default", observable.lastOrDefault("default")); - } - - @Test - public void testLastOrDefaultWithPredicate() { - BlockingObservable observable = BlockingObservable.from(Observable.from(1, 0, -1)); - int last = observable.lastOrDefault(0, new Func1() { - @Override - public Boolean call(Integer args) { - return args < 0; - } - }); - - assertEquals(-1, last); - } - - @Test - public void testLastOrDefaultWrongPredicate() { - BlockingObservable observable = BlockingObservable.from(Observable.from(-1, -2, -3)); - int last = observable.lastOrDefault(0, new Func1() { - @Override - public Boolean call(Integer args) { - return args >= 0; - } - }); - assertEquals(0, last); - } - - @Test - public void testLastWithPredicate() { - BlockingObservable obs = BlockingObservable.from(Observable.from("one", "two", "three")); - - assertEquals("two", obs.last(new Func1() { - @Override - public Boolean call(String s) { - return s.length() == 3; - } - })); - } - - public void testSingle() { - BlockingObservable observable = BlockingObservable.from(Observable.from("one")); - assertEquals("one", observable.single()); - } - - @Test - public void testSingleDefault() { - BlockingObservable observable = BlockingObservable.from(Observable.empty()); - assertEquals("default", observable.singleOrDefault("default")); - } - - @Test(expected = IllegalStateException.class) - public void testSingleDefaultPredicateMatchesMoreThanOne() { - BlockingObservable.from(Observable.from("one", "two")).singleOrDefault("default", new Func1() { - @Override - public Boolean call(String args) { - return args.length() == 3; - } - }); - } - - @Test - public void testSingleDefaultPredicateMatchesNothing() { - BlockingObservable observable = BlockingObservable.from(Observable.from("one", "two")); - String result = observable.singleOrDefault("default", new Func1() { - @Override - public Boolean call(String args) { - return args.length() == 4; - } - }); - assertEquals("default", result); - } - - @Test(expected = IllegalStateException.class) - public void testSingleDefaultWithMoreThanOne() { - BlockingObservable observable = BlockingObservable.from(Observable.from("one", "two", "three")); - observable.singleOrDefault("default"); - } - - @Test - public void testSingleWithPredicateDefault() { - BlockingObservable observable = BlockingObservable.from(Observable.from("one", "two", "four")); - assertEquals("four", observable.single(new Func1() { - @Override - public Boolean call(String s) { - return s.length() == 4; - } - })); - } - - @Test(expected = IllegalStateException.class) - public void testSingleWrong() { - BlockingObservable observable = BlockingObservable.from(Observable.from(1, 2)); - observable.single(); - } - - @Test(expected = IllegalStateException.class) - public void testSingleWrongPredicate() { - BlockingObservable observable = BlockingObservable.from(Observable.from(-1)); - observable.single(new Func1() { - @Override - public Boolean call(Integer args) { - return args > 0; - } - }); - } - - @Test - public void testToIterable() { - BlockingObservable obs = BlockingObservable.from(Observable.from("one", "two", "three")); - - Iterator it = obs.toIterable().iterator(); - - assertEquals(true, it.hasNext()); - assertEquals("one", it.next()); - - assertEquals(true, it.hasNext()); - assertEquals("two", it.next()); - - assertEquals(true, it.hasNext()); - assertEquals("three", it.next()); - - assertEquals(false, it.hasNext()); - - } - - @Test(expected = TestException.class) - public void testToIterableWithException() { - BlockingObservable obs = BlockingObservable.from(Observable.create(new OnSubscribeFunc() { - - @Override - public Subscription onSubscribe(Observer observer) { - observer.onNext("one"); - observer.onError(new TestException()); - return Subscriptions.empty(); - } - })); - - Iterator it = obs.toIterable().iterator(); - - assertEquals(true, it.hasNext()); - assertEquals("one", it.next()); - - assertEquals(true, it.hasNext()); - it.next(); - - } - - @Test - public void testForEachWithError() { - try { - BlockingObservable.from(Observable.create(new OnSubscribeFunc() { - - @Override - public Subscription onSubscribe(final Observer observer) { - final BooleanSubscription subscription = new BooleanSubscription(); - new Thread(new Runnable() { - - @Override - public void run() { - observer.onNext("one"); - observer.onNext("two"); - observer.onNext("three"); - observer.onCompleted(); - } - }).start(); - return subscription; - } - })).forEach(new Action1() { - - @Override - public void call(String t1) { - throw new RuntimeException("fail"); - } - }); - fail("we expect an exception to be thrown"); - } catch (Throwable e) { - // do nothing as we expect this - } - } - - private static class TestException extends RuntimeException { - private static final long serialVersionUID = 1L; - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationAll.java b/rxjava-core/src/main/java/rx/operators/OperationAll.java index e0a18154c0..908fd1f54e 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationAll.java +++ b/rxjava-core/src/main/java/rx/operators/OperationAll.java @@ -15,18 +15,14 @@ */ package rx.operators; -import static org.mockito.Mockito.*; - -import java.util.concurrent.atomic.AtomicBoolean; - -import org.junit.Test; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; import rx.util.functions.Func1; +import java.util.concurrent.atomic.AtomicBoolean; + /** * Returns an Observable that emits a Boolean that indicates whether all items emitted by an * Observable satisfy a condition. @@ -94,79 +90,4 @@ public void onNext(T args) { } } - - public static class UnitTest { - - @Test - @SuppressWarnings("unchecked") - public void testAll() { - Observable obs = Observable.from("one", "two", "six"); - - Observer observer = mock(Observer.class); - Observable.create(all(obs, new Func1() { - @Override - public Boolean call(String s) { - return s.length() == 3; - } - })).subscribe(observer); - - verify(observer).onNext(true); - verify(observer).onCompleted(); - verifyNoMoreInteractions(observer); - } - - @Test - @SuppressWarnings("unchecked") - public void testNotAll() { - Observable obs = Observable.from("one", "two", "three", "six"); - - Observer observer = mock(Observer.class); - Observable.create(all(obs, new Func1() { - @Override - public Boolean call(String s) { - return s.length() == 3; - } - })).subscribe(observer); - - verify(observer).onNext(false); - verify(observer).onCompleted(); - verifyNoMoreInteractions(observer); - } - - @Test - @SuppressWarnings("unchecked") - public void testEmpty() { - Observable obs = Observable.empty(); - - Observer observer = mock(Observer.class); - Observable.create(all(obs, new Func1() { - @Override - public Boolean call(String s) { - return s.length() == 3; - } - })).subscribe(observer); - - verify(observer).onNext(true); - verify(observer).onCompleted(); - verifyNoMoreInteractions(observer); - } - - @Test - @SuppressWarnings("unchecked") - public void testError() { - Throwable error = new Throwable(); - Observable obs = Observable.error(error); - - Observer observer = mock(Observer.class); - Observable.create(all(obs, new Func1() { - @Override - public Boolean call(String s) { - return s.length() == 3; - } - })).subscribe(observer); - - verify(observer).onError(error); - verifyNoMoreInteractions(observer); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationAny.java b/rxjava-core/src/main/java/rx/operators/OperationAny.java index a5f12c224f..5830fbb1f2 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationAny.java +++ b/rxjava-core/src/main/java/rx/operators/OperationAny.java @@ -15,19 +15,16 @@ */ package rx.operators; -import static org.mockito.Mockito.*; -import static rx.util.functions.Functions.*; - -import java.util.concurrent.atomic.AtomicBoolean; - -import org.junit.Test; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; import rx.util.functions.Func1; +import java.util.concurrent.atomic.AtomicBoolean; + +import static rx.util.functions.Functions.alwaysTrue; + /** * Returns an {@link Observable} that emits true if any element of * an observable sequence satisfies a condition, otherwise false. @@ -126,176 +123,4 @@ public void onCompleted() { } } - - public static class UnitTest { - - @Test - public void testAnyWithTwoItems() { - Observable w = Observable.from(1, 2); - Observable observable = Observable.create(any(w)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, never()).onNext(false); - verify(aObserver, times(1)).onNext(true); - verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testIsEmptyWithTwoItems() { - Observable w = Observable.from(1, 2); - Observable observable = Observable.create(isEmpty(w)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, never()).onNext(true); - verify(aObserver, times(1)).onNext(false); - verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testAnyWithOneItem() { - Observable w = Observable.from(1); - Observable observable = Observable.create(any(w)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, never()).onNext(false); - verify(aObserver, times(1)).onNext(true); - verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testIsEmptyWithOneItem() { - Observable w = Observable.from(1); - Observable observable = Observable.create(isEmpty(w)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, never()).onNext(true); - verify(aObserver, times(1)).onNext(false); - verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testAnyWithEmpty() { - Observable w = Observable.empty(); - Observable observable = Observable.create(any(w)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, times(1)).onNext(false); - verify(aObserver, never()).onNext(true); - verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testIsEmptyWithEmpty() { - Observable w = Observable.empty(); - Observable observable = Observable.create(isEmpty(w)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, times(1)).onNext(true); - verify(aObserver, never()).onNext(false); - verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testAnyWithPredicate1() { - Observable w = Observable.from(1, 2, 3); - Observable observable = Observable.create(any(w, - new Func1() { - - @Override - public Boolean call(Integer t1) { - return t1 < 2; - } - })); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, never()).onNext(false); - verify(aObserver, times(1)).onNext(true); - verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testExists1() { - Observable w = Observable.from(1, 2, 3); - Observable observable = Observable.create(exists(w, - new Func1() { - - @Override - public Boolean call(Integer t1) { - return t1 < 2; - } - })); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, never()).onNext(false); - verify(aObserver, times(1)).onNext(true); - verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testAnyWithPredicate2() { - Observable w = Observable.from(1, 2, 3); - Observable observable = Observable.create(any(w, - new Func1() { - - @Override - public Boolean call(Integer t1) { - return t1 < 1; - } - })); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, times(1)).onNext(false); - verify(aObserver, never()).onNext(true); - verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testAnyWithEmptyAndPredicate() { - // If the source is empty, always output false. - Observable w = Observable.empty(); - Observable observable = Observable.create(any(w, - new Func1() { - - @Override - public Boolean call(Integer t1) { - return true; - } - })); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, times(1)).onNext(false); - verify(aObserver, never()).onNext(true); - verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationAverage.java b/rxjava-core/src/main/java/rx/operators/OperationAverage.java index 054a117053..c130396f2a 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationAverage.java +++ b/rxjava-core/src/main/java/rx/operators/OperationAverage.java @@ -15,12 +15,7 @@ */ package rx.operators; -import static org.mockito.Mockito.*; - -import org.junit.Test; - import rx.Observable; -import rx.Observer; import rx.util.functions.Func1; import rx.util.functions.Func2; @@ -100,99 +95,4 @@ public Double call(Tuple2 result) { } }); } - - public static class UnitTest { - @SuppressWarnings("unchecked") - Observer w = mock(Observer.class); - @SuppressWarnings("unchecked") - Observer wl = mock(Observer.class); - @SuppressWarnings("unchecked") - Observer wf = mock(Observer.class); - @SuppressWarnings("unchecked") - Observer wd = mock(Observer.class); - - @Test - public void testAverageOfAFewInts() throws Throwable { - Observable src = Observable.from(1, 2, 3, 4, 6); - average(src).subscribe(w); - - verify(w, times(1)).onNext(anyInt()); - verify(w).onNext(3); - verify(w, never()).onError(any(Throwable.class)); - verify(w, times(1)).onCompleted(); - } - - @Test - public void testEmptyAverage() throws Throwable { - Observable src = Observable.empty(); - average(src).subscribe(w); - - verify(w, never()).onNext(anyInt()); - verify(w, times(1)).onError(any(ArithmeticException.class)); - verify(w, never()).onCompleted(); - } - - @Test - public void testAverageOfAFewLongs() throws Throwable { - Observable src = Observable.from(1L, 2L, 3L, 4L, 6L); - averageLongs(src).subscribe(wl); - - verify(wl, times(1)).onNext(anyLong()); - verify(wl).onNext(3L); - verify(wl, never()).onError(any(Throwable.class)); - verify(wl, times(1)).onCompleted(); - } - - @Test - public void testEmptyAverageLongs() throws Throwable { - Observable src = Observable.empty(); - averageLongs(src).subscribe(wl); - - verify(wl, never()).onNext(anyLong()); - verify(wl, times(1)).onError(any(ArithmeticException.class)); - verify(wl, never()).onCompleted(); - } - - @Test - public void testAverageOfAFewFloats() throws Throwable { - Observable src = Observable.from(1.0f, 2.0f); - averageFloats(src).subscribe(wf); - - verify(wf, times(1)).onNext(anyFloat()); - verify(wf).onNext(1.5f); - verify(wf, never()).onError(any(Throwable.class)); - verify(wf, times(1)).onCompleted(); - } - - @Test - public void testEmptyAverageFloats() throws Throwable { - Observable src = Observable.empty(); - averageFloats(src).subscribe(wf); - - verify(wf, never()).onNext(anyFloat()); - verify(wf, times(1)).onError(any(ArithmeticException.class)); - verify(wf, never()).onCompleted(); - } - - @Test - public void testAverageOfAFewDoubles() throws Throwable { - Observable src = Observable.from(1.0d, 2.0d); - averageDoubles(src).subscribe(wd); - - verify(wd, times(1)).onNext(anyDouble()); - verify(wd).onNext(1.5d); - verify(wd, never()).onError(any(Throwable.class)); - verify(wd, times(1)).onCompleted(); - } - - @Test - public void testEmptyAverageDoubles() throws Throwable { - Observable src = Observable.empty(); - averageDoubles(src).subscribe(wd); - - verify(wd, never()).onNext(anyDouble()); - verify(wd, times(1)).onError(any(ArithmeticException.class)); - verify(wd, never()).onCompleted(); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationBuffer.java b/rxjava-core/src/main/java/rx/operators/OperationBuffer.java index 898260d0ef..03d2dc02b8 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationBuffer.java +++ b/rxjava-core/src/main/java/rx/operators/OperationBuffer.java @@ -15,35 +15,20 @@ */ package rx.operators; -import static org.junit.Assert.assertFalse; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.Mockito; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Scheduler; import rx.Subscription; import rx.concurrency.Schedulers; -import rx.concurrency.TestScheduler; -import rx.subscriptions.Subscriptions; import rx.util.Closing; -import rx.util.Closings; import rx.util.Opening; -import rx.util.Openings; -import rx.util.functions.Action0; -import rx.util.functions.Action1; import rx.util.functions.Func0; import rx.util.functions.Func1; +import java.util.List; +import java.util.concurrent.TimeUnit; + public final class OperationBuffer extends ChunkedOperation { private static Func0> bufferMaker() { @@ -372,327 +357,4 @@ public List getContents() { return contents; } } - - public static class UnitTest { - - private Observer> observer; - private TestScheduler scheduler; - - @Before - @SuppressWarnings("unchecked") - public void before() { - observer = Mockito.mock(Observer.class); - scheduler = new TestScheduler(); - } - - @Test - public void testComplete() { - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - observer.onCompleted(); - return Subscriptions.empty(); - } - }); - - Observable> buffered = Observable.create(buffer(source, 3, 3)); - buffered.subscribe(observer); - - Mockito.verify(observer, Mockito.never()).onNext(Mockito.anyListOf(String.class)); - Mockito.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); - Mockito.verify(observer, Mockito.times(1)).onCompleted(); - } - - @Test - public void testSkipAndCountOverlappingBuffers() { - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - observer.onNext("one"); - observer.onNext("two"); - observer.onNext("three"); - observer.onNext("four"); - observer.onNext("five"); - return Subscriptions.empty(); - } - }); - - Observable> buffered = Observable.create(buffer(source, 3, 1)); - buffered.subscribe(observer); - - InOrder inOrder = Mockito.inOrder(observer); - inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two", "three")); - inOrder.verify(observer, Mockito.times(1)).onNext(list("two", "three", "four")); - inOrder.verify(observer, Mockito.times(1)).onNext(list("three", "four", "five")); - inOrder.verify(observer, Mockito.never()).onNext(Mockito.anyListOf(String.class)); - inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); - inOrder.verify(observer, Mockito.never()).onCompleted(); - } - - @Test - public void testSkipAndCountGaplessBuffers() { - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - observer.onNext("one"); - observer.onNext("two"); - observer.onNext("three"); - observer.onNext("four"); - observer.onNext("five"); - observer.onCompleted(); - return Subscriptions.empty(); - } - }); - - Observable> buffered = Observable.create(buffer(source, 3, 3)); - buffered.subscribe(observer); - - InOrder inOrder = Mockito.inOrder(observer); - inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two", "three")); - inOrder.verify(observer, Mockito.times(1)).onNext(list("four", "five")); - inOrder.verify(observer, Mockito.never()).onNext(Mockito.anyListOf(String.class)); - inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); - inOrder.verify(observer, Mockito.times(1)).onCompleted(); - } - - @Test - public void testSkipAndCountBuffersWithGaps() { - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - observer.onNext("one"); - observer.onNext("two"); - observer.onNext("three"); - observer.onNext("four"); - observer.onNext("five"); - observer.onCompleted(); - return Subscriptions.empty(); - } - }); - - Observable> buffered = Observable.create(buffer(source, 2, 3)); - buffered.subscribe(observer); - - InOrder inOrder = Mockito.inOrder(observer); - inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two")); - inOrder.verify(observer, Mockito.times(1)).onNext(list("four", "five")); - inOrder.verify(observer, Mockito.never()).onNext(Mockito.anyListOf(String.class)); - inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); - inOrder.verify(observer, Mockito.times(1)).onCompleted(); - } - - @Test - public void testTimedAndCount() { - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - push(observer, "one", 10); - push(observer, "two", 90); - push(observer, "three", 110); - push(observer, "four", 190); - push(observer, "five", 210); - complete(observer, 250); - return Subscriptions.empty(); - } - }); - - Observable> buffered = Observable.create(buffer(source, 100, TimeUnit.MILLISECONDS, 2, scheduler)); - buffered.subscribe(observer); - - InOrder inOrder = Mockito.inOrder(observer); - scheduler.advanceTimeTo(100, TimeUnit.MILLISECONDS); - inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two")); - - scheduler.advanceTimeTo(200, TimeUnit.MILLISECONDS); - inOrder.verify(observer, Mockito.times(1)).onNext(list("three", "four")); - - scheduler.advanceTimeTo(300, TimeUnit.MILLISECONDS); - inOrder.verify(observer, Mockito.times(1)).onNext(list("five")); - inOrder.verify(observer, Mockito.never()).onNext(Mockito.anyListOf(String.class)); - inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); - inOrder.verify(observer, Mockito.times(1)).onCompleted(); - } - - @Test - public void testTimed() { - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - push(observer, "one", 98); - push(observer, "two", 99); - push(observer, "three", 100); - push(observer, "four", 101); - push(observer, "five", 102); - complete(observer, 150); - return Subscriptions.empty(); - } - }); - - Observable> buffered = Observable.create(buffer(source, 100, TimeUnit.MILLISECONDS, scheduler)); - buffered.subscribe(observer); - - InOrder inOrder = Mockito.inOrder(observer); - scheduler.advanceTimeTo(101, TimeUnit.MILLISECONDS); - inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two", "three")); - - scheduler.advanceTimeTo(201, TimeUnit.MILLISECONDS); - inOrder.verify(observer, Mockito.times(1)).onNext(list("four", "five")); - inOrder.verify(observer, Mockito.never()).onNext(Mockito.anyListOf(String.class)); - inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); - inOrder.verify(observer, Mockito.times(1)).onCompleted(); - } - - @Test - public void testObservableBasedOpenerAndCloser() { - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - push(observer, "one", 10); - push(observer, "two", 60); - push(observer, "three", 110); - push(observer, "four", 160); - push(observer, "five", 210); - complete(observer, 500); - return Subscriptions.empty(); - } - }); - - Observable openings = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - push(observer, Openings.create(), 50); - push(observer, Openings.create(), 200); - complete(observer, 250); - return Subscriptions.empty(); - } - }); - - Func1> closer = new Func1>() { - @Override - public Observable call(Opening opening) { - return Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - push(observer, Closings.create(), 100); - complete(observer, 101); - return Subscriptions.empty(); - } - }); - } - }; - - Observable> buffered = Observable.create(buffer(source, openings, closer)); - buffered.subscribe(observer); - - InOrder inOrder = Mockito.inOrder(observer); - scheduler.advanceTimeTo(500, TimeUnit.MILLISECONDS); - inOrder.verify(observer, Mockito.times(1)).onNext(list("two", "three")); - inOrder.verify(observer, Mockito.times(1)).onNext(list("five")); - inOrder.verify(observer, Mockito.never()).onNext(Mockito.anyListOf(String.class)); - inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); - inOrder.verify(observer, Mockito.times(1)).onCompleted(); - } - - @Test - public void testObservableBasedCloser() { - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - push(observer, "one", 10); - push(observer, "two", 60); - push(observer, "three", 110); - push(observer, "four", 160); - push(observer, "five", 210); - complete(observer, 250); - return Subscriptions.empty(); - } - }); - - Func0> closer = new Func0>() { - @Override - public Observable call() { - return Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - push(observer, Closings.create(), 100); - complete(observer, 101); - return Subscriptions.empty(); - } - }); - } - }; - - Observable> buffered = Observable.create(buffer(source, closer)); - buffered.subscribe(observer); - - InOrder inOrder = Mockito.inOrder(observer); - scheduler.advanceTimeTo(500, TimeUnit.MILLISECONDS); - inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two")); - inOrder.verify(observer, Mockito.times(1)).onNext(list("three", "four")); - inOrder.verify(observer, Mockito.times(1)).onNext(list("five")); - inOrder.verify(observer, Mockito.never()).onNext(Mockito.anyListOf(String.class)); - inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); - inOrder.verify(observer, Mockito.times(1)).onCompleted(); - } - - @Test - public void testLongTimeAction() throws InterruptedException { - final CountDownLatch latch = new CountDownLatch(1); - LongTimeAction action = new LongTimeAction(latch); - Observable.from(1).buffer(10, TimeUnit.MILLISECONDS, 10) - .subscribe(action); - latch.await(); - assertFalse(action.fail); - } - - private static class LongTimeAction implements Action1> { - - CountDownLatch latch; - boolean fail = false; - - public LongTimeAction(CountDownLatch latch) { - this.latch = latch; - } - - @Override - public void call(List t1) { - try { - if (fail) { - return; - } - Thread.sleep(200); - } catch (InterruptedException e) { - fail = true; - } finally { - latch.countDown(); - } - } - } - - private List list(String... args) { - List list = new ArrayList(); - for (String arg : args) { - list.add(arg); - } - return list; - } - - private void push(final Observer observer, final T value, int delay) { - scheduler.schedule(new Action0() { - @Override - public void call() { - observer.onNext(value); - } - }, delay, TimeUnit.MILLISECONDS); - } - - private void complete(final Observer observer, int delay) { - scheduler.schedule(new Action0() { - @Override - public void call() { - observer.onCompleted(); - } - }, delay, TimeUnit.MILLISECONDS); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationCache.java b/rxjava-core/src/main/java/rx/operators/OperationCache.java index e5f8ce69e3..44749bbd15 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationCache.java +++ b/rxjava-core/src/main/java/rx/operators/OperationCache.java @@ -15,22 +15,13 @@ */ package rx.operators; -import static org.junit.Assert.*; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -import org.junit.Test; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; import rx.subjects.ReplaySubject; -import rx.subscriptions.BooleanSubscription; -import rx.util.functions.Action1; + +import java.util.concurrent.atomic.AtomicBoolean; /** * This method has similar behavior to {@link Observable#replay()} except that this auto-subscribes @@ -70,61 +61,4 @@ public Subscription onSubscribe(Observer observer) { }; } - - public static class UnitTest { - - @Test - public void testCache() throws InterruptedException { - final AtomicInteger counter = new AtomicInteger(); - Observable o = Observable.create(cache(Observable.create(new OnSubscribeFunc() { - - @Override - public Subscription onSubscribe(final Observer observer) { - final BooleanSubscription subscription = new BooleanSubscription(); - new Thread(new Runnable() { - - @Override - public void run() { - counter.incrementAndGet(); - System.out.println("published observable being executed"); - observer.onNext("one"); - observer.onCompleted(); - } - }).start(); - return subscription; - } - }))); - - // we then expect the following 2 subscriptions to get that same value - final CountDownLatch latch = new CountDownLatch(2); - - // subscribe once - o.subscribe(new Action1() { - - @Override - public void call(String v) { - assertEquals("one", v); - System.out.println("v: " + v); - latch.countDown(); - } - }); - - // subscribe again - o.subscribe(new Action1() { - - @Override - public void call(String v) { - assertEquals("one", v); - System.out.println("v: " + v); - latch.countDown(); - } - }); - - if (!latch.await(1000, TimeUnit.MILLISECONDS)) { - fail("subscriptions did not receive values"); - } - assertEquals(1, counter.get()); - } - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationCast.java b/rxjava-core/src/main/java/rx/operators/OperationCast.java index a4887c3afe..0643624a02 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationCast.java +++ b/rxjava-core/src/main/java/rx/operators/OperationCast.java @@ -1,15 +1,7 @@ package rx.operators; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import org.junit.Test; - import rx.Observable; import rx.Observable.OnSubscribeFunc; -import rx.Observer; import rx.util.functions.Func1; /** @@ -25,37 +17,4 @@ public R call(T t) { } }); } - - public static class UnitTest { - - @Test - public void testCast() { - Observable source = Observable.from(1, 2); - Observable observable = Observable.create(cast(source, - Integer.class)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, times(1)).onNext(1); - verify(aObserver, times(1)).onNext(1); - verify(aObserver, never()).onError( - org.mockito.Matchers.any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testCastWithWrongType() { - Observable source = Observable.from(1, 2); - Observable observable = Observable.create(cast(source, - Boolean.class)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, times(1)).onError( - org.mockito.Matchers.any(ClassCastException.class)); - } - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationCombineLatest.java b/rxjava-core/src/main/java/rx/operators/OperationCombineLatest.java index 020254d8a0..b87aaea0ba 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationCombineLatest.java +++ b/rxjava-core/src/main/java/rx/operators/OperationCombineLatest.java @@ -15,10 +15,12 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; +import rx.Observable; +import rx.Observable.OnSubscribeFunc; +import rx.Observer; +import rx.Subscription; +import rx.util.functions.*; -import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -26,26 +28,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.Matchers; - -import rx.Observable; -import rx.Observable.OnSubscribeFunc; -import rx.Observer; -import rx.Subscription; -import rx.subscriptions.Subscriptions; -import rx.util.functions.Func2; -import rx.util.functions.Func3; -import rx.util.functions.Func4; -import rx.util.functions.Func5; -import rx.util.functions.Func6; -import rx.util.functions.Func7; -import rx.util.functions.Func8; -import rx.util.functions.Func9; -import rx.util.functions.FuncN; -import rx.util.functions.Functions; - /** * Returns an Observable that combines the emissions of multiple source observables. Once each * source Observable has emitted at least one item, combineLatest emits an item whenever any of @@ -179,7 +161,7 @@ public static OnSubscribeFunc combine return a; } - private static class CombineObserver implements Observer { + static class CombineObserver implements Observer { final Observable w; final Aggregator a; private Subscription subscription; @@ -217,7 +199,7 @@ public void onNext(T args) { * whenever we have received an event from one of the observables, as soon as each Observable has received * at least one event. */ - private static class Aggregator implements OnSubscribeFunc { + static class Aggregator implements OnSubscribeFunc { private volatile Observer observer; @@ -351,603 +333,4 @@ private void stop() { } } } - - public static class UnitTest { - - @Test - public void testCombineLatestWithFunctionThatThrowsAnException() { - @SuppressWarnings("unchecked") // mock calls don't do generics - Observer w = mock(Observer.class); - - TestObservable w1 = new TestObservable(); - TestObservable w2 = new TestObservable(); - - Observable combined = Observable.create(combineLatest(Observable.create(w1), Observable.create(w2), new Func2() { - @Override - public String call(String v1, String v2) { - throw new RuntimeException("I don't work."); - } - })); - combined.subscribe(w); - - w1.observer.onNext("first value of w1"); - w2.observer.onNext("first value of w2"); - - verify(w, never()).onNext(anyString()); - verify(w, never()).onCompleted(); - verify(w, times(1)).onError(Matchers.any()); - } - - @Test - public void testCombineLatestDifferentLengthObservableSequences1() { - @SuppressWarnings("unchecked") // mock calls don't do generics - Observer w = mock(Observer.class); - - TestObservable w1 = new TestObservable(); - TestObservable w2 = new TestObservable(); - TestObservable w3 = new TestObservable(); - - Observable combineLatestW = Observable.create(combineLatest(Observable.create(w1), Observable.create(w2), Observable.create(w3), getConcat3StringsCombineLatestFunction())); - combineLatestW.subscribe(w); - - /* simulate sending data */ - // once for w1 - w1.observer.onNext("1a"); - w2.observer.onNext("2a"); - w3.observer.onNext("3a"); - w1.observer.onCompleted(); - // twice for w2 - w2.observer.onNext("2b"); - w2.observer.onCompleted(); - // 4 times for w3 - w3.observer.onNext("3b"); - w3.observer.onNext("3c"); - w3.observer.onNext("3d"); - w3.observer.onCompleted(); - - /* we should have been called 4 times on the Observer */ - InOrder inOrder = inOrder(w); - inOrder.verify(w).onNext("1a2a3a"); - inOrder.verify(w).onNext("1a2b3a"); - inOrder.verify(w).onNext("1a2b3b"); - inOrder.verify(w).onNext("1a2b3c"); - inOrder.verify(w).onNext("1a2b3d"); - inOrder.verify(w, never()).onNext(anyString()); - inOrder.verify(w, times(1)).onCompleted(); - } - - @Test - public void testCombineLatestDifferentLengthObservableSequences2() { - @SuppressWarnings("unchecked") - Observer w = mock(Observer.class); - - TestObservable w1 = new TestObservable(); - TestObservable w2 = new TestObservable(); - TestObservable w3 = new TestObservable(); - - Observable combineLatestW = Observable.create(combineLatest(Observable.create(w1), Observable.create(w2), Observable.create(w3), getConcat3StringsCombineLatestFunction())); - combineLatestW.subscribe(w); - - /* simulate sending data */ - // 4 times for w1 - w1.observer.onNext("1a"); - w1.observer.onNext("1b"); - w1.observer.onNext("1c"); - w1.observer.onNext("1d"); - w1.observer.onCompleted(); - // twice for w2 - w2.observer.onNext("2a"); - w2.observer.onNext("2b"); - w2.observer.onCompleted(); - // 1 times for w3 - w3.observer.onNext("3a"); - w3.observer.onCompleted(); - - /* we should have been called 1 time only on the Observer since we only combine the "latest" we don't go back and loop through others once completed */ - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext("1d2b3a"); - inOrder.verify(w, never()).onNext(anyString()); - - inOrder.verify(w, times(1)).onCompleted(); - - } - - @Test - public void testCombineLatestWithInterleavingSequences() { - @SuppressWarnings("unchecked") - Observer w = mock(Observer.class); - - TestObservable w1 = new TestObservable(); - TestObservable w2 = new TestObservable(); - TestObservable w3 = new TestObservable(); - - Observable combineLatestW = Observable.create(combineLatest(Observable.create(w1), Observable.create(w2), Observable.create(w3), getConcat3StringsCombineLatestFunction())); - combineLatestW.subscribe(w); - - /* simulate sending data */ - w1.observer.onNext("1a"); - w2.observer.onNext("2a"); - w2.observer.onNext("2b"); - w3.observer.onNext("3a"); - - w1.observer.onNext("1b"); - w2.observer.onNext("2c"); - w2.observer.onNext("2d"); - w3.observer.onNext("3b"); - - w1.observer.onCompleted(); - w2.observer.onCompleted(); - w3.observer.onCompleted(); - - /* we should have been called 5 times on the Observer */ - InOrder inOrder = inOrder(w); - inOrder.verify(w).onNext("1a2b3a"); - inOrder.verify(w).onNext("1b2b3a"); - inOrder.verify(w).onNext("1b2c3a"); - inOrder.verify(w).onNext("1b2d3a"); - inOrder.verify(w).onNext("1b2d3b"); - - inOrder.verify(w, never()).onNext(anyString()); - inOrder.verify(w, times(1)).onCompleted(); - } - - /** - * Testing internal private logic due to the complexity so I want to use TDD to test as a I build it rather than relying purely on the overall functionality expected by the public methods. - */ - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testAggregatorSimple() { - FuncN combineLatestFunction = getConcatCombineLatestFunction(); - /* create the aggregator which will execute the combineLatest function when all Observables provide values */ - Aggregator a = new Aggregator(combineLatestFunction); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - Observable.create(a).subscribe(aObserver); - - /* mock the Observable Observers that are 'pushing' data for us */ - CombineObserver r1 = mock(CombineObserver.class); - CombineObserver r2 = mock(CombineObserver.class); - - /* pretend we're starting up */ - a.addObserver(r1); - a.addObserver(r2); - - /* simulate the Observables pushing data into the aggregator */ - a.next(r1, "hello"); - a.next(r2, "world"); - - InOrder inOrder = inOrder(aObserver); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - inOrder.verify(aObserver, times(1)).onNext("helloworld"); - - a.next(r1, "hello "); - a.next(r2, "again"); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - inOrder.verify(aObserver, times(1)).onNext("hello again"); - - a.complete(r1); - a.complete(r2); - - inOrder.verify(aObserver, never()).onNext(anyString()); - verify(aObserver, times(1)).onCompleted(); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testAggregatorDifferentSizedResultsWithOnComplete() { - FuncN combineLatestFunction = getConcatCombineLatestFunction(); - /* create the aggregator which will execute the combineLatest function when all Observables provide values */ - Aggregator a = new Aggregator(combineLatestFunction); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - Observable.create(a).subscribe(aObserver); - - /* mock the Observable Observers that are 'pushing' data for us */ - CombineObserver r1 = mock(CombineObserver.class); - CombineObserver r2 = mock(CombineObserver.class); - - /* pretend we're starting up */ - a.addObserver(r1); - a.addObserver(r2); - - /* simulate the Observables pushing data into the aggregator */ - a.next(r1, "hello"); - a.next(r2, "world"); - a.complete(r2); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - verify(aObserver, times(1)).onNext("helloworld"); - - a.next(r1, "hi"); - a.complete(r1); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - verify(aObserver, times(1)).onNext("hiworld"); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testAggregateMultipleTypes() { - FuncN combineLatestFunction = getConcatCombineLatestFunction(); - /* create the aggregator which will execute the combineLatest function when all Observables provide values */ - Aggregator a = new Aggregator(combineLatestFunction); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - Observable.create(a).subscribe(aObserver); - - /* mock the Observable Observers that are 'pushing' data for us */ - CombineObserver r1 = mock(CombineObserver.class); - CombineObserver r2 = mock(CombineObserver.class); - - /* pretend we're starting up */ - a.addObserver(r1); - a.addObserver(r2); - - /* simulate the Observables pushing data into the aggregator */ - a.next(r1, "hello"); - a.next(r2, "world"); - a.complete(r2); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - verify(aObserver, times(1)).onNext("helloworld"); - - a.next(r1, "hi"); - a.complete(r1); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - verify(aObserver, times(1)).onNext("hiworld"); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testAggregate3Types() { - FuncN combineLatestFunction = getConcatCombineLatestFunction(); - /* create the aggregator which will execute the combineLatest function when all Observables provide values */ - Aggregator a = new Aggregator(combineLatestFunction); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - Observable.create(a).subscribe(aObserver); - - /* mock the Observable Observers that are 'pushing' data for us */ - CombineObserver r1 = mock(CombineObserver.class); - CombineObserver r2 = mock(CombineObserver.class); - CombineObserver r3 = mock(CombineObserver.class); - - /* pretend we're starting up */ - a.addObserver(r1); - a.addObserver(r2); - a.addObserver(r3); - - /* simulate the Observables pushing data into the aggregator */ - a.next(r1, "hello"); - a.next(r2, 2); - a.next(r3, new int[] { 5, 6, 7 }); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - verify(aObserver, times(1)).onNext("hello2[5, 6, 7]"); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testAggregatorsWithDifferentSizesAndTiming() { - FuncN combineLatestFunction = getConcatCombineLatestFunction(); - /* create the aggregator which will execute the combineLatest function when all Observables provide values */ - Aggregator a = new Aggregator(combineLatestFunction); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - Observable.create(a).subscribe(aObserver); - - /* mock the Observable Observers that are 'pushing' data for us */ - CombineObserver r1 = mock(CombineObserver.class); - CombineObserver r2 = mock(CombineObserver.class); - - /* pretend we're starting up */ - a.addObserver(r1); - a.addObserver(r2); - - /* simulate the Observables pushing data into the aggregator */ - a.next(r1, "one"); - a.next(r1, "two"); - a.next(r1, "three"); - a.next(r2, "A"); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - verify(aObserver, times(1)).onNext("threeA"); - - a.next(r1, "four"); - a.complete(r1); - a.next(r2, "B"); - verify(aObserver, times(1)).onNext("fourB"); - a.next(r2, "C"); - verify(aObserver, times(1)).onNext("fourC"); - a.next(r2, "D"); - verify(aObserver, times(1)).onNext("fourD"); - a.next(r2, "E"); - verify(aObserver, times(1)).onNext("fourE"); - a.complete(r2); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testAggregatorError() { - FuncN combineLatestFunction = getConcatCombineLatestFunction(); - /* create the aggregator which will execute the combineLatest function when all Observables provide values */ - Aggregator a = new Aggregator(combineLatestFunction); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - Observable.create(a).subscribe(aObserver); - - /* mock the Observable Observers that are 'pushing' data for us */ - CombineObserver r1 = mock(CombineObserver.class); - CombineObserver r2 = mock(CombineObserver.class); - - /* pretend we're starting up */ - a.addObserver(r1); - a.addObserver(r2); - - /* simulate the Observables pushing data into the aggregator */ - a.next(r1, "hello"); - a.next(r2, "world"); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - verify(aObserver, times(1)).onNext("helloworld"); - - a.error(new RuntimeException("")); - a.next(r1, "hello"); - a.next(r2, "again"); - - verify(aObserver, times(1)).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - // we don't want to be called again after an error - verify(aObserver, times(0)).onNext("helloagain"); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testAggregatorUnsubscribe() { - FuncN combineLatestFunction = getConcatCombineLatestFunction(); - /* create the aggregator which will execute the combineLatest function when all Observables provide values */ - Aggregator a = new Aggregator(combineLatestFunction); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - Subscription subscription = Observable.create(a).subscribe(aObserver); - - /* mock the Observable Observers that are 'pushing' data for us */ - CombineObserver r1 = mock(CombineObserver.class); - CombineObserver r2 = mock(CombineObserver.class); - - /* pretend we're starting up */ - a.addObserver(r1); - a.addObserver(r2); - - /* simulate the Observables pushing data into the aggregator */ - a.next(r1, "hello"); - a.next(r2, "world"); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - verify(aObserver, times(1)).onNext("helloworld"); - - subscription.unsubscribe(); - a.next(r1, "hello"); - a.next(r2, "again"); - - verify(aObserver, times(0)).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - // we don't want to be called again after an error - verify(aObserver, times(0)).onNext("helloagain"); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testAggregatorEarlyCompletion() { - FuncN combineLatestFunction = getConcatCombineLatestFunction(); - /* create the aggregator which will execute the combineLatest function when all Observables provide values */ - Aggregator a = new Aggregator(combineLatestFunction); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - Observable.create(a).subscribe(aObserver); - - /* mock the Observable Observers that are 'pushing' data for us */ - CombineObserver r1 = mock(CombineObserver.class); - CombineObserver r2 = mock(CombineObserver.class); - - /* pretend we're starting up */ - a.addObserver(r1); - a.addObserver(r2); - - /* simulate the Observables pushing data into the aggregator */ - a.next(r1, "one"); - a.next(r1, "two"); - a.complete(r1); - a.next(r2, "A"); - - InOrder inOrder = inOrder(aObserver); - - inOrder.verify(aObserver, never()).onError(any(Throwable.class)); - inOrder.verify(aObserver, never()).onCompleted(); - inOrder.verify(aObserver, times(1)).onNext("twoA"); - - a.complete(r2); - - inOrder.verify(aObserver, never()).onError(any(Throwable.class)); - inOrder.verify(aObserver, times(1)).onCompleted(); - // we shouldn't get this since completed is called before any other onNext calls could trigger this - inOrder.verify(aObserver, never()).onNext(anyString()); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testCombineLatest2Types() { - Func2 combineLatestFunction = getConcatStringIntegerCombineLatestFunction(); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - - Observable w = Observable.create(combineLatest(Observable.from("one", "two"), Observable.from(2, 3, 4), combineLatestFunction)); - w.subscribe(aObserver); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - verify(aObserver, times(1)).onNext("two2"); - verify(aObserver, times(1)).onNext("two3"); - verify(aObserver, times(1)).onNext("two4"); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testCombineLatest3TypesA() { - Func3 combineLatestFunction = getConcatStringIntegerIntArrayCombineLatestFunction(); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - - Observable w = Observable.create(combineLatest(Observable.from("one", "two"), Observable.from(2), Observable.from(new int[] { 4, 5, 6 }), combineLatestFunction)); - w.subscribe(aObserver); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - verify(aObserver, times(1)).onNext("two2[4, 5, 6]"); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testCombineLatest3TypesB() { - Func3 combineLatestFunction = getConcatStringIntegerIntArrayCombineLatestFunction(); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - - Observable w = Observable.create(combineLatest(Observable.from("one"), Observable.from(2), Observable.from(new int[] { 4, 5, 6 }, new int[] { 7, 8 }), combineLatestFunction)); - w.subscribe(aObserver); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - verify(aObserver, times(1)).onNext("one2[4, 5, 6]"); - verify(aObserver, times(1)).onNext("one2[7, 8]"); - } - - private Func3 getConcat3StringsCombineLatestFunction() { - Func3 combineLatestFunction = new Func3() { - - @Override - public String call(String a1, String a2, String a3) { - if (a1 == null) { - a1 = ""; - } - if (a2 == null) { - a2 = ""; - } - if (a3 == null) { - a3 = ""; - } - return a1 + a2 + a3; - } - - }; - return combineLatestFunction; - } - - private FuncN getConcatCombineLatestFunction() { - FuncN combineLatestFunction = new FuncN() { - - @Override - public String call(Object... args) { - String returnValue = ""; - for (Object o : args) { - if (o != null) { - returnValue += getStringValue(o); - } - } - System.out.println("returning: " + returnValue); - return returnValue; - } - - }; - return combineLatestFunction; - } - - private Func2 getConcatStringIntegerCombineLatestFunction() { - Func2 combineLatestFunction = new Func2() { - - @Override - public String call(String s, Integer i) { - return getStringValue(s) + getStringValue(i); - } - - }; - return combineLatestFunction; - } - - private Func3 getConcatStringIntegerIntArrayCombineLatestFunction() { - Func3 combineLatestFunction = new Func3() { - - @Override - public String call(String s, Integer i, int[] iArray) { - return getStringValue(s) + getStringValue(i) + getStringValue(iArray); - } - - }; - return combineLatestFunction; - } - - private static String getStringValue(Object o) { - if (o == null) { - return ""; - } else { - if (o instanceof int[]) { - return Arrays.toString((int[]) o); - } else { - return String.valueOf(o); - } - } - } - - private static class TestObservable implements OnSubscribeFunc { - - Observer observer; - - @Override - public Subscription onSubscribe(Observer observer) { - // just store the variable where it can be accessed so we can manually trigger it - this.observer = observer; - return Subscriptions.empty(); - } - - } - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationConcat.java b/rxjava-core/src/main/java/rx/operators/OperationConcat.java index 734751e9d0..4488ddf177 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationConcat.java +++ b/rxjava-core/src/main/java/rx/operators/OperationConcat.java @@ -15,28 +15,14 @@ */ package rx.operators; -import static org.junit.Assert.*; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - -import org.junit.Test; -import org.mockito.InOrder; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; -import rx.subscriptions.BooleanSubscription; + +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicBoolean; /** * Returns an Observable that emits the items emitted by two or more Observables, one after the @@ -166,529 +152,4 @@ public void unsubscribe() { }; } } - - public static class UnitTest { - - @Test - public void testConcat() { - @SuppressWarnings("unchecked") - Observer observer = mock(Observer.class); - - final String[] o = { "1", "3", "5", "7" }; - final String[] e = { "2", "4", "6" }; - - final Observable odds = Observable.from(o); - final Observable even = Observable.from(e); - - @SuppressWarnings("unchecked") - Observable concat = Observable.create(concat(odds, even)); - concat.subscribe(observer); - - verify(observer, times(7)).onNext(anyString()); - } - - @Test - public void testConcatWithList() { - @SuppressWarnings("unchecked") - Observer observer = mock(Observer.class); - - final String[] o = { "1", "3", "5", "7" }; - final String[] e = { "2", "4", "6" }; - - final Observable odds = Observable.from(o); - final Observable even = Observable.from(e); - final List> list = new ArrayList>(); - list.add(odds); - list.add(even); - Observable concat = Observable.create(concat(list)); - concat.subscribe(observer); - - verify(observer, times(7)).onNext(anyString()); - } - - @Test - public void testConcatObservableOfObservables() { - @SuppressWarnings("unchecked") - Observer observer = mock(Observer.class); - - final String[] o = { "1", "3", "5", "7" }; - final String[] e = { "2", "4", "6" }; - - final Observable odds = Observable.from(o); - final Observable even = Observable.from(e); - - Observable> observableOfObservables = Observable.create(new OnSubscribeFunc>() { - - @Override - public Subscription onSubscribe(Observer> observer) { - // simulate what would happen in an observable - observer.onNext(odds); - observer.onNext(even); - observer.onCompleted(); - - return new Subscription() { - - @Override - public void unsubscribe() { - // unregister ... will never be called here since we are executing synchronously - } - - }; - } - - }); - Observable concat = Observable.create(concat(observableOfObservables)); - - concat.subscribe(observer); - - verify(observer, times(7)).onNext(anyString()); - } - - /** - * Simple concat of 2 asynchronous observables ensuring it emits in correct order. - */ - @SuppressWarnings("unchecked") - @Test - public void testSimpleAsyncConcat() { - Observer observer = mock(Observer.class); - - TestObservable o1 = new TestObservable("one", "two", "three"); - TestObservable o2 = new TestObservable("four", "five", "six"); - - Observable.concat(Observable.create(o1), Observable.create(o2)).subscribe(observer); - - try { - // wait for async observables to complete - o1.t.join(); - o2.t.join(); - } catch (Throwable e) { - throw new RuntimeException("failed waiting on threads"); - } - - InOrder inOrder = inOrder(observer); - inOrder.verify(observer, times(1)).onNext("one"); - inOrder.verify(observer, times(1)).onNext("two"); - inOrder.verify(observer, times(1)).onNext("three"); - inOrder.verify(observer, times(1)).onNext("four"); - inOrder.verify(observer, times(1)).onNext("five"); - inOrder.verify(observer, times(1)).onNext("six"); - } - - /** - * Test an async Observable that emits more async Observables - */ - @SuppressWarnings("unchecked") - @Test - public void testNestedAsyncConcat() throws Throwable { - Observer observer = mock(Observer.class); - - final TestObservable o1 = new TestObservable("one", "two", "three"); - final TestObservable o2 = new TestObservable("four", "five", "six"); - final TestObservable o3 = new TestObservable("seven", "eight", "nine"); - final CountDownLatch allowThird = new CountDownLatch(1); - - final AtomicReference parent = new AtomicReference(); - Observable> observableOfObservables = Observable.create(new OnSubscribeFunc>() { - - @Override - public Subscription onSubscribe(final Observer> observer) { - final BooleanSubscription s = new BooleanSubscription(); - parent.set(new Thread(new Runnable() { - - @Override - public void run() { - try { - // emit first - if (!s.isUnsubscribed()) { - System.out.println("Emit o1"); - observer.onNext(Observable.create(o1)); - } - // emit second - if (!s.isUnsubscribed()) { - System.out.println("Emit o2"); - observer.onNext(Observable.create(o2)); - } - - // wait until sometime later and emit third - try { - allowThird.await(); - } catch (InterruptedException e) { - observer.onError(e); - } - if (!s.isUnsubscribed()) { - System.out.println("Emit o3"); - observer.onNext(Observable.create(o3)); - } - - } catch (Throwable e) { - observer.onError(e); - } finally { - System.out.println("Done parent Observable"); - observer.onCompleted(); - } - } - })); - parent.get().start(); - return s; - } - }); - - Observable.create(concat(observableOfObservables)).subscribe(observer); - - // wait for parent to start - while (parent.get() == null) { - Thread.sleep(1); - } - - try { - // wait for first 2 async observables to complete - while (o1.t == null) { - Thread.sleep(1); - } - System.out.println("Thread1 started ... waiting for it to complete ..."); - o1.t.join(); - while (o2.t == null) { - Thread.sleep(1); - } - System.out.println("Thread2 started ... waiting for it to complete ..."); - o2.t.join(); - } catch (Throwable e) { - throw new RuntimeException("failed waiting on threads", e); - } - - InOrder inOrder = inOrder(observer); - inOrder.verify(observer, times(1)).onNext("one"); - inOrder.verify(observer, times(1)).onNext("two"); - inOrder.verify(observer, times(1)).onNext("three"); - inOrder.verify(observer, times(1)).onNext("four"); - inOrder.verify(observer, times(1)).onNext("five"); - inOrder.verify(observer, times(1)).onNext("six"); - // we shouldn't have the following 3 yet - inOrder.verify(observer, never()).onNext("seven"); - inOrder.verify(observer, never()).onNext("eight"); - inOrder.verify(observer, never()).onNext("nine"); - // we should not be completed yet - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - // now allow the third - allowThird.countDown(); - - try { - while (o3.t == null) { - Thread.sleep(1); - } - // wait for 3rd to complete - o3.t.join(); - } catch (Throwable e) { - throw new RuntimeException("failed waiting on threads", e); - } - - inOrder.verify(observer, times(1)).onNext("seven"); - inOrder.verify(observer, times(1)).onNext("eight"); - inOrder.verify(observer, times(1)).onNext("nine"); - - inOrder.verify(observer, times(1)).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - } - - @SuppressWarnings("unchecked") - @Test - public void testBlockedObservableOfObservables() { - Observer observer = mock(Observer.class); - - final String[] o = { "1", "3", "5", "7" }; - final String[] e = { "2", "4", "6" }; - final Observable odds = Observable.from(o); - final Observable even = Observable.from(e); - final CountDownLatch callOnce = new CountDownLatch(1); - final CountDownLatch okToContinue = new CountDownLatch(1); - TestObservable> observableOfObservables = new TestObservable>(callOnce, okToContinue, odds, even); - OnSubscribeFunc concatF = concat(Observable.create(observableOfObservables)); - Observable concat = Observable.create(concatF); - concat.subscribe(observer); - try { - //Block main thread to allow observables to serve up o1. - callOnce.await(); - } catch (Throwable ex) { - ex.printStackTrace(); - fail(ex.getMessage()); - } - // The concated observable should have served up all of the odds. - verify(observer, times(1)).onNext("1"); - verify(observer, times(1)).onNext("3"); - verify(observer, times(1)).onNext("5"); - verify(observer, times(1)).onNext("7"); - - try { - // unblock observables so it can serve up o2 and complete - okToContinue.countDown(); - observableOfObservables.t.join(); - } catch (Throwable ex) { - ex.printStackTrace(); - fail(ex.getMessage()); - } - // The concatenated observable should now have served up all the evens. - verify(observer, times(1)).onNext("2"); - verify(observer, times(1)).onNext("4"); - verify(observer, times(1)).onNext("6"); - } - - @Test - public void testConcatConcurrentWithInfinity() { - final TestObservable w1 = new TestObservable("one", "two", "three"); - //This observable will send "hello" MAX_VALUE time. - final TestObservable w2 = new TestObservable("hello", Integer.MAX_VALUE); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - @SuppressWarnings("unchecked") - TestObservable> observableOfObservables = new TestObservable>(Observable.create(w1), Observable.create(w2)); - OnSubscribeFunc concatF = concat(Observable.create(observableOfObservables)); - - Observable concat = Observable.create(concatF); - - concat.take(50).subscribe(aObserver); - - //Wait for the thread to start up. - try { - Thread.sleep(25); - w1.t.join(); - w2.t.join(); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - InOrder inOrder = inOrder(aObserver); - inOrder.verify(aObserver, times(1)).onNext("one"); - inOrder.verify(aObserver, times(1)).onNext("two"); - inOrder.verify(aObserver, times(1)).onNext("three"); - inOrder.verify(aObserver, times(47)).onNext("hello"); - verify(aObserver, times(1)).onCompleted(); - verify(aObserver, never()).onError(any(Throwable.class)); - } - - @Test - public void testConcatNonBlockingObservables() { - - final CountDownLatch okToContinueW1 = new CountDownLatch(1); - final CountDownLatch okToContinueW2 = new CountDownLatch(1); - - final TestObservable w1 = new TestObservable(null, okToContinueW1, "one", "two", "three"); - final TestObservable w2 = new TestObservable(null, okToContinueW2, "four", "five", "six"); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - Observable> observableOfObservables = Observable.create(new OnSubscribeFunc>() { - - @Override - public Subscription onSubscribe(Observer> observer) { - // simulate what would happen in an observable - observer.onNext(Observable.create(w1)); - observer.onNext(Observable.create(w2)); - observer.onCompleted(); - - return new Subscription() { - - @Override - public void unsubscribe() { - } - - }; - } - - }); - Observable concat = Observable.create(concat(observableOfObservables)); - concat.subscribe(aObserver); - - verify(aObserver, times(0)).onCompleted(); - - try { - // release both threads - okToContinueW1.countDown(); - okToContinueW2.countDown(); - // wait for both to finish - w1.t.join(); - w2.t.join(); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - InOrder inOrder = inOrder(aObserver); - inOrder.verify(aObserver, times(1)).onNext("one"); - inOrder.verify(aObserver, times(1)).onNext("two"); - inOrder.verify(aObserver, times(1)).onNext("three"); - inOrder.verify(aObserver, times(1)).onNext("four"); - inOrder.verify(aObserver, times(1)).onNext("five"); - inOrder.verify(aObserver, times(1)).onNext("six"); - verify(aObserver, times(1)).onCompleted(); - - } - - /** - * Test unsubscribing the concatenated Observable in a single thread. - */ - @Test - public void testConcatUnsubscribe() { - final CountDownLatch callOnce = new CountDownLatch(1); - final CountDownLatch okToContinue = new CountDownLatch(1); - final TestObservable w1 = new TestObservable("one", "two", "three"); - final TestObservable w2 = new TestObservable(callOnce, okToContinue, "four", "five", "six"); - - @SuppressWarnings("unchecked") - final Observer aObserver = mock(Observer.class); - @SuppressWarnings("unchecked") - final Observable concat = Observable.create(concat(Observable.create(w1), Observable.create(w2))); - final SafeObservableSubscription s1 = new SafeObservableSubscription(); - - try { - // Subscribe - s1.wrap(concat.subscribe(aObserver)); - //Block main thread to allow observable "w1" to complete and observable "w2" to call onNext once. - callOnce.await(); - // Unsubcribe - s1.unsubscribe(); - //Unblock the observable to continue. - okToContinue.countDown(); - w1.t.join(); - w2.t.join(); - } catch (Throwable e) { - e.printStackTrace(); - fail(e.getMessage()); - } - - InOrder inOrder = inOrder(aObserver); - inOrder.verify(aObserver, times(1)).onNext("one"); - inOrder.verify(aObserver, times(1)).onNext("two"); - inOrder.verify(aObserver, times(1)).onNext("three"); - inOrder.verify(aObserver, times(1)).onNext("four"); - inOrder.verify(aObserver, never()).onNext("five"); - inOrder.verify(aObserver, never()).onNext("six"); - inOrder.verify(aObserver, never()).onCompleted(); - - } - - /** - * All observables will be running in different threads so subscribe() is unblocked. CountDownLatch is only used in order to call unsubscribe() in a predictable manner. - */ - @Test - public void testConcatUnsubscribeConcurrent() { - final CountDownLatch callOnce = new CountDownLatch(1); - final CountDownLatch okToContinue = new CountDownLatch(1); - final TestObservable w1 = new TestObservable("one", "two", "three"); - final TestObservable w2 = new TestObservable(callOnce, okToContinue, "four", "five", "six"); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - @SuppressWarnings("unchecked") - TestObservable> observableOfObservables = new TestObservable>(Observable.create(w1), Observable.create(w2)); - OnSubscribeFunc concatF = concat(Observable.create(observableOfObservables)); - - Observable concat = Observable.create(concatF); - - Subscription s1 = concat.subscribe(aObserver); - - try { - //Block main thread to allow observable "w1" to complete and observable "w2" to call onNext exactly once. - callOnce.await(); - //"four" from w2 has been processed by onNext() - s1.unsubscribe(); - //"five" and "six" will NOT be processed by onNext() - //Unblock the observable to continue. - okToContinue.countDown(); - w1.t.join(); - w2.t.join(); - } catch (Throwable e) { - e.printStackTrace(); - fail(e.getMessage()); - } - - InOrder inOrder = inOrder(aObserver); - inOrder.verify(aObserver, times(1)).onNext("one"); - inOrder.verify(aObserver, times(1)).onNext("two"); - inOrder.verify(aObserver, times(1)).onNext("three"); - inOrder.verify(aObserver, times(1)).onNext("four"); - inOrder.verify(aObserver, never()).onNext("five"); - inOrder.verify(aObserver, never()).onNext("six"); - verify(aObserver, never()).onCompleted(); - verify(aObserver, never()).onError(any(Throwable.class)); - } - - private static class TestObservable implements OnSubscribeFunc { - - private final Subscription s = new Subscription() { - - @Override - public void unsubscribe() { - subscribed = false; - } - - }; - private final List values; - private Thread t = null; - private int count = 0; - private boolean subscribed = true; - private final CountDownLatch once; - private final CountDownLatch okToContinue; - private final T seed; - private final int size; - - public TestObservable(T... values) { - this(null, null, values); - } - - public TestObservable(CountDownLatch once, CountDownLatch okToContinue, T... values) { - this.values = Arrays.asList(values); - this.size = this.values.size(); - this.once = once; - this.okToContinue = okToContinue; - this.seed = null; - } - - public TestObservable(T seed, int size) { - values = null; - once = null; - okToContinue = null; - this.seed = seed; - this.size = size; - } - - @Override - public Subscription onSubscribe(final Observer observer) { - t = new Thread(new Runnable() { - - @Override - public void run() { - try { - while (count < size && subscribed) { - if (null != values) - observer.onNext(values.get(count)); - else - observer.onNext(seed); - count++; - //Unblock the main thread to call unsubscribe. - if (null != once) - once.countDown(); - //Block until the main thread has called unsubscribe. - if (null != okToContinue) - okToContinue.await(5, TimeUnit.SECONDS); - } - if (subscribed) - observer.onCompleted(); - } catch (InterruptedException e) { - e.printStackTrace(); - fail(e.getMessage()); - } - } - - }); - t.start(); - return s; - } - - } - - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationDebounce.java b/rxjava-core/src/main/java/rx/operators/OperationDebounce.java index d225477069..ebbcbc8ad1 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationDebounce.java +++ b/rxjava-core/src/main/java/rx/operators/OperationDebounce.java @@ -15,27 +15,18 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.InOrder; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Scheduler; import rx.Subscription; import rx.concurrency.Schedulers; -import rx.concurrency.TestScheduler; -import rx.subscriptions.Subscriptions; import rx.util.functions.Action0; import rx.util.functions.Func1; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + /** * This operation is used to filter out bursts of events. This is done by ignoring the events from an observable which are too * quickly followed up with other values. Values which are not followed up by other values within the specified timeout are published @@ -160,135 +151,4 @@ public void call() { } } } - - public static class UnitTest { - - private TestScheduler scheduler; - private Observer observer; - - @Before - @SuppressWarnings("unchecked") - public void before() { - scheduler = new TestScheduler(); - observer = mock(Observer.class); - } - - @Test - public void testDebounceWithCompleted() { - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - publishNext(observer, 100, "one"); // Should be skipped since "two" will arrive before the timeout expires. - publishNext(observer, 400, "two"); // Should be published since "three" will arrive after the timeout expires. - publishNext(observer, 900, "three"); // Should be skipped since onCompleted will arrive before the timeout expires. - publishCompleted(observer, 1000); // Should be published as soon as the timeout expires. - - return Subscriptions.empty(); - } - }); - - Observable sampled = Observable.create(OperationDebounce.debounce(source, 400, TimeUnit.MILLISECONDS, scheduler)); - sampled.subscribe(observer); - - scheduler.advanceTimeTo(0, TimeUnit.MILLISECONDS); - InOrder inOrder = inOrder(observer); - // must go to 800 since it must be 400 after when two is sent, which is at 400 - scheduler.advanceTimeTo(800, TimeUnit.MILLISECONDS); - inOrder.verify(observer, times(1)).onNext("two"); - scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS); - inOrder.verify(observer, times(1)).onCompleted(); - inOrder.verifyNoMoreInteractions(); - } - - @Test - public void testDebounceNeverEmits() { - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - // all should be skipped since they are happening faster than the 200ms timeout - publishNext(observer, 100, "a"); // Should be skipped - publishNext(observer, 200, "b"); // Should be skipped - publishNext(observer, 300, "c"); // Should be skipped - publishNext(observer, 400, "d"); // Should be skipped - publishNext(observer, 500, "e"); // Should be skipped - publishNext(observer, 600, "f"); // Should be skipped - publishNext(observer, 700, "g"); // Should be skipped - publishNext(observer, 800, "h"); // Should be skipped - publishCompleted(observer, 900); // Should be published as soon as the timeout expires. - - return Subscriptions.empty(); - } - }); - - Observable sampled = Observable.create(OperationDebounce.debounce(source, 200, TimeUnit.MILLISECONDS, scheduler)); - sampled.subscribe(observer); - - scheduler.advanceTimeTo(0, TimeUnit.MILLISECONDS); - InOrder inOrder = inOrder(observer); - inOrder.verify(observer, times(0)).onNext(anyString()); - scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS); - inOrder.verify(observer, times(1)).onCompleted(); - inOrder.verifyNoMoreInteractions(); - } - - @Test - public void testDebounceWithError() { - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - Exception error = new TestException(); - publishNext(observer, 100, "one"); // Should be published since "two" will arrive after the timeout expires. - publishNext(observer, 600, "two"); // Should be skipped since onError will arrive before the timeout expires. - publishError(observer, 700, error); // Should be published as soon as the timeout expires. - - return Subscriptions.empty(); - } - }); - - Observable sampled = Observable.create(OperationDebounce.debounce(source, 400, TimeUnit.MILLISECONDS, scheduler)); - sampled.subscribe(observer); - - scheduler.advanceTimeTo(0, TimeUnit.MILLISECONDS); - InOrder inOrder = inOrder(observer); - // 100 + 400 means it triggers at 500 - scheduler.advanceTimeTo(500, TimeUnit.MILLISECONDS); - inOrder.verify(observer).onNext("one"); - scheduler.advanceTimeTo(701, TimeUnit.MILLISECONDS); - inOrder.verify(observer).onError(any(TestException.class)); - inOrder.verifyNoMoreInteractions(); - } - - private void publishCompleted(final Observer observer, long delay) { - scheduler.schedule(new Action0() { - @Override - public void call() { - observer.onCompleted(); - } - }, delay, TimeUnit.MILLISECONDS); - } - - private void publishError(final Observer observer, long delay, final Exception error) { - scheduler.schedule(new Action0() { - @Override - public void call() { - observer.onError(error); - } - }, delay, TimeUnit.MILLISECONDS); - } - - private void publishNext(final Observer observer, final long delay, final T value) { - scheduler.schedule(new Action0() { - @Override - public void call() { - observer.onNext(value); - } - }, delay, TimeUnit.MILLISECONDS); - } - - @SuppressWarnings("serial") - private class TestException extends Exception { - } - - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationDefaultIfEmpty.java b/rxjava-core/src/main/java/rx/operators/OperationDefaultIfEmpty.java index 195422dadc..cfe7f27a2f 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationDefaultIfEmpty.java +++ b/rxjava-core/src/main/java/rx/operators/OperationDefaultIfEmpty.java @@ -1,12 +1,5 @@ package rx.operators; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import org.junit.Test; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; @@ -82,41 +75,4 @@ public void onCompleted() { })); } } - - public static class UnitTest { - - @Test - public void testDefaultIfEmpty() { - Observable source = Observable.from(1, 2, 3); - Observable observable = Observable.create(defaultIfEmpty( - source, 10)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, never()).onNext(10); - verify(aObserver, times(1)).onNext(1); - verify(aObserver, times(1)).onNext(2); - verify(aObserver, times(1)).onNext(3); - verify(aObserver, never()).onError( - org.mockito.Matchers.any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testDefaultIfEmptyWithEmpty() { - Observable source = Observable.empty(); - Observable observable = Observable.create(defaultIfEmpty( - source, 10)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, times(1)).onNext(10); - verify(aObserver, never()).onError( - org.mockito.Matchers.any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationDefer.java b/rxjava-core/src/main/java/rx/operators/OperationDefer.java index 4be1ff01df..0d326b364e 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationDefer.java +++ b/rxjava-core/src/main/java/rx/operators/OperationDefer.java @@ -15,10 +15,6 @@ */ package rx.operators; -import static org.mockito.Mockito.*; - -import org.junit.Test; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; @@ -48,43 +44,4 @@ public Subscription onSubscribe(Observer observer) { }; } - - public static class UnitTest { - @Test - @SuppressWarnings("unchecked") - public void testDefer() throws Throwable { - - Func0> factory = mock(Func0.class); - - Observable firstObservable = Observable.from("one", "two"); - Observable secondObservable = Observable.from("three", "four"); - when(factory.call()).thenReturn(firstObservable, secondObservable); - - Observable deferred = Observable.defer(factory); - - verifyZeroInteractions(factory); - - Observer firstObserver = mock(Observer.class); - deferred.subscribe(firstObserver); - - verify(factory, times(1)).call(); - verify(firstObserver, times(1)).onNext("one"); - verify(firstObserver, times(1)).onNext("two"); - verify(firstObserver, times(0)).onNext("three"); - verify(firstObserver, times(0)).onNext("four"); - verify(firstObserver, times(1)).onCompleted(); - - Observer secondObserver = mock(Observer.class); - deferred.subscribe(secondObserver); - - verify(factory, times(2)).call(); - verify(secondObserver, times(0)).onNext("one"); - verify(secondObserver, times(0)).onNext("two"); - verify(secondObserver, times(1)).onNext("three"); - verify(secondObserver, times(1)).onNext("four"); - verify(secondObserver, times(1)).onCompleted(); - - } - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationDematerialize.java b/rxjava-core/src/main/java/rx/operators/OperationDematerialize.java index 529c507b14..8e958cbc14 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationDematerialize.java +++ b/rxjava-core/src/main/java/rx/operators/OperationDematerialize.java @@ -15,11 +15,6 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import org.junit.Test; - import rx.Notification; import rx.Observable; import rx.Observable.OnSubscribeFunc; @@ -85,52 +80,4 @@ public void onNext(Notification value) { }); } } - - public static class UnitTest { - - @Test - @SuppressWarnings("unchecked") - public void testDematerialize1() { - Observable> notifications = Observable.from(1, 2).materialize(); - Observable dematerialize = notifications.dematerialize(); - - Observer aObserver = mock(Observer.class); - dematerialize.subscribe(aObserver); - - verify(aObserver, times(1)).onNext(1); - verify(aObserver, times(1)).onNext(2); - verify(aObserver, times(1)).onCompleted(); - verify(aObserver, never()).onError(any(Throwable.class)); - } - - @Test - @SuppressWarnings("unchecked") - public void testDematerialize2() { - Throwable exception = new Throwable("test"); - Observable observable = Observable.error(exception); - Observable dematerialize = Observable.create(dematerialize(observable.materialize())); - - Observer aObserver = mock(Observer.class); - dematerialize.subscribe(aObserver); - - verify(aObserver, times(1)).onError(exception); - verify(aObserver, times(0)).onCompleted(); - verify(aObserver, times(0)).onNext(any(Integer.class)); - } - - @Test - @SuppressWarnings("unchecked") - public void testDematerialize3() { - Exception exception = new Exception("test"); - Observable observable = Observable.error(exception); - Observable dematerialize = Observable.create(dematerialize(observable.materialize())); - - Observer aObserver = mock(Observer.class); - dematerialize.subscribe(aObserver); - - verify(aObserver, times(1)).onError(exception); - verify(aObserver, times(0)).onCompleted(); - verify(aObserver, times(0)).onNext(any(Integer.class)); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationDistinct.java b/rxjava-core/src/main/java/rx/operators/OperationDistinct.java index b56f0cd22f..9c0bccce2c 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationDistinct.java +++ b/rxjava-core/src/main/java/rx/operators/OperationDistinct.java @@ -15,24 +15,6 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; -import static org.mockito.MockitoAnnotations.initMocks; -import static rx.Observable.create; -import static rx.Observable.empty; -import static rx.Observable.from; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.Mock; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; @@ -42,6 +24,8 @@ import rx.util.functions.Func1; import rx.util.functions.Functions; +import java.util.*; + /** * Returns an Observable that emits all distinct items emitted by the source. * @@ -192,166 +176,4 @@ public void call() { }); } } - - public static class UnitTest { - @Mock - Observer w; - @Mock - Observer w2; - - // nulls lead to exceptions - final Func1 TO_UPPER_WITH_EXCEPTION = new Func1() { - @Override - public String call(String s) { - if (s.equals("x")) { - return "XX"; - } - return s.toUpperCase(); - } - }; - - final Comparator COMPARE_LENGTH = new Comparator() { - @Override - public int compare(String s1, String s2) { - return s1.length() - s2.length(); - } - }; - - @Before - public void before() { - initMocks(this); - } - - @Test - public void testDistinctOfNone() { - Observable src = empty(); - create(distinct(src)).subscribe(w); - - verify(w, never()).onNext(anyString()); - verify(w, never()).onError(any(Throwable.class)); - verify(w, times(1)).onCompleted(); - } - - @Test - public void testDistinctOfNoneWithKeySelector() { - Observable src = empty(); - create(distinct(src, TO_UPPER_WITH_EXCEPTION)).subscribe(w); - - verify(w, never()).onNext(anyString()); - verify(w, never()).onError(any(Throwable.class)); - verify(w, times(1)).onCompleted(); - } - - @Test - public void testDistinctOfNormalSource() { - Observable src = from("a", "b", "c", "c", "c", "b", "b", "a", "e"); - create(distinct(src)).subscribe(w); - - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext("a"); - inOrder.verify(w, times(1)).onNext("b"); - inOrder.verify(w, times(1)).onNext("c"); - inOrder.verify(w, times(1)).onNext("e"); - inOrder.verify(w, times(1)).onCompleted(); - inOrder.verify(w, never()).onNext(anyString()); - verify(w, never()).onError(any(Throwable.class)); - } - - @Test - public void testDistinctOfNormalSourceWithKeySelector() { - Observable src = from("a", "B", "c", "C", "c", "B", "b", "a", "E"); - create(distinct(src, TO_UPPER_WITH_EXCEPTION)).subscribe(w); - - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext("a"); - inOrder.verify(w, times(1)).onNext("B"); - inOrder.verify(w, times(1)).onNext("c"); - inOrder.verify(w, times(1)).onNext("E"); - inOrder.verify(w, times(1)).onCompleted(); - inOrder.verify(w, never()).onNext(anyString()); - verify(w, never()).onError(any(Throwable.class)); - } - - @Test - public void testDistinctOfNormalSourceWithComparator() { - Observable src = from("1", "12", "123", "aaa", "321", "12", "21", "1", "12345"); - create(distinct(src, COMPARE_LENGTH)).subscribe(w); - - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext("1"); - inOrder.verify(w, times(1)).onNext("12"); - inOrder.verify(w, times(1)).onNext("123"); - inOrder.verify(w, times(1)).onNext("12345"); - inOrder.verify(w, times(1)).onCompleted(); - inOrder.verify(w, never()).onNext(anyString()); - verify(w, never()).onError(any(Throwable.class)); - } - - @Test - public void testDistinctOfNormalSourceWithKeySelectorAndComparator() { - Observable src = from("a", "x", "ab", "abc", "cba", "de", "x", "a", "abcd"); - create(distinct(src, TO_UPPER_WITH_EXCEPTION, COMPARE_LENGTH)).subscribe(w); - - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext("a"); - inOrder.verify(w, times(1)).onNext("x"); - inOrder.verify(w, times(1)).onNext("abc"); - inOrder.verify(w, times(1)).onNext("abcd"); - inOrder.verify(w, times(1)).onCompleted(); - inOrder.verify(w, never()).onNext(anyString()); - verify(w, never()).onError(any(Throwable.class)); - } - - @Test - public void testDistinctOfNormalSourceWithKeySelectorAndComparatorAndTwoSubscriptions() { - Observable src = from("a", "x", "ab", "abc", "cba", "de", "x", "a", "abcd"); - create(distinct(src, TO_UPPER_WITH_EXCEPTION, COMPARE_LENGTH)).subscribe(w); - - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext("a"); - inOrder.verify(w, times(1)).onNext("x"); - create(distinct(src, TO_UPPER_WITH_EXCEPTION, COMPARE_LENGTH)).subscribe(w2); - inOrder.verify(w, times(1)).onNext("abc"); - inOrder.verify(w, times(1)).onNext("abcd"); - inOrder.verify(w, times(1)).onCompleted(); - inOrder.verify(w, never()).onNext(anyString()); - verify(w, never()).onError(any(Throwable.class)); - - InOrder inOrder2 = inOrder(w2); - inOrder2.verify(w2, times(1)).onNext("a"); - inOrder2.verify(w2, times(1)).onNext("x"); - inOrder2.verify(w2, times(1)).onNext("abc"); - inOrder2.verify(w2, times(1)).onNext("abcd"); - inOrder2.verify(w2, times(1)).onCompleted(); - inOrder2.verify(w2, never()).onNext(anyString()); - verify(w2, never()).onError(any(Throwable.class)); - } - - @Test - public void testDistinctOfSourceWithNulls() { - Observable src = from(null, "a", "a", null, null, "b", null); - create(distinct(src)).subscribe(w); - - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext(null); - inOrder.verify(w, times(1)).onNext("a"); - inOrder.verify(w, times(1)).onNext("b"); - inOrder.verify(w, times(1)).onCompleted(); - inOrder.verify(w, never()).onNext(anyString()); - verify(w, never()).onError(any(Throwable.class)); - } - - @Test - public void testDistinctOfSourceWithExceptionsFromKeySelector() { - Observable src = from("a", "b", null, "c"); - create(distinct(src, TO_UPPER_WITH_EXCEPTION)).subscribe(w); - - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext("a"); - inOrder.verify(w, times(1)).onNext("b"); - inOrder.verify(w, times(1)).onError(any(NullPointerException.class)); - inOrder.verify(w, never()).onNext(anyString()); - inOrder.verify(w, never()).onCompleted(); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationDistinctUntilChanged.java b/rxjava-core/src/main/java/rx/operators/OperationDistinctUntilChanged.java index c43edc0202..d1ea86b653 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationDistinctUntilChanged.java +++ b/rxjava-core/src/main/java/rx/operators/OperationDistinctUntilChanged.java @@ -15,20 +15,6 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; -import static org.mockito.MockitoAnnotations.initMocks; -import static rx.Observable.create; -import static rx.Observable.empty; -import static rx.Observable.from; - -import java.util.Comparator; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.Mock; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; @@ -38,6 +24,8 @@ import rx.util.functions.Func1; import rx.util.functions.Functions; +import java.util.Comparator; + /** * Returns an Observable that emits all sequentially distinct items emitted by the source. */ @@ -152,169 +140,4 @@ public void call() { }); } } - - public static class UnitTest { - @Mock - Observer w; - @Mock - Observer w2; - - // nulls lead to exceptions - final Func1 TO_UPPER_WITH_EXCEPTION = new Func1() { - @Override - public String call(String s) { - if (s.equals("x")) { - return "xx"; - } - return s.toUpperCase(); - } - }; - - final Comparator COMPARE_LENGTH = new Comparator() { - @Override - public int compare(String s1, String s2) { - return s1.length() - s2.length(); - } - }; - - @Before - public void before() { - initMocks(this); - } - - @Test - public void testDistinctUntilChangedOfNone() { - Observable src = empty(); - create(distinctUntilChanged(src)).subscribe(w); - - verify(w, never()).onNext(anyString()); - verify(w, never()).onError(any(Throwable.class)); - verify(w, times(1)).onCompleted(); - } - - @Test - public void testDistinctUntilChangedOfNoneWithKeySelector() { - Observable src = empty(); - create(distinctUntilChanged(src, TO_UPPER_WITH_EXCEPTION)).subscribe(w); - - verify(w, never()).onNext(anyString()); - verify(w, never()).onError(any(Throwable.class)); - verify(w, times(1)).onCompleted(); - } - - @Test - public void testDistinctUntilChangedOfNormalSource() { - Observable src = from("a", "b", "c", "c", "c", "b", "b", "a", "e"); - create(distinctUntilChanged(src)).subscribe(w); - - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext("a"); - inOrder.verify(w, times(1)).onNext("b"); - inOrder.verify(w, times(1)).onNext("c"); - inOrder.verify(w, times(1)).onNext("b"); - inOrder.verify(w, times(1)).onNext("a"); - inOrder.verify(w, times(1)).onNext("e"); - inOrder.verify(w, times(1)).onCompleted(); - inOrder.verify(w, never()).onNext(anyString()); - verify(w, never()).onError(any(Throwable.class)); - } - - @Test - public void testDistinctUntilChangedOfNormalSourceWithKeySelector() { - Observable src = from("a", "b", "c", "C", "c", "B", "b", "a", "e"); - create(distinctUntilChanged(src, TO_UPPER_WITH_EXCEPTION)).subscribe(w); - - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext("a"); - inOrder.verify(w, times(1)).onNext("b"); - inOrder.verify(w, times(1)).onNext("c"); - inOrder.verify(w, times(1)).onNext("B"); - inOrder.verify(w, times(1)).onNext("a"); - inOrder.verify(w, times(1)).onNext("e"); - inOrder.verify(w, times(1)).onCompleted(); - inOrder.verify(w, never()).onNext(anyString()); - verify(w, never()).onError(any(Throwable.class)); - } - - @Test - public void testDistinctUntilChangedOfSourceWithNulls() { - Observable src = from(null, "a", "a", null, null, "b", null, null); - create(distinctUntilChanged(src)).subscribe(w); - - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext(null); - inOrder.verify(w, times(1)).onNext("a"); - inOrder.verify(w, times(1)).onNext(null); - inOrder.verify(w, times(1)).onNext("b"); - inOrder.verify(w, times(1)).onNext(null); - inOrder.verify(w, times(1)).onCompleted(); - inOrder.verify(w, never()).onNext(anyString()); - verify(w, never()).onError(any(Throwable.class)); - } - - @Test - public void testDistinctUntilChangedOfSourceWithExceptionsFromKeySelector() { - Observable src = from("a", "b", null, "c"); - create(distinctUntilChanged(src, TO_UPPER_WITH_EXCEPTION)).subscribe(w); - - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext("a"); - inOrder.verify(w, times(1)).onNext("b"); - verify(w, times(1)).onError(any(NullPointerException.class)); - inOrder.verify(w, never()).onNext(anyString()); - inOrder.verify(w, never()).onCompleted(); - } - - @Test - public void testDistinctUntilChangedWithComparator() { - Observable src = from("a", "b", "c", "aa", "bb", "c", "ddd"); - create(distinctUntilChanged(src, COMPARE_LENGTH)).subscribe(w); - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext("a"); - inOrder.verify(w, times(1)).onNext("aa"); - inOrder.verify(w, times(1)).onNext("c"); - inOrder.verify(w, times(1)).onNext("ddd"); - inOrder.verify(w, times(1)).onCompleted(); - inOrder.verify(w, never()).onNext(anyString()); - verify(w, never()).onError(any(Throwable.class)); - } - - @Test - public void testDistinctUntilChangedWithComparatorAndKeySelector() { - Observable src = from("a", "b", "x", "aa", "bb", "c", "ddd"); - create(distinctUntilChanged(src, TO_UPPER_WITH_EXCEPTION, COMPARE_LENGTH)).subscribe(w); - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext("a"); - inOrder.verify(w, times(1)).onNext("x"); - inOrder.verify(w, times(1)).onNext("c"); - inOrder.verify(w, times(1)).onNext("ddd"); - inOrder.verify(w, times(1)).onCompleted(); - inOrder.verify(w, never()).onNext(anyString()); - verify(w, never()).onError(any(Throwable.class)); - } - - @Test - public void testDistinctUntilChangedWithComparatorAndKeySelectorandTwoSubscriptions() { - Observable src = from("a", "b", "x", "aa", "bb", "c", "ddd"); - create(distinctUntilChanged(src, TO_UPPER_WITH_EXCEPTION, COMPARE_LENGTH)).subscribe(w); - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext("a"); - inOrder.verify(w, times(1)).onNext("x"); - create(distinctUntilChanged(src, TO_UPPER_WITH_EXCEPTION, COMPARE_LENGTH)).subscribe(w2); - inOrder.verify(w, times(1)).onNext("c"); - inOrder.verify(w, times(1)).onNext("ddd"); - inOrder.verify(w, times(1)).onCompleted(); - inOrder.verify(w, never()).onNext(anyString()); - verify(w, never()).onError(any(Throwable.class)); - - InOrder inOrder2 = inOrder(w2); - inOrder2.verify(w2, times(1)).onNext("a"); - inOrder2.verify(w2, times(1)).onNext("x"); - inOrder2.verify(w2, times(1)).onNext("c"); - inOrder2.verify(w2, times(1)).onNext("ddd"); - inOrder2.verify(w2, times(1)).onCompleted(); - inOrder2.verify(w2, never()).onNext(anyString()); - verify(w2, never()).onError(any(Throwable.class)); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationElementAt.java b/rxjava-core/src/main/java/rx/operators/OperationElementAt.java index 0d91709be1..c1310bc013 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationElementAt.java +++ b/rxjava-core/src/main/java/rx/operators/OperationElementAt.java @@ -15,25 +15,13 @@ */ package rx.operators; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.util.Iterator; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicInteger; - -import org.junit.Test; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; +import java.util.concurrent.atomic.AtomicInteger; + /** * Returns the element at a specified index in a sequence. */ @@ -146,102 +134,4 @@ public void onCompleted() { })); } } - - public static class UnitTest { - - @Test - public void testElementAt() { - Observable w = Observable.from(1, 2); - Observable observable = Observable.create(elementAt(w, 1)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, never()).onNext(1); - verify(aObserver, times(1)).onNext(2); - verify(aObserver, never()).onError( - any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testElementAtWithMinusIndex() { - Observable w = Observable.from(1, 2); - Observable observable = Observable - .create(elementAt(w, -1)); - - try { - Iterator iter = OperationToIterator - .toIterator(observable); - assertTrue(iter.hasNext()); - iter.next(); - fail("expect an IndexOutOfBoundsException when index is out of bounds"); - } catch (IndexOutOfBoundsException e) { - } - } - - @Test - public void testElementAtWithIndexOutOfBounds() - throws InterruptedException, ExecutionException { - Observable w = Observable.from(1, 2); - Observable observable = Observable.create(elementAt(w, 2)); - try { - Iterator iter = OperationToIterator - .toIterator(observable); - assertTrue(iter.hasNext()); - iter.next(); - fail("expect an IndexOutOfBoundsException when index is out of bounds"); - } catch (IndexOutOfBoundsException e) { - } - } - - @Test - public void testElementAtOrDefault() throws InterruptedException, - ExecutionException { - Observable w = Observable.from(1, 2); - Observable observable = Observable - .create(elementAtOrDefault(w, 1, 0)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, never()).onNext(1); - verify(aObserver, times(1)).onNext(2); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testElementAtOrDefaultWithIndexOutOfBounds() - throws InterruptedException, ExecutionException { - Observable w = Observable.from(1, 2); - Observable observable = Observable - .create(elementAtOrDefault(w, 2, 0)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, never()).onNext(1); - verify(aObserver, never()).onNext(2); - verify(aObserver, times(1)).onNext(0); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testElementAtOrDefaultWithMinusIndex() { - Observable w = Observable.from(1, 2); - Observable observable = Observable - .create(elementAtOrDefault(w, -1, 0)); - - try { - Iterator iter = OperationToIterator - .toIterator(observable); - assertTrue(iter.hasNext()); - iter.next(); - fail("expect an IndexOutOfBoundsException when index is out of bounds"); - } catch (IndexOutOfBoundsException e) { - } - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationFilter.java b/rxjava-core/src/main/java/rx/operators/OperationFilter.java index 5026f11d0c..560600dc9c 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationFilter.java +++ b/rxjava-core/src/main/java/rx/operators/OperationFilter.java @@ -15,12 +15,6 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import org.junit.Test; -import org.mockito.Mockito; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; @@ -74,28 +68,4 @@ public void onCompleted() { } } - - public static class UnitTest { - - @Test - public void testFilter() { - Observable w = Observable.from("one", "two", "three"); - Observable observable = Observable.create(filter(w, new Func1() { - - @Override - public Boolean call(String t1) { - return t1.equals("two"); - } - })); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, Mockito.never()).onNext("one"); - verify(aObserver, times(1)).onNext("two"); - verify(aObserver, Mockito.never()).onNext("three"); - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationFinally.java b/rxjava-core/src/main/java/rx/operators/OperationFinally.java index ad711b08ca..6e4d58768a 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationFinally.java +++ b/rxjava-core/src/main/java/rx/operators/OperationFinally.java @@ -15,11 +15,6 @@ */ package rx.operators; -import static org.mockito.Mockito.*; - -import org.junit.Before; -import org.junit.Test; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; @@ -105,31 +100,4 @@ public void onNext(T args) { } } } - - public static class UnitTest { - private Action0 aAction0; - private Observer aObserver; - - @SuppressWarnings("unchecked") // mocking has to be unchecked, unfortunately - @Before - public void before() { - aAction0 = mock(Action0.class); - aObserver = mock(Observer.class); - } - - private void checkActionCalled(Observable input) { - Observable.create(finallyDo(input, aAction0)).subscribe(aObserver); - verify(aAction0, times(1)).call(); - } - - @Test - public void testFinallyCalledOnComplete() { - checkActionCalled(Observable.from(new String[] {"1", "2", "3"})); - } - - @Test - public void testFinallyCalledOnError() { - checkActionCalled(Observable.error(new RuntimeException("expected"))); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationFirstOrDefault.java b/rxjava-core/src/main/java/rx/operators/OperationFirstOrDefault.java index 73283a8a3b..66dcb6e90d 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationFirstOrDefault.java +++ b/rxjava-core/src/main/java/rx/operators/OperationFirstOrDefault.java @@ -15,20 +15,6 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; -import static org.mockito.MockitoAnnotations.initMocks; -import static rx.Observable.create; -import static rx.Observable.empty; -import static rx.Observable.from; -import static rx.util.functions.Functions.alwaysTrue; - -import java.util.concurrent.atomic.AtomicBoolean; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; @@ -37,6 +23,10 @@ import rx.util.functions.Action0; import rx.util.functions.Func1; +import java.util.concurrent.atomic.AtomicBoolean; + +import static rx.util.functions.Functions.alwaysTrue; + /** * Returns an Observable that emits the first item emitted by the source * Observable, or a default value if the source emits nothing. @@ -126,65 +116,4 @@ public void call() { }); } } - - public static class UnitTest { - @Mock - Observer w; - - private static final Func1 IS_D = new Func1() { - @Override - public Boolean call(String value) { - return "d".equals(value); - } - }; - - @Before - public void before() { - initMocks(this); - } - - @Test - public void testFirstOrElseOfNone() { - Observable src = empty(); - create(firstOrDefault(src, "default")).subscribe(w); - - verify(w, times(1)).onNext(anyString()); - verify(w, times(1)).onNext("default"); - verify(w, never()).onError(any(Throwable.class)); - verify(w, times(1)).onCompleted(); - } - - @Test - public void testFirstOrElseOfSome() { - Observable src = from("a", "b", "c"); - create(firstOrDefault(src, "default")).subscribe(w); - - verify(w, times(1)).onNext(anyString()); - verify(w, times(1)).onNext("a"); - verify(w, never()).onError(any(Throwable.class)); - verify(w, times(1)).onCompleted(); - } - - @Test - public void testFirstOrElseWithPredicateOfNoneMatchingThePredicate() { - Observable src = from("a", "b", "c"); - create(firstOrDefault(src, IS_D, "default")).subscribe(w); - - verify(w, times(1)).onNext(anyString()); - verify(w, times(1)).onNext("default"); - verify(w, never()).onError(any(Throwable.class)); - verify(w, times(1)).onCompleted(); - } - - @Test - public void testFirstOrElseWithPredicateOfSome() { - Observable src = from("a", "b", "c", "d", "e", "f"); - create(firstOrDefault(src, IS_D, "default")).subscribe(w); - - verify(w, times(1)).onNext(anyString()); - verify(w, times(1)).onNext("d"); - verify(w, never()).onError(any(Throwable.class)); - verify(w, times(1)).onCompleted(); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationGroupBy.java b/rxjava-core/src/main/java/rx/operators/OperationGroupBy.java index 96a6861406..e4311c5421 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationGroupBy.java +++ b/rxjava-core/src/main/java/rx/operators/OperationGroupBy.java @@ -15,32 +15,19 @@ */ package rx.operators; -import static org.junit.Assert.*; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -import org.junit.Test; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; import rx.observables.GroupedObservable; -import rx.subscriptions.BooleanSubscription; -import rx.subscriptions.Subscriptions; -import rx.util.functions.Action1; import rx.util.functions.Func1; import rx.util.functions.Functions; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + /** * Groups the items emitted by an Observable according to a specified criterion, and emits these * grouped items as Observables, one Observable per group. @@ -251,312 +238,4 @@ private KeyValue(K key, V value) { this.value = value; } } - - public static class UnitTest { - final Func1 length = new Func1() { - @Override - public Integer call(String s) { - return s.length(); - } - }; - - @Test - public void testGroupBy() { - Observable source = Observable.from("one", "two", "three", "four", "five", "six"); - Observable> grouped = Observable.create(groupBy(source, length)); - - Map> map = toMap(grouped); - - assertEquals(3, map.size()); - assertArrayEquals(Arrays.asList("one", "two", "six").toArray(), map.get(3).toArray()); - assertArrayEquals(Arrays.asList("four", "five").toArray(), map.get(4).toArray()); - assertArrayEquals(Arrays.asList("three").toArray(), map.get(5).toArray()); - } - - @Test - public void testEmpty() { - Observable source = Observable.empty(); - Observable> grouped = Observable.create(groupBy(source, length)); - - Map> map = toMap(grouped); - - assertTrue(map.isEmpty()); - } - - @Test - public void testError() { - Observable sourceStrings = Observable.from("one", "two", "three", "four", "five", "six"); - Observable errorSource = Observable.error(new RuntimeException("forced failure")); - Observable source = Observable.concat(sourceStrings, errorSource); - - Observable> grouped = Observable.create(groupBy(source, length)); - - final AtomicInteger groupCounter = new AtomicInteger(); - final AtomicInteger eventCounter = new AtomicInteger(); - final AtomicReference error = new AtomicReference(); - - grouped.mapMany(new Func1, Observable>() { - - @Override - public Observable call(final GroupedObservable o) { - groupCounter.incrementAndGet(); - return o.map(new Func1() { - - @Override - public String call(String v) { - return "Event => key: " + o.getKey() + " value: " + v; - } - }); - } - }).subscribe(new Observer() { - - @Override - public void onCompleted() { - - } - - @Override - public void onError(Throwable e) { - e.printStackTrace(); - error.set(e); - } - - @Override - public void onNext(String v) { - eventCounter.incrementAndGet(); - System.out.println(v); - - } - }); - - assertEquals(3, groupCounter.get()); - assertEquals(6, eventCounter.get()); - assertNotNull(error.get()); - } - - private static Map> toMap(Observable> observable) { - - final ConcurrentHashMap> result = new ConcurrentHashMap>(); - - observable.toBlockingObservable().forEach(new Action1>() { - - @Override - public void call(final GroupedObservable o) { - result.put(o.getKey(), new ConcurrentLinkedQueue()); - o.subscribe(new Action1() { - - @Override - public void call(V v) { - result.get(o.getKey()).add(v); - } - - }); - } - }); - - return result; - } - - /** - * Assert that only a single subscription to a stream occurs and that all events are received. - * - * @throws Throwable - */ - @Test - public void testGroupedEventStream() throws Throwable { - - final AtomicInteger eventCounter = new AtomicInteger(); - final AtomicInteger subscribeCounter = new AtomicInteger(); - final AtomicInteger groupCounter = new AtomicInteger(); - final CountDownLatch latch = new CountDownLatch(1); - final int count = 100; - final int groupCount = 2; - - Observable es = Observable.create(new OnSubscribeFunc() { - - @Override - public Subscription onSubscribe(final Observer observer) { - System.out.println("*** Subscribing to EventStream ***"); - subscribeCounter.incrementAndGet(); - new Thread(new Runnable() { - - @Override - public void run() { - for (int i = 0; i < count; i++) { - Event e = new Event(); - e.source = i % groupCount; - e.message = "Event-" + i; - observer.onNext(e); - } - observer.onCompleted(); - } - - }).start(); - return Subscriptions.empty(); - } - - }); - - es.groupBy(new Func1() { - - @Override - public Integer call(Event e) { - return e.source; - } - }).mapMany(new Func1, Observable>() { - - @Override - public Observable call(GroupedObservable eventGroupedObservable) { - System.out.println("GroupedObservable Key: " + eventGroupedObservable.getKey()); - groupCounter.incrementAndGet(); - - return eventGroupedObservable.map(new Func1() { - - @Override - public String call(Event event) { - return "Source: " + event.source + " Message: " + event.message; - } - }); - - } - }).subscribe(new Observer() { - - @Override - public void onCompleted() { - latch.countDown(); - } - - @Override - public void onError(Throwable e) { - e.printStackTrace(); - latch.countDown(); - } - - @Override - public void onNext(String outputMessage) { - System.out.println(outputMessage); - eventCounter.incrementAndGet(); - } - }); - - latch.await(5000, TimeUnit.MILLISECONDS); - assertEquals(1, subscribeCounter.get()); - assertEquals(groupCount, groupCounter.get()); - assertEquals(count, eventCounter.get()); - - } - - /* - * We will only take 1 group with 20 events from it and then unsubscribe. - */ - @Test - public void testUnsubscribe() throws InterruptedException { - - final AtomicInteger eventCounter = new AtomicInteger(); - final AtomicInteger subscribeCounter = new AtomicInteger(); - final AtomicInteger groupCounter = new AtomicInteger(); - final AtomicInteger sentEventCounter = new AtomicInteger(); - final CountDownLatch latch = new CountDownLatch(1); - final int count = 100; - final int groupCount = 2; - - Observable es = Observable.create(new OnSubscribeFunc() { - - @Override - public Subscription onSubscribe(final Observer observer) { - final BooleanSubscription s = new BooleanSubscription(); - System.out.println("testUnsubscribe => *** Subscribing to EventStream ***"); - subscribeCounter.incrementAndGet(); - new Thread(new Runnable() { - - @Override - public void run() { - for (int i = 0; i < count; i++) { - if (s.isUnsubscribed()) { - break; - } - Event e = new Event(); - e.source = i % groupCount; - e.message = "Event-" + i; - observer.onNext(e); - sentEventCounter.incrementAndGet(); - } - observer.onCompleted(); - } - - }).start(); - return s; - } - - }); - - es.groupBy(new Func1() { - - @Override - public Integer call(Event e) { - return e.source; - } - }) - .take(1) // we want only the first group - .mapMany(new Func1, Observable>() { - - @Override - public Observable call(GroupedObservable eventGroupedObservable) { - System.out.println("testUnsubscribe => GroupedObservable Key: " + eventGroupedObservable.getKey()); - groupCounter.incrementAndGet(); - - return eventGroupedObservable - .take(20) // limit to only 20 events on this group - .map(new Func1() { - - @Override - public String call(Event event) { - return "testUnsubscribe => Source: " + event.source + " Message: " + event.message; - } - }); - - } - }).subscribe(new Observer() { - - @Override - public void onCompleted() { - latch.countDown(); - } - - @Override - public void onError(Throwable e) { - e.printStackTrace(); - latch.countDown(); - } - - @Override - public void onNext(String outputMessage) { - System.out.println(outputMessage); - eventCounter.incrementAndGet(); - } - }); - - latch.await(5000, TimeUnit.MILLISECONDS); - assertEquals(1, subscribeCounter.get()); - assertEquals(1, groupCounter.get()); - assertEquals(20, eventCounter.get()); - // sentEvents will go until 'eventCounter' hits 20 and then unsubscribes - // which means it will also send (but ignore) the 19/20 events for the other group - // It will not however send all 100 events. - assertEquals(39, sentEventCounter.get(), 10); - // gave it a delta of 10 to account for the threading/unsubscription race condition which can vary depending on a machines performance, thread-scheduler, etc - } - - private static class Event { - int source; - String message; - - @Override - public String toString() { - return "Event => source: " + source + " message: " + message; - } - } - - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationInterval.java b/rxjava-core/src/main/java/rx/operators/OperationInterval.java index 0711bff4a2..0c767eada7 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationInterval.java +++ b/rxjava-core/src/main/java/rx/operators/OperationInterval.java @@ -15,27 +15,16 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.InOrder; - -import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Scheduler; import rx.Subscription; import rx.concurrency.Schedulers; -import rx.concurrency.TestScheduler; -import rx.observables.ConnectableObservable; import rx.subscriptions.Subscriptions; import rx.util.functions.Action0; +import java.util.concurrent.TimeUnit; + /** * Returns an observable sequence that produces a value after each period. * The value starts at 0 and counts up each period. @@ -94,163 +83,4 @@ public void call() { }); } } - - public static class UnitTest { - private TestScheduler scheduler; - private Observer observer; - private Observer observer2; - - @Before - @SuppressWarnings("unchecked") // due to mocking - public void before() { - scheduler = new TestScheduler(); - observer = mock(Observer.class); - observer2 = mock(Observer.class); - } - - @Test - public void testInterval() { - Observable w = Observable.create(OperationInterval.interval(1, TimeUnit.SECONDS, scheduler)); - Subscription sub = w.subscribe(observer); - - verify(observer, never()).onNext(0L); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - scheduler.advanceTimeTo(2, TimeUnit.SECONDS); - - InOrder inOrder = inOrder(observer); - inOrder.verify(observer, times(1)).onNext(0L); - inOrder.verify(observer, times(1)).onNext(1L); - inOrder.verify(observer, never()).onNext(2L); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - sub.unsubscribe(); - scheduler.advanceTimeTo(4, TimeUnit.SECONDS); - verify(observer, never()).onNext(2L); - verify(observer, times(1)).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - } - - @Test - public void testWithMultipleSubscribersStartingAtSameTime() { - Observable w = Observable.create(OperationInterval.interval(1, TimeUnit.SECONDS, scheduler)); - Subscription sub1 = w.subscribe(observer); - Subscription sub2 = w.subscribe(observer2); - - verify(observer, never()).onNext(anyLong()); - verify(observer2, never()).onNext(anyLong()); - - scheduler.advanceTimeTo(2, TimeUnit.SECONDS); - - InOrder inOrder1 = inOrder(observer); - InOrder inOrder2 = inOrder(observer2); - - inOrder1.verify(observer, times(1)).onNext(0L); - inOrder1.verify(observer, times(1)).onNext(1L); - inOrder1.verify(observer, never()).onNext(2L); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - inOrder2.verify(observer2, times(1)).onNext(0L); - inOrder2.verify(observer2, times(1)).onNext(1L); - inOrder2.verify(observer2, never()).onNext(2L); - verify(observer2, never()).onCompleted(); - verify(observer2, never()).onError(any(Throwable.class)); - - sub1.unsubscribe(); - sub2.unsubscribe(); - scheduler.advanceTimeTo(4, TimeUnit.SECONDS); - - verify(observer, never()).onNext(2L); - verify(observer, times(1)).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - verify(observer2, never()).onNext(2L); - verify(observer2, times(1)).onCompleted(); - verify(observer2, never()).onError(any(Throwable.class)); - } - - @Test - public void testWithMultipleStaggeredSubscribers() { - Observable w = Observable.create(OperationInterval.interval(1, TimeUnit.SECONDS, scheduler)); - Subscription sub1 = w.subscribe(observer); - - verify(observer, never()).onNext(anyLong()); - - scheduler.advanceTimeTo(2, TimeUnit.SECONDS); - Subscription sub2 = w.subscribe(observer2); - - InOrder inOrder1 = inOrder(observer); - inOrder1.verify(observer, times(1)).onNext(0L); - inOrder1.verify(observer, times(1)).onNext(1L); - inOrder1.verify(observer, never()).onNext(2L); - - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - verify(observer2, never()).onNext(anyLong()); - - scheduler.advanceTimeTo(4, TimeUnit.SECONDS); - - inOrder1.verify(observer, times(1)).onNext(2L); - inOrder1.verify(observer, times(1)).onNext(3L); - - InOrder inOrder2 = inOrder(observer2); - inOrder2.verify(observer2, times(1)).onNext(0L); - inOrder2.verify(observer2, times(1)).onNext(1L); - - sub1.unsubscribe(); - sub2.unsubscribe(); - - inOrder1.verify(observer, never()).onNext(anyLong()); - inOrder1.verify(observer, times(1)).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - inOrder2.verify(observer2, never()).onNext(anyLong()); - inOrder2.verify(observer2, times(1)).onCompleted(); - verify(observer2, never()).onError(any(Throwable.class)); - } - - @Test - public void testWithMultipleStaggeredSubscribersAndPublish() { - ConnectableObservable w = Observable.create(OperationInterval.interval(1, TimeUnit.SECONDS, scheduler)).publish(); - Subscription sub1 = w.subscribe(observer); - w.connect(); - - verify(observer, never()).onNext(anyLong()); - - scheduler.advanceTimeTo(2, TimeUnit.SECONDS); - Subscription sub2 = w.subscribe(observer2); - - InOrder inOrder1 = inOrder(observer); - inOrder1.verify(observer, times(1)).onNext(0L); - inOrder1.verify(observer, times(1)).onNext(1L); - inOrder1.verify(observer, never()).onNext(2L); - - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - verify(observer2, never()).onNext(anyLong()); - - scheduler.advanceTimeTo(4, TimeUnit.SECONDS); - - inOrder1.verify(observer, times(1)).onNext(2L); - inOrder1.verify(observer, times(1)).onNext(3L); - - InOrder inOrder2 = inOrder(observer2); - inOrder2.verify(observer2, times(1)).onNext(2L); - inOrder2.verify(observer2, times(1)).onNext(3L); - - sub1.unsubscribe(); - sub2.unsubscribe(); - - inOrder1.verify(observer, never()).onNext(anyLong()); - inOrder1.verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - inOrder2.verify(observer2, never()).onNext(anyLong()); - inOrder2.verify(observer2, never()).onCompleted(); - verify(observer2, never()).onError(any(Throwable.class)); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationMap.java b/rxjava-core/src/main/java/rx/operators/OperationMap.java index 940147b0b8..f2543326f2 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationMap.java +++ b/rxjava-core/src/main/java/rx/operators/OperationMap.java @@ -15,29 +15,10 @@ */ package rx.operators; -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicInteger; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; -import rx.concurrency.Schedulers; import rx.util.functions.Func1; import rx.util.functions.Func2; @@ -156,258 +137,4 @@ public void onCompleted() { }))); } } - - public static class UnitTest { - @Mock - Observer stringObserver; - @Mock - Observer stringObserver2; - - final static Func2 APPEND_INDEX = new Func2() { - @Override - public String call(String value, Integer index) { - return value + index; - } - }; - - @Before - public void before() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testMap() { - Map m1 = getMap("One"); - Map m2 = getMap("Two"); - Observable> observable = Observable.from(m1, m2); - - Observable m = Observable.create(map(observable, new Func1, String>() { - - @Override - public String call(Map map) { - return map.get("firstName"); - } - - })); - m.subscribe(stringObserver); - - verify(stringObserver, never()).onError(any(Throwable.class)); - verify(stringObserver, times(1)).onNext("OneFirst"); - verify(stringObserver, times(1)).onNext("TwoFirst"); - verify(stringObserver, times(1)).onCompleted(); - } - - @Test - public void testMapWithIndex() { - Observable w = Observable.from("a", "b", "c"); - Observable m = Observable.create(mapWithIndex(w, APPEND_INDEX)); - m.subscribe(stringObserver); - InOrder inOrder = inOrder(stringObserver); - inOrder.verify(stringObserver, times(1)).onNext("a0"); - inOrder.verify(stringObserver, times(1)).onNext("b1"); - inOrder.verify(stringObserver, times(1)).onNext("c2"); - inOrder.verify(stringObserver, times(1)).onCompleted(); - verify(stringObserver, never()).onError(any(Throwable.class)); - } - - @Test - public void testMapWithIndexAndMultipleSubscribers() { - Observable w = Observable.from("a", "b", "c"); - Observable m = Observable.create(mapWithIndex(w, APPEND_INDEX)); - m.subscribe(stringObserver); - m.subscribe(stringObserver2); - InOrder inOrder = inOrder(stringObserver); - inOrder.verify(stringObserver, times(1)).onNext("a0"); - inOrder.verify(stringObserver, times(1)).onNext("b1"); - inOrder.verify(stringObserver, times(1)).onNext("c2"); - inOrder.verify(stringObserver, times(1)).onCompleted(); - verify(stringObserver, never()).onError(any(Throwable.class)); - - InOrder inOrder2 = inOrder(stringObserver2); - inOrder2.verify(stringObserver2, times(1)).onNext("a0"); - inOrder2.verify(stringObserver2, times(1)).onNext("b1"); - inOrder2.verify(stringObserver2, times(1)).onNext("c2"); - inOrder2.verify(stringObserver2, times(1)).onCompleted(); - verify(stringObserver2, never()).onError(any(Throwable.class)); - } - - @Test - public void testMapMany() { - /* simulate a top-level async call which returns IDs */ - Observable ids = Observable.from(1, 2); - - /* now simulate the behavior to take those IDs and perform nested async calls based on them */ - Observable m = Observable.create(mapMany(ids, new Func1>() { - - @Override - public Observable call(Integer id) { - /* simulate making a nested async call which creates another Observable */ - Observable> subObservable = null; - if (id == 1) { - Map m1 = getMap("One"); - Map m2 = getMap("Two"); - subObservable = Observable.from(m1, m2); - } else { - Map m3 = getMap("Three"); - Map m4 = getMap("Four"); - subObservable = Observable.from(m3, m4); - } - - /* simulate kicking off the async call and performing a select on it to transform the data */ - return Observable.create(map(subObservable, new Func1, String>() { - @Override - public String call(Map map) { - return map.get("firstName"); - } - })); - } - - })); - m.subscribe(stringObserver); - - verify(stringObserver, never()).onError(any(Throwable.class)); - verify(stringObserver, times(1)).onNext("OneFirst"); - verify(stringObserver, times(1)).onNext("TwoFirst"); - verify(stringObserver, times(1)).onNext("ThreeFirst"); - verify(stringObserver, times(1)).onNext("FourFirst"); - verify(stringObserver, times(1)).onCompleted(); - } - - @Test - public void testMapMany2() { - Map m1 = getMap("One"); - Map m2 = getMap("Two"); - Observable> observable1 = Observable.from(m1, m2); - - Map m3 = getMap("Three"); - Map m4 = getMap("Four"); - Observable> observable2 = Observable.from(m3, m4); - - Observable>> observable = Observable.from(observable1, observable2); - - Observable m = Observable.create(mapMany(observable, new Func1>, Observable>() { - - @Override - public Observable call(Observable> o) { - return Observable.create(map(o, new Func1, String>() { - - @Override - public String call(Map map) { - return map.get("firstName"); - } - })); - } - - })); - m.subscribe(stringObserver); - - verify(stringObserver, never()).onError(any(Throwable.class)); - verify(stringObserver, times(1)).onNext("OneFirst"); - verify(stringObserver, times(1)).onNext("TwoFirst"); - verify(stringObserver, times(1)).onNext("ThreeFirst"); - verify(stringObserver, times(1)).onNext("FourFirst"); - verify(stringObserver, times(1)).onCompleted(); - - } - - @Test - public void testMapWithError() { - Observable w = Observable.from("one", "fail", "two", "three", "fail"); - Observable m = Observable.create(map(w, new Func1() { - @Override - public String call(String s) { - if ("fail".equals(s)) { - throw new RuntimeException("Forced Failure"); - } - return s; - } - })); - - m.subscribe(stringObserver); - verify(stringObserver, times(1)).onNext("one"); - verify(stringObserver, never()).onNext("two"); - verify(stringObserver, never()).onNext("three"); - verify(stringObserver, never()).onCompleted(); - verify(stringObserver, times(1)).onError(any(Throwable.class)); - } - - @Test - public void testMapWithSynchronousObservableContainingError() { - Observable w = Observable.from("one", "fail", "two", "three", "fail"); - final AtomicInteger c1 = new AtomicInteger(); - final AtomicInteger c2 = new AtomicInteger(); - Observable m = Observable.create(map(w, new Func1() { - @Override - public String call(String s) { - if ("fail".equals(s)) - throw new RuntimeException("Forced Failure"); - System.out.println("BadMapper:" + s); - c1.incrementAndGet(); - return s; - } - })).map(new Func1() { - @Override - public String call(String s) { - System.out.println("SecondMapper:" + s); - c2.incrementAndGet(); - return s; - } - }); - - m.subscribe(stringObserver); - - verify(stringObserver, times(1)).onNext("one"); - verify(stringObserver, never()).onNext("two"); - verify(stringObserver, never()).onNext("three"); - verify(stringObserver, never()).onCompleted(); - verify(stringObserver, times(1)).onError(any(Throwable.class)); - - // we should have only returned 1 value: "one" - assertEquals(1, c1.get()); - assertEquals(1, c2.get()); - } - - @Test(expected = IllegalArgumentException.class) - public void testMapWithIssue417() { - Observable.from(1).observeOn(Schedulers.threadPoolForComputation()) - .map(new Func1() { - public Integer call(Integer arg0) { - throw new IllegalArgumentException("any error"); - } - }).toBlockingObservable().single(); - } - - @Test - public void testMapWithErrorInFuncAndThreadPoolScheduler() throws InterruptedException { - // The error will throw in one of threads in the thread pool. - // If map does not handle it, the error will disappear. - // so map needs to handle the error by itself. - final CountDownLatch latch = new CountDownLatch(1); - Observable m = Observable.from("one") - .observeOn(Schedulers.threadPoolForComputation()) - .map(new Func1() { - public String call(String arg0) { - try { - throw new IllegalArgumentException("any error"); - } finally { - latch.countDown(); - } - } - }); - - m.subscribe(stringObserver); - latch.await(); - InOrder inorder = inOrder(stringObserver); - inorder.verify(stringObserver, times(1)).onError(any(IllegalArgumentException.class)); - inorder.verifyNoMoreInteractions(); - } - - private static Map getMap(String prefix) { - Map m = new HashMap(); - m.put("firstName", prefix + "First"); - m.put("lastName", prefix + "Last"); - return m; - } - - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationMaterialize.java b/rxjava-core/src/main/java/rx/operators/OperationMaterialize.java index 7d906720fa..f1998ffe64 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationMaterialize.java +++ b/rxjava-core/src/main/java/rx/operators/OperationMaterialize.java @@ -15,14 +15,6 @@ */ package rx.operators; -import static org.junit.Assert.*; - -import java.util.List; -import java.util.Vector; -import java.util.concurrent.ExecutionException; - -import org.junit.Test; - import rx.Notification; import rx.Observable; import rx.Observable.OnSubscribeFunc; @@ -85,140 +77,4 @@ public void onNext(T value) { } } - - public static class UnitTest { - @Test - public void testMaterialize1() { - // null will cause onError to be triggered before "three" can be returned - final TestAsyncErrorObservable o1 = new TestAsyncErrorObservable("one", "two", null, "three"); - - TestObserver Observer = new TestObserver(); - Observable> m = Observable.create(materialize(Observable.create(o1))); - m.subscribe(Observer); - - try { - o1.t.join(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - - assertFalse(Observer.onError); - assertTrue(Observer.onCompleted); - assertEquals(3, Observer.notifications.size()); - assertEquals("one", Observer.notifications.get(0).getValue()); - assertTrue(Observer.notifications.get(0).isOnNext()); - assertEquals("two", Observer.notifications.get(1).getValue()); - assertTrue(Observer.notifications.get(1).isOnNext()); - assertEquals(NullPointerException.class, Observer.notifications.get(2).getThrowable().getClass()); - assertTrue(Observer.notifications.get(2).isOnError()); - } - - @Test - public void testMaterialize2() { - final TestAsyncErrorObservable o1 = new TestAsyncErrorObservable("one", "two", "three"); - - TestObserver Observer = new TestObserver(); - Observable> m = Observable.create(materialize(Observable.create(o1))); - m.subscribe(Observer); - - try { - o1.t.join(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - - assertFalse(Observer.onError); - assertTrue(Observer.onCompleted); - assertEquals(4, Observer.notifications.size()); - assertEquals("one", Observer.notifications.get(0).getValue()); - assertTrue(Observer.notifications.get(0).isOnNext()); - assertEquals("two", Observer.notifications.get(1).getValue()); - assertTrue(Observer.notifications.get(1).isOnNext()); - assertEquals("three", Observer.notifications.get(2).getValue()); - assertTrue(Observer.notifications.get(2).isOnNext()); - assertTrue(Observer.notifications.get(3).isOnCompleted()); - } - - @Test - public void testMultipleSubscribes() throws InterruptedException, ExecutionException { - final TestAsyncErrorObservable o = new TestAsyncErrorObservable("one", "two", null, "three"); - - Observable> m = Observable.create(materialize(Observable.create(o))); - - assertEquals(3, m.toList().toBlockingObservable().toFuture().get().size()); - assertEquals(3, m.toList().toBlockingObservable().toFuture().get().size()); - } - - } - - private static class TestObserver implements Observer> { - - boolean onCompleted = false; - boolean onError = false; - List> notifications = new Vector>(); - - @Override - public void onCompleted() { - this.onCompleted = true; - } - - @Override - public void onError(Throwable e) { - this.onError = true; - } - - @Override - public void onNext(Notification value) { - this.notifications.add(value); - } - - } - - private static class TestAsyncErrorObservable implements OnSubscribeFunc { - - String[] valuesToReturn; - - TestAsyncErrorObservable(String... values) { - valuesToReturn = values; - } - - volatile Thread t; - - @Override - public Subscription onSubscribe(final Observer observer) { - t = new Thread(new Runnable() { - - @Override - public void run() { - for (String s : valuesToReturn) { - if (s == null) { - System.out.println("throwing exception"); - try { - Thread.sleep(100); - } catch (Throwable e) { - - } - observer.onError(new NullPointerException()); - return; - } else { - observer.onNext(s); - } - } - System.out.println("subscription complete"); - observer.onCompleted(); - } - - }); - t.start(); - - return new Subscription() { - - @Override - public void unsubscribe() { - - } - - }; - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationMerge.java b/rxjava-core/src/main/java/rx/operators/OperationMerge.java index ab226c1eee..4f98439292 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationMerge.java +++ b/rxjava-core/src/main/java/rx/operators/OperationMerge.java @@ -15,32 +15,15 @@ */ package rx.operators; -import static org.junit.Assert.*; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; import rx.subscriptions.CompositeSubscription; -import rx.subscriptions.Subscriptions; -import rx.util.functions.Action0; -import rx.util.functions.Action1; + +import java.util.Arrays; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; /** * Flattens a list of Observables into one Observable sequence, without any transformation. @@ -287,435 +270,4 @@ public void onNext(T args) { } } - - public static class UnitTest { - @Mock - Observer stringObserver; - - @Before - public void before() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testMergeObservableOfObservables() { - final Observable o1 = Observable.create(new TestSynchronousObservable()); - final Observable o2 = Observable.create(new TestSynchronousObservable()); - - Observable> observableOfObservables = Observable.create(new OnSubscribeFunc>() { - - @Override - public Subscription onSubscribe(Observer> observer) { - // simulate what would happen in an observable - observer.onNext(o1); - observer.onNext(o2); - observer.onCompleted(); - - return new Subscription() { - - @Override - public void unsubscribe() { - // unregister ... will never be called here since we are executing synchronously - } - - }; - } - - }); - Observable m = Observable.create(merge(observableOfObservables)); - m.subscribe(stringObserver); - - verify(stringObserver, never()).onError(any(Throwable.class)); - verify(stringObserver, times(1)).onCompleted(); - verify(stringObserver, times(2)).onNext("hello"); - } - - @Test - public void testMergeArray() { - final Observable o1 = Observable.create(new TestSynchronousObservable()); - final Observable o2 = Observable.create(new TestSynchronousObservable()); - - @SuppressWarnings("unchecked") - Observable m = Observable.create(merge(o1, o2)); - m.subscribe(stringObserver); - - verify(stringObserver, never()).onError(any(Throwable.class)); - verify(stringObserver, times(2)).onNext("hello"); - verify(stringObserver, times(1)).onCompleted(); - } - - @Test - public void testMergeList() { - final Observable o1 = Observable.create(new TestSynchronousObservable()); - final Observable o2 = Observable.create(new TestSynchronousObservable()); - List> listOfObservables = new ArrayList>(); - listOfObservables.add(o1); - listOfObservables.add(o2); - - Observable m = Observable.create(merge(listOfObservables)); - m.subscribe(stringObserver); - - verify(stringObserver, never()).onError(any(Throwable.class)); - verify(stringObserver, times(1)).onCompleted(); - verify(stringObserver, times(2)).onNext("hello"); - } - - @Test - public void testUnSubscribe() { - TestObservable tA = new TestObservable(); - TestObservable tB = new TestObservable(); - - @SuppressWarnings("unchecked") - Observable m = Observable.create(merge(Observable.create(tA), Observable.create(tB))); - Subscription s = m.subscribe(stringObserver); - - tA.sendOnNext("Aone"); - tB.sendOnNext("Bone"); - s.unsubscribe(); - tA.sendOnNext("Atwo"); - tB.sendOnNext("Btwo"); - tA.sendOnCompleted(); - tB.sendOnCompleted(); - - verify(stringObserver, never()).onError(any(Throwable.class)); - verify(stringObserver, times(1)).onNext("Aone"); - verify(stringObserver, times(1)).onNext("Bone"); - assertTrue(tA.unsubscribed); - assertTrue(tB.unsubscribed); - verify(stringObserver, never()).onNext("Atwo"); - verify(stringObserver, never()).onNext("Btwo"); - verify(stringObserver, never()).onCompleted(); - } - - @Test - public void testUnSubscribeObservableOfObservables() throws InterruptedException { - - final AtomicBoolean unsubscribed = new AtomicBoolean(); - final CountDownLatch latch = new CountDownLatch(1); - - Observable> source = Observable.create(new OnSubscribeFunc>() { - - @Override - public Subscription onSubscribe(final Observer> observer) { - // verbose on purpose so I can track the inside of it - final Subscription s = Subscriptions.create(new Action0() { - - @Override - public void call() { - System.out.println("*** unsubscribed"); - unsubscribed.set(true); - } - - }); - - new Thread(new Runnable() { - - @Override - public void run() { - - while (!unsubscribed.get()) { - observer.onNext(Observable.from(1L, 2L)); - } - System.out.println("Done looping after unsubscribe: " + unsubscribed.get()); - observer.onCompleted(); - - // mark that the thread is finished - latch.countDown(); - } - }).start(); - - return s; - }; - - }); - - final AtomicInteger count = new AtomicInteger(); - Observable.create(merge(source)).take(6).toBlockingObservable().forEach(new Action1() { - - @Override - public void call(Long v) { - System.out.println("Value: " + v); - int c = count.incrementAndGet(); - if (c > 6) { - fail("Should be only 6"); - } - - } - }); - - latch.await(1000, TimeUnit.MILLISECONDS); - - System.out.println("unsubscribed: " + unsubscribed.get()); - - assertTrue(unsubscribed.get()); - - } - - @Test - public void testMergeArrayWithThreading() { - final TestASynchronousObservable o1 = new TestASynchronousObservable(); - final TestASynchronousObservable o2 = new TestASynchronousObservable(); - - @SuppressWarnings("unchecked") - Observable m = Observable.create(merge(Observable.create(o1), Observable.create(o2))); - m.subscribe(stringObserver); - - try { - o1.t.join(); - o2.t.join(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - - verify(stringObserver, never()).onError(any(Throwable.class)); - verify(stringObserver, times(2)).onNext("hello"); - verify(stringObserver, times(1)).onCompleted(); - } - - @Test - public void testSynchronizationOfMultipleSequences() throws Throwable { - final TestASynchronousObservable o1 = new TestASynchronousObservable(); - final TestASynchronousObservable o2 = new TestASynchronousObservable(); - - // use this latch to cause onNext to wait until we're ready to let it go - final CountDownLatch endLatch = new CountDownLatch(1); - - final AtomicInteger concurrentCounter = new AtomicInteger(); - final AtomicInteger totalCounter = new AtomicInteger(); - - @SuppressWarnings("unchecked") - Observable m = Observable.create(merge(Observable.create(o1), Observable.create(o2))); - m.subscribe(new Observer() { - - @Override - public void onCompleted() { - - } - - @Override - public void onError(Throwable e) { - throw new RuntimeException("failed", e); - } - - @Override - public void onNext(String v) { - totalCounter.incrementAndGet(); - concurrentCounter.incrementAndGet(); - try { - // wait here until we're done asserting - endLatch.await(); - } catch (InterruptedException e) { - e.printStackTrace(); - throw new RuntimeException("failed", e); - } finally { - concurrentCounter.decrementAndGet(); - } - } - - }); - - // wait for both observables to send (one should be blocked) - o1.onNextBeingSent.await(); - o2.onNextBeingSent.await(); - - // I can't think of a way to know for sure that both threads have or are trying to send onNext - // since I can't use a CountDownLatch for "after" onNext since I want to catch during it - // but I can't know for sure onNext is invoked - // so I'm unfortunately reverting to using a Thread.sleep to allow the process scheduler time - // to make sure after o1.onNextBeingSent and o2.onNextBeingSent are hit that the following - // onNext is invoked. - - Thread.sleep(300); - - try { // in try/finally so threads are released via latch countDown even if assertion fails - assertEquals(1, concurrentCounter.get()); - } finally { - // release so it can finish - endLatch.countDown(); - } - - try { - o1.t.join(); - o2.t.join(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - - assertEquals(2, totalCounter.get()); - assertEquals(0, concurrentCounter.get()); - } - - /** - * unit test from OperationMergeDelayError backported here to show how these use cases work with normal merge - */ - @Test - public void testError1() { - // we are using synchronous execution to test this exactly rather than non-deterministic concurrent behavior - final Observable o1 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" - final Observable o2 = Observable.create(new TestErrorObservable("one", "two", "three")); // we expect to lose all of these since o1 is done first and fails - - @SuppressWarnings("unchecked") - Observable m = Observable.create(merge(o1, o2)); - m.subscribe(stringObserver); - - verify(stringObserver, times(1)).onError(any(NullPointerException.class)); - verify(stringObserver, never()).onCompleted(); - verify(stringObserver, times(0)).onNext("one"); - verify(stringObserver, times(0)).onNext("two"); - verify(stringObserver, times(0)).onNext("three"); - verify(stringObserver, times(1)).onNext("four"); - verify(stringObserver, times(0)).onNext("five"); - verify(stringObserver, times(0)).onNext("six"); - } - - /** - * unit test from OperationMergeDelayError backported here to show how these use cases work with normal merge - */ - @Test - public void testError2() { - // we are using synchronous execution to test this exactly rather than non-deterministic concurrent behavior - final Observable o1 = Observable.create(new TestErrorObservable("one", "two", "three")); - final Observable o2 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" - final Observable o3 = Observable.create(new TestErrorObservable("seven", "eight", null));// we expect to lose all of these since o2 is done first and fails - final Observable o4 = Observable.create(new TestErrorObservable("nine"));// we expect to lose all of these since o2 is done first and fails - - @SuppressWarnings("unchecked") - Observable m = Observable.create(merge(o1, o2, o3, o4)); - m.subscribe(stringObserver); - - verify(stringObserver, times(1)).onError(any(NullPointerException.class)); - verify(stringObserver, never()).onCompleted(); - verify(stringObserver, times(1)).onNext("one"); - verify(stringObserver, times(1)).onNext("two"); - verify(stringObserver, times(1)).onNext("three"); - verify(stringObserver, times(1)).onNext("four"); - verify(stringObserver, times(0)).onNext("five"); - verify(stringObserver, times(0)).onNext("six"); - verify(stringObserver, times(0)).onNext("seven"); - verify(stringObserver, times(0)).onNext("eight"); - verify(stringObserver, times(0)).onNext("nine"); - } - - private static class TestSynchronousObservable implements OnSubscribeFunc { - - @Override - public Subscription onSubscribe(Observer observer) { - - observer.onNext("hello"); - observer.onCompleted(); - - return new Subscription() { - - @Override - public void unsubscribe() { - // unregister ... will never be called here since we are executing synchronously - } - - }; - } - } - - private static class TestASynchronousObservable implements OnSubscribeFunc { - Thread t; - final CountDownLatch onNextBeingSent = new CountDownLatch(1); - - @Override - public Subscription onSubscribe(final Observer observer) { - t = new Thread(new Runnable() { - - @Override - public void run() { - onNextBeingSent.countDown(); - observer.onNext("hello"); - // I can't use a countDownLatch to prove we are actually sending 'onNext' - // since it will block if synchronized and I'll deadlock - observer.onCompleted(); - } - - }); - t.start(); - - return new Subscription() { - - @Override - public void unsubscribe() { - - } - - }; - } - } - - /** - * A Observable that doesn't do the right thing on UnSubscribe/Error/etc in that it will keep sending events down the pipe regardless of what happens. - */ - private static class TestObservable implements OnSubscribeFunc { - - Observer observer = null; - volatile boolean unsubscribed = false; - Subscription s = new Subscription() { - - @Override - public void unsubscribe() { - unsubscribed = true; - - } - - }; - - /* used to simulate subscription */ - public void sendOnCompleted() { - observer.onCompleted(); - } - - /* used to simulate subscription */ - public void sendOnNext(String value) { - observer.onNext(value); - } - - /* used to simulate subscription */ - @SuppressWarnings("unused") - public void sendOnError(Throwable e) { - observer.onError(e); - } - - @Override - public Subscription onSubscribe(final Observer observer) { - this.observer = observer; - return s; - } - } - - private static class TestErrorObservable implements OnSubscribeFunc { - - String[] valuesToReturn; - - TestErrorObservable(String... values) { - valuesToReturn = values; - } - - @Override - public Subscription onSubscribe(Observer observer) { - - for (String s : valuesToReturn) { - if (s == null) { - System.out.println("throwing exception"); - observer.onError(new NullPointerException()); - } else { - observer.onNext(s); - } - } - observer.onCompleted(); - - return new Subscription() { - - @Override - public void unsubscribe() { - // unregister ... will never be called here since we are executing synchronously - } - - }; - } - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationMergeDelayError.java b/rxjava-core/src/main/java/rx/operators/OperationMergeDelayError.java index abb450dd4d..5f1af2ff80 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationMergeDelayError.java +++ b/rxjava-core/src/main/java/rx/operators/OperationMergeDelayError.java @@ -15,27 +15,17 @@ */ package rx.operators; -import static org.junit.Assert.*; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; import rx.util.CompositeException; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicBoolean; + /** * This behaves like {@link OperationMerge} except that if any of the merged Observables notify of * an error via onError, mergeDelayError will refrain from propagating that error @@ -342,484 +332,4 @@ public void onNext(T args) { } } - - public static class UnitTest { - @Mock - Observer stringObserver; - - @Before - public void before() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testErrorDelayed1() { - final Observable o1 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" from the source (and it should never be sent by the source since onError was called - final Observable o2 = Observable.create(new TestErrorObservable("one", "two", "three")); - - @SuppressWarnings("unchecked") - Observable m = Observable.create(mergeDelayError(o1, o2)); - m.subscribe(stringObserver); - - verify(stringObserver, times(1)).onError(any(NullPointerException.class)); - verify(stringObserver, never()).onCompleted(); - verify(stringObserver, times(1)).onNext("one"); - verify(stringObserver, times(1)).onNext("two"); - verify(stringObserver, times(1)).onNext("three"); - verify(stringObserver, times(1)).onNext("four"); - verify(stringObserver, times(0)).onNext("five"); - verify(stringObserver, times(0)).onNext("six"); - } - - @Test - public void testErrorDelayed2() { - final Observable o1 = Observable.create(new TestErrorObservable("one", "two", "three")); - final Observable o2 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" from the source (and it should never be sent by the source since onError was called - final Observable o3 = Observable.create(new TestErrorObservable("seven", "eight", null)); - final Observable o4 = Observable.create(new TestErrorObservable("nine")); - - @SuppressWarnings("unchecked") - Observable m = Observable.create(mergeDelayError(o1, o2, o3, o4)); - m.subscribe(stringObserver); - - verify(stringObserver, times(1)).onError(any(NullPointerException.class)); - verify(stringObserver, never()).onCompleted(); - verify(stringObserver, times(1)).onNext("one"); - verify(stringObserver, times(1)).onNext("two"); - verify(stringObserver, times(1)).onNext("three"); - verify(stringObserver, times(1)).onNext("four"); - verify(stringObserver, times(0)).onNext("five"); - verify(stringObserver, times(0)).onNext("six"); - verify(stringObserver, times(1)).onNext("seven"); - verify(stringObserver, times(1)).onNext("eight"); - verify(stringObserver, times(1)).onNext("nine"); - } - - @Test - public void testErrorDelayed3() { - final Observable o1 = Observable.create(new TestErrorObservable("one", "two", "three")); - final Observable o2 = Observable.create(new TestErrorObservable("four", "five", "six")); - final Observable o3 = Observable.create(new TestErrorObservable("seven", "eight", null)); - final Observable o4 = Observable.create(new TestErrorObservable("nine")); - - @SuppressWarnings("unchecked") - Observable m = Observable.create(mergeDelayError(o1, o2, o3, o4)); - m.subscribe(stringObserver); - - verify(stringObserver, times(1)).onError(any(NullPointerException.class)); - verify(stringObserver, never()).onCompleted(); - verify(stringObserver, times(1)).onNext("one"); - verify(stringObserver, times(1)).onNext("two"); - verify(stringObserver, times(1)).onNext("three"); - verify(stringObserver, times(1)).onNext("four"); - verify(stringObserver, times(1)).onNext("five"); - verify(stringObserver, times(1)).onNext("six"); - verify(stringObserver, times(1)).onNext("seven"); - verify(stringObserver, times(1)).onNext("eight"); - verify(stringObserver, times(1)).onNext("nine"); - } - - @Test - public void testErrorDelayed4() { - final Observable o1 = Observable.create(new TestErrorObservable("one", "two", "three")); - final Observable o2 = Observable.create(new TestErrorObservable("four", "five", "six")); - final Observable o3 = Observable.create(new TestErrorObservable("seven", "eight")); - final Observable o4 = Observable.create(new TestErrorObservable("nine", null)); - - @SuppressWarnings("unchecked") - Observable m = Observable.create(mergeDelayError(o1, o2, o3, o4)); - m.subscribe(stringObserver); - - verify(stringObserver, times(1)).onError(any(NullPointerException.class)); - verify(stringObserver, never()).onCompleted(); - verify(stringObserver, times(1)).onNext("one"); - verify(stringObserver, times(1)).onNext("two"); - verify(stringObserver, times(1)).onNext("three"); - verify(stringObserver, times(1)).onNext("four"); - verify(stringObserver, times(1)).onNext("five"); - verify(stringObserver, times(1)).onNext("six"); - verify(stringObserver, times(1)).onNext("seven"); - verify(stringObserver, times(1)).onNext("eight"); - verify(stringObserver, times(1)).onNext("nine"); - } - - @Test - public void testErrorDelayed4WithThreading() { - final TestAsyncErrorObservable o1 = new TestAsyncErrorObservable("one", "two", "three"); - final TestAsyncErrorObservable o2 = new TestAsyncErrorObservable("four", "five", "six"); - final TestAsyncErrorObservable o3 = new TestAsyncErrorObservable("seven", "eight"); - // throw the error at the very end so no onComplete will be called after it - final TestAsyncErrorObservable o4 = new TestAsyncErrorObservable("nine", null); - - @SuppressWarnings("unchecked") - Observable m = Observable.create(mergeDelayError(Observable.create(o1), Observable.create(o2), Observable.create(o3), Observable.create(o4))); - m.subscribe(stringObserver); - - try { - o1.t.join(); - o2.t.join(); - o3.t.join(); - o4.t.join(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - - verify(stringObserver, times(1)).onError(any(NullPointerException.class)); - verify(stringObserver, never()).onCompleted(); - verify(stringObserver, times(1)).onNext("one"); - verify(stringObserver, times(1)).onNext("two"); - verify(stringObserver, times(1)).onNext("three"); - verify(stringObserver, times(1)).onNext("four"); - verify(stringObserver, times(1)).onNext("five"); - verify(stringObserver, times(1)).onNext("six"); - verify(stringObserver, times(1)).onNext("seven"); - verify(stringObserver, times(1)).onNext("eight"); - verify(stringObserver, times(1)).onNext("nine"); - } - - @Test - public void testCompositeErrorDelayed1() { - final Observable o1 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" from the source (and it should never be sent by the source since onError was called - final Observable o2 = Observable.create(new TestErrorObservable("one", "two", null)); - - @SuppressWarnings("unchecked") - Observable m = Observable.create(mergeDelayError(o1, o2)); - m.subscribe(stringObserver); - - verify(stringObserver, times(1)).onError(any(CompositeException.class)); - verify(stringObserver, never()).onCompleted(); - verify(stringObserver, times(1)).onNext("one"); - verify(stringObserver, times(1)).onNext("two"); - verify(stringObserver, times(0)).onNext("three"); - verify(stringObserver, times(1)).onNext("four"); - verify(stringObserver, times(0)).onNext("five"); - verify(stringObserver, times(0)).onNext("six"); - } - - @Test - public void testCompositeErrorDelayed2() { - final Observable o1 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" from the source (and it should never be sent by the source since onError was called - final Observable o2 = Observable.create(new TestErrorObservable("one", "two", null)); - - @SuppressWarnings("unchecked") - Observable m = Observable.create(mergeDelayError(o1, o2)); - CaptureObserver w = new CaptureObserver(); - m.subscribe(w); - - assertNotNull(w.e); - if (w.e instanceof CompositeException) { - assertEquals(2, ((CompositeException) w.e).getExceptions().size()); - w.e.printStackTrace(); - } else { - fail("Expecting CompositeException"); - } - - } - - /** - * The unit tests below are from OperationMerge and should ensure the normal merge functionality is correct. - */ - - @Test - public void testMergeObservableOfObservables() { - final Observable o1 = Observable.create(new TestSynchronousObservable()); - final Observable o2 = Observable.create(new TestSynchronousObservable()); - - Observable> observableOfObservables = Observable.create(new OnSubscribeFunc>() { - - @Override - public Subscription onSubscribe(Observer> observer) { - // simulate what would happen in an observable - observer.onNext(o1); - observer.onNext(o2); - observer.onCompleted(); - - return new Subscription() { - - @Override - public void unsubscribe() { - // unregister ... will never be called here since we are executing synchronously - } - - }; - } - - }); - Observable m = Observable.create(mergeDelayError(observableOfObservables)); - m.subscribe(stringObserver); - - verify(stringObserver, never()).onError(any(Throwable.class)); - verify(stringObserver, times(1)).onCompleted(); - verify(stringObserver, times(2)).onNext("hello"); - } - - @Test - public void testMergeArray() { - final Observable o1 = Observable.create(new TestSynchronousObservable()); - final Observable o2 = Observable.create(new TestSynchronousObservable()); - - @SuppressWarnings("unchecked") - Observable m = Observable.create(mergeDelayError(o1, o2)); - m.subscribe(stringObserver); - - verify(stringObserver, never()).onError(any(Throwable.class)); - verify(stringObserver, times(2)).onNext("hello"); - verify(stringObserver, times(1)).onCompleted(); - } - - @Test - public void testMergeList() { - final Observable o1 = Observable.create(new TestSynchronousObservable()); - final Observable o2 = Observable.create(new TestSynchronousObservable()); - List> listOfObservables = new ArrayList>(); - listOfObservables.add(o1); - listOfObservables.add(o2); - - Observable m = Observable.create(mergeDelayError(listOfObservables)); - m.subscribe(stringObserver); - - verify(stringObserver, never()).onError(any(Throwable.class)); - verify(stringObserver, times(1)).onCompleted(); - verify(stringObserver, times(2)).onNext("hello"); - } - - @Test - public void testUnSubscribe() { - TestObservable tA = new TestObservable(); - TestObservable tB = new TestObservable(); - - @SuppressWarnings("unchecked") - Observable m = Observable.create(mergeDelayError(Observable.create(tA), Observable.create(tB))); - Subscription s = m.subscribe(stringObserver); - - tA.sendOnNext("Aone"); - tB.sendOnNext("Bone"); - s.unsubscribe(); - tA.sendOnNext("Atwo"); - tB.sendOnNext("Btwo"); - tA.sendOnCompleted(); - tB.sendOnCompleted(); - - verify(stringObserver, never()).onError(any(Throwable.class)); - verify(stringObserver, times(1)).onNext("Aone"); - verify(stringObserver, times(1)).onNext("Bone"); - assertTrue(tA.unsubscribed); - assertTrue(tB.unsubscribed); - verify(stringObserver, never()).onNext("Atwo"); - verify(stringObserver, never()).onNext("Btwo"); - verify(stringObserver, never()).onCompleted(); - } - - @Test - public void testMergeArrayWithThreading() { - final TestASynchronousObservable o1 = new TestASynchronousObservable(); - final TestASynchronousObservable o2 = new TestASynchronousObservable(); - - @SuppressWarnings("unchecked") - Observable m = Observable.create(mergeDelayError(Observable.create(o1), Observable.create(o2))); - m.subscribe(stringObserver); - - try { - o1.t.join(); - o2.t.join(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - - verify(stringObserver, never()).onError(any(Throwable.class)); - verify(stringObserver, times(2)).onNext("hello"); - verify(stringObserver, times(1)).onCompleted(); - } - - private static class TestSynchronousObservable implements OnSubscribeFunc { - - @Override - public Subscription onSubscribe(Observer observer) { - - observer.onNext("hello"); - observer.onCompleted(); - - return new Subscription() { - - @Override - public void unsubscribe() { - // unregister ... will never be called here since we are executing synchronously - } - - }; - } - } - - private static class TestASynchronousObservable implements OnSubscribeFunc { - Thread t; - - @Override - public Subscription onSubscribe(final Observer observer) { - t = new Thread(new Runnable() { - - @Override - public void run() { - observer.onNext("hello"); - observer.onCompleted(); - } - - }); - t.start(); - - return new Subscription() { - - @Override - public void unsubscribe() { - - } - - }; - } - } - - /** - * A Observable that doesn't do the right thing on UnSubscribe/Error/etc in that it will keep sending events down the pipe regardless of what happens. - */ - private static class TestObservable implements OnSubscribeFunc { - - Observer observer = null; - volatile boolean unsubscribed = false; - Subscription s = new Subscription() { - - @Override - public void unsubscribe() { - unsubscribed = true; - - } - - }; - - /* used to simulate subscription */ - public void sendOnCompleted() { - observer.onCompleted(); - } - - /* used to simulate subscription */ - public void sendOnNext(String value) { - observer.onNext(value); - } - - /* used to simulate subscription */ - @SuppressWarnings("unused") - public void sendOnError(Throwable e) { - observer.onError(e); - } - - @Override - public Subscription onSubscribe(final Observer observer) { - this.observer = observer; - return s; - } - } - - private static class TestErrorObservable implements OnSubscribeFunc { - - String[] valuesToReturn; - - TestErrorObservable(String... values) { - valuesToReturn = values; - } - - @Override - public Subscription onSubscribe(Observer observer) { - boolean errorThrown = false; - for (String s : valuesToReturn) { - if (s == null) { - System.out.println("throwing exception"); - observer.onError(new NullPointerException()); - errorThrown = true; - // purposefully not returning here so it will continue calling onNext - // so that we also test that we handle bad sequences like this - } else { - observer.onNext(s); - } - } - if (!errorThrown) { - observer.onCompleted(); - } - - return new Subscription() { - - @Override - public void unsubscribe() { - // unregister ... will never be called here since we are executing synchronously - } - - }; - } - } - - private static class TestAsyncErrorObservable implements OnSubscribeFunc { - - String[] valuesToReturn; - - TestAsyncErrorObservable(String... values) { - valuesToReturn = values; - } - - Thread t; - - @Override - public Subscription onSubscribe(final Observer observer) { - t = new Thread(new Runnable() { - - @Override - public void run() { - for (String s : valuesToReturn) { - if (s == null) { - System.out.println("throwing exception"); - try { - Thread.sleep(100); - } catch (Throwable e) { - - } - observer.onError(new NullPointerException()); - return; - } else { - observer.onNext(s); - } - } - System.out.println("subscription complete"); - observer.onCompleted(); - } - - }); - t.start(); - - return new Subscription() { - - @Override - public void unsubscribe() { - - } - - }; - } - } - - private static class CaptureObserver implements Observer { - volatile Throwable e; - - @Override - public void onCompleted() { - - } - - @Override - public void onError(Throwable e) { - this.e = e; - } - - @Override - public void onNext(String args) { - - } - - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationMostRecent.java b/rxjava-core/src/main/java/rx/operators/OperationMostRecent.java index b2eabb2893..003b54aaad 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationMostRecent.java +++ b/rxjava-core/src/main/java/rx/operators/OperationMostRecent.java @@ -15,20 +15,14 @@ */ package rx.operators; -import static org.junit.Assert.*; +import rx.Observable; +import rx.Observer; +import rx.util.Exceptions; import java.util.Iterator; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; -import org.junit.Test; - -import rx.Observable; -import rx.Observer; -import rx.subjects.PublishSubject; -import rx.subjects.Subject; -import rx.util.Exceptions; - /** * Returns an Iterable that always returns the item most recently emitted by an Observable, or a * seed value if no item has yet been emitted. @@ -117,53 +111,4 @@ private T getRecentValue() { } } - - public static class UnitTest { - @Test - public void testMostRecent() { - Subject observable = PublishSubject.create(); - - Iterator it = mostRecent(observable, "default").iterator(); - - assertTrue(it.hasNext()); - assertEquals("default", it.next()); - assertEquals("default", it.next()); - - observable.onNext("one"); - assertTrue(it.hasNext()); - assertEquals("one", it.next()); - assertEquals("one", it.next()); - - observable.onNext("two"); - assertTrue(it.hasNext()); - assertEquals("two", it.next()); - assertEquals("two", it.next()); - - observable.onCompleted(); - assertFalse(it.hasNext()); - - } - - @Test(expected = TestException.class) - public void testMostRecentWithException() { - Subject observable = PublishSubject.create(); - - Iterator it = mostRecent(observable, "default").iterator(); - - assertTrue(it.hasNext()); - assertEquals("default", it.next()); - assertEquals("default", it.next()); - - observable.onError(new TestException()); - assertTrue(it.hasNext()); - - it.next(); - } - - private static class TestException extends RuntimeException { - private static final long serialVersionUID = 1L; - } - - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationMulticast.java b/rxjava-core/src/main/java/rx/operators/OperationMulticast.java index e24c24a91a..b93f9917f1 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationMulticast.java +++ b/rxjava-core/src/main/java/rx/operators/OperationMulticast.java @@ -15,15 +15,10 @@ */ package rx.operators; -import static org.mockito.Mockito.*; - -import org.junit.Test; - import rx.Observable; import rx.Observer; import rx.Subscription; import rx.observables.ConnectableObservable; -import rx.subjects.PublishSubject; import rx.subjects.Subject; public class OperationMulticast { @@ -88,92 +83,4 @@ public void unsubscribe() { } - - public static class UnitTest { - - @Test - public void testMulticast() { - Subject source = PublishSubject.create(); - - ConnectableObservable multicasted = OperationMulticast.multicast(source, - PublishSubject.create()); - - @SuppressWarnings("unchecked") - Observer observer = mock(Observer.class); - multicasted.subscribe(observer); - - source.onNext("one"); - source.onNext("two"); - - multicasted.connect(); - - source.onNext("three"); - source.onNext("four"); - source.onCompleted(); - - verify(observer, never()).onNext("one"); - verify(observer, never()).onNext("two"); - verify(observer, times(1)).onNext("three"); - verify(observer, times(1)).onNext("four"); - verify(observer, times(1)).onCompleted(); - - } - - @Test - public void testMulticastConnectTwice() { - Subject source = PublishSubject.create(); - - ConnectableObservable multicasted = OperationMulticast.multicast(source, - PublishSubject.create()); - - @SuppressWarnings("unchecked") - Observer observer = mock(Observer.class); - multicasted.subscribe(observer); - - source.onNext("one"); - - multicasted.connect(); - multicasted.connect(); - - source.onNext("two"); - source.onCompleted(); - - verify(observer, never()).onNext("one"); - verify(observer, times(1)).onNext("two"); - verify(observer, times(1)).onCompleted(); - - } - - @Test - public void testMulticastDisconnect() { - Subject source = PublishSubject.create(); - - ConnectableObservable multicasted = OperationMulticast.multicast(source, - PublishSubject.create()); - - @SuppressWarnings("unchecked") - Observer observer = mock(Observer.class); - multicasted.subscribe(observer); - - source.onNext("one"); - - Subscription connection = multicasted.connect(); - source.onNext("two"); - - connection.unsubscribe(); - source.onNext("three"); - - multicasted.connect(); - source.onNext("four"); - source.onCompleted(); - - verify(observer, never()).onNext("one"); - verify(observer, times(1)).onNext("two"); - verify(observer, never()).onNext("three"); - verify(observer, times(1)).onNext("four"); - verify(observer, times(1)).onCompleted(); - - } - - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationNext.java b/rxjava-core/src/main/java/rx/operators/OperationNext.java index 43100e1096..a4812881e3 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationNext.java +++ b/rxjava-core/src/main/java/rx/operators/OperationNext.java @@ -15,32 +15,16 @@ */ package rx.operators; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import rx.Notification; +import rx.Observable; +import rx.Observer; +import rx.util.Exceptions; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -import org.junit.Test; - -import rx.Notification; -import rx.Observable; -import rx.Observable.OnSubscribeFunc; -import rx.Observer; -import rx.Subscription; -import rx.concurrency.Schedulers; -import rx.subjects.PublishSubject; -import rx.subjects.Subject; -import rx.subscriptions.Subscriptions; -import rx.util.Exceptions; /** * Returns an Iterable that blocks until the Observable emits another item, then returns that item. @@ -180,278 +164,4 @@ public Notification takeNext() throws InterruptedException { } } - - public static class UnitTest { - - private void fireOnNextInNewThread(final Subject o, final String value) { - new Thread() { - @Override - public void run() { - try { - Thread.sleep(500); - } catch (InterruptedException e) { - // ignore - } - o.onNext(value); - } - }.start(); - } - - private void fireOnErrorInNewThread(final Subject o) { - new Thread() { - @Override - public void run() { - try { - Thread.sleep(500); - } catch (InterruptedException e) { - // ignore - } - o.onError(new TestException()); - } - }.start(); - } - - - @Test - public void testNext() { - Subject obs = PublishSubject.create(); - Iterator it = next(obs).iterator(); - fireOnNextInNewThread(obs, "one"); - assertTrue(it.hasNext()); - assertEquals("one", it.next()); - - fireOnNextInNewThread(obs, "two"); - assertTrue(it.hasNext()); - assertEquals("two", it.next()); - - obs.onCompleted(); - assertFalse(it.hasNext()); - try { - it.next(); - fail("At the end of an iterator should throw a NoSuchElementException"); - } - catch(NoSuchElementException e){ - } - - // If the observable is completed, hasNext always returns false and next always throw a NoSuchElementException. - assertFalse(it.hasNext()); - try { - it.next(); - fail("At the end of an iterator should throw a NoSuchElementException"); - } - catch(NoSuchElementException e){ - } - } - - @Test - public void testNextWithError() { - Subject obs = PublishSubject.create(); - Iterator it = next(obs).iterator(); - fireOnNextInNewThread(obs, "one"); - assertTrue(it.hasNext()); - assertEquals("one", it.next()); - - fireOnErrorInNewThread(obs); - try { - it.hasNext(); - fail("Expected an TestException"); - } - catch(TestException e) { - } - - assertErrorAfterObservableFail(it); - } - - @Test - public void testNextWithEmpty() { - Observable obs = Observable.empty().observeOn(Schedulers.newThread()); - Iterator it = next(obs).iterator(); - - assertFalse(it.hasNext()); - try { - it.next(); - fail("At the end of an iterator should throw a NoSuchElementException"); - } - catch(NoSuchElementException e){ - } - - // If the observable is completed, hasNext always returns false and next always throw a NoSuchElementException. - assertFalse(it.hasNext()); - try { - it.next(); - fail("At the end of an iterator should throw a NoSuchElementException"); - } - catch(NoSuchElementException e){ - } - } - - @Test - public void testOnError() throws Throwable { - Subject obs = PublishSubject.create(); - Iterator it = next(obs).iterator(); - - obs.onError(new TestException()); - try { - it.hasNext(); - fail("Expected an TestException"); - } - catch(TestException e) { - // successful - } - - assertErrorAfterObservableFail(it); - } - - @Test - public void testOnErrorInNewThread() { - Subject obs = PublishSubject.create(); - Iterator it = next(obs).iterator(); - - fireOnErrorInNewThread(obs); - - try { - it.hasNext(); - fail("Expected an TestException"); - } - catch(TestException e) { - // successful - } - - assertErrorAfterObservableFail(it); - } - - private void assertErrorAfterObservableFail(Iterator it) { - // After the observable fails, hasNext and next always throw the exception. - try { - it.hasNext(); - fail("hasNext should throw a TestException"); - } - catch(TestException e){ - } - try { - it.next(); - fail("next should throw a TestException"); - } - catch(TestException e){ - } - } - - @Test - public void testNextWithOnlyUsingNextMethod() { - Subject obs = PublishSubject.create(); - Iterator it = next(obs).iterator(); - fireOnNextInNewThread(obs, "one"); - assertEquals("one", it.next()); - - fireOnNextInNewThread(obs, "two"); - assertEquals("two", it.next()); - - obs.onCompleted(); - try { - it.next(); - fail("At the end of an iterator should throw a NoSuchElementException"); - } - catch(NoSuchElementException e){ - } - } - - @Test - public void testNextWithCallingHasNextMultipleTimes() { - Subject obs = PublishSubject.create(); - Iterator it = next(obs).iterator(); - fireOnNextInNewThread(obs, "one"); - assertTrue(it.hasNext()); - assertTrue(it.hasNext()); - assertTrue(it.hasNext()); - assertTrue(it.hasNext()); - assertEquals("one", it.next()); - - obs.onCompleted(); - try { - it.next(); - fail("At the end of an iterator should throw a NoSuchElementException"); - } - catch(NoSuchElementException e){ - } - } - - @SuppressWarnings("serial") - private static class TestException extends RuntimeException { - - } - - /** - * Confirm that no buffering or blocking of the Observable onNext calls occurs and it just grabs the next emitted value. - * - * This results in output such as => a: 1 b: 2 c: 89 - * - * @throws Throwable - */ - @Test - public void testNoBufferingOrBlockingOfSequence() throws Throwable { - final CountDownLatch finished = new CountDownLatch(1); - final int COUNT = 30; - final CountDownLatch timeHasPassed = new CountDownLatch(COUNT); - final AtomicBoolean running = new AtomicBoolean(true); - final AtomicInteger count = new AtomicInteger(0); - final Observable obs = Observable.create(new OnSubscribeFunc() { - - @Override - public Subscription onSubscribe(final Observer o) { - new Thread(new Runnable() { - - @Override - public void run() { - try { - while (running.get()) { - o.onNext(count.incrementAndGet()); - timeHasPassed.countDown(); - } - o.onCompleted(); - } catch (Throwable e) { - o.onError(e); - } finally { - finished.countDown(); - } - } - }).start(); - return Subscriptions.empty(); - } - - }); - - Iterator it = next(obs).iterator(); - - assertTrue(it.hasNext()); - int a = it.next(); - assertTrue(it.hasNext()); - int b = it.next(); - // we should have a different value - assertTrue("a and b should be different", a != b); - - // wait for some time (if times out we are blocked somewhere so fail ... set very high for very slow, constrained machines) - timeHasPassed.await(8000, TimeUnit.MILLISECONDS); - - assertTrue(it.hasNext()); - int c = it.next(); - - assertTrue("c should not just be the next in sequence", c != (b + 1)); - assertTrue("expected that c [" + c + "] is higher than or equal to " + COUNT, c >= COUNT); - - assertTrue(it.hasNext()); - int d = it.next(); - assertTrue(d > c); - - // shut down the thread - running.set(false); - - finished.await(); - - assertFalse(it.hasNext()); - - System.out.println("a: " + a + " b: " + b + " c: " + c); - } - - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationObserveOn.java b/rxjava-core/src/main/java/rx/operators/OperationObserveOn.java index aef1cb9548..e1272b8152 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationObserveOn.java +++ b/rxjava-core/src/main/java/rx/operators/OperationObserveOn.java @@ -15,27 +15,13 @@ */ package rx.operators; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Scheduler; import rx.Subscription; import rx.concurrency.ImmediateScheduler; -import rx.concurrency.Schedulers; import rx.subscriptions.CompositeSubscription; -import rx.util.functions.Func2; /** * Asynchronously notify Observers on the specified Scheduler. @@ -69,58 +55,4 @@ public Subscription onSubscribe(final Observer observer) { } } } - - public static class UnitTest { - - /** - * This is testing a no-op path since it uses Schedulers.immediate() which will not do scheduling. - */ - @Test - @SuppressWarnings("unchecked") - public void testObserveOn() { - Observer observer = mock(Observer.class); - Observable.create(observeOn(Observable.from(1, 2, 3), Schedulers.immediate())).subscribe(observer); - - verify(observer, times(1)).onNext(1); - verify(observer, times(1)).onNext(2); - verify(observer, times(1)).onNext(3); - verify(observer, times(1)).onCompleted(); - } - - @Test - @SuppressWarnings("unchecked") - public void testOrdering() throws InterruptedException { - Observable obs = Observable.from("one", null, "two", "three", "four"); - - Observer observer = mock(Observer.class); - - InOrder inOrder = inOrder(observer); - - final CountDownLatch completedLatch = new CountDownLatch(1); - doAnswer(new Answer() { - - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - completedLatch.countDown(); - return null; - } - }).when(observer).onCompleted(); - - obs.observeOn(Schedulers.threadPoolForComputation()).subscribe(observer); - - if (!completedLatch.await(1000, TimeUnit.MILLISECONDS)) { - fail("timed out waiting"); - } - - inOrder.verify(observer, times(1)).onNext("one"); - inOrder.verify(observer, times(1)).onNext(null); - inOrder.verify(observer, times(1)).onNext("two"); - inOrder.verify(observer, times(1)).onNext("three"); - inOrder.verify(observer, times(1)).onNext("four"); - inOrder.verify(observer, times(1)).onCompleted(); - inOrder.verifyNoMoreInteractions(); - } - - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationOnErrorResumeNextViaFunction.java b/rxjava-core/src/main/java/rx/operators/OperationOnErrorResumeNextViaFunction.java index 28bf8be311..3f63463cf9 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationOnErrorResumeNextViaFunction.java +++ b/rxjava-core/src/main/java/rx/operators/OperationOnErrorResumeNextViaFunction.java @@ -15,24 +15,16 @@ */ package rx.operators; -import static org.junit.Assert.*; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicReference; - -import org.junit.Test; -import org.mockito.Mockito; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; -import rx.subscriptions.Subscriptions; import rx.util.CompositeException; import rx.util.functions.Func1; +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicReference; + /** * Instruct an Observable to pass control to another Observable (the return value of a function) * rather than invoking onError if it encounters an error. @@ -122,155 +114,4 @@ public void unsubscribe() { }; } } - - public static class UnitTest { - - @Test - public void testResumeNextWithSynchronousExecution() { - final AtomicReference receivedException = new AtomicReference(); - Observable w = Observable.create(new OnSubscribeFunc() { - - @Override - public Subscription onSubscribe(Observer observer) { - observer.onNext("one"); - observer.onError(new Throwable("injected failure")); - return Subscriptions.empty(); - } - }); - - Func1> resume = new Func1>() { - - @Override - public Observable call(Throwable t1) { - receivedException.set(t1); - return Observable.from("twoResume", "threeResume"); - } - - }; - Observable observable = Observable.create(onErrorResumeNextViaFunction(w, resume)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, Mockito.never()).onNext("two"); - verify(aObserver, Mockito.never()).onNext("three"); - verify(aObserver, times(1)).onNext("twoResume"); - verify(aObserver, times(1)).onNext("threeResume"); - assertNotNull(receivedException.get()); - } - - @Test - public void testResumeNextWithAsyncExecution() { - final AtomicReference receivedException = new AtomicReference(); - Subscription s = mock(Subscription.class); - TestObservable w = new TestObservable(s, "one"); - Func1> resume = new Func1>() { - - @Override - public Observable call(Throwable t1) { - receivedException.set(t1); - return Observable.from("twoResume", "threeResume"); - } - - }; - Observable observable = Observable.create(onErrorResumeNextViaFunction(Observable.create(w), resume)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - - try { - w.t.join(); - } catch (InterruptedException e) { - fail(e.getMessage()); - } - - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, Mockito.never()).onNext("two"); - verify(aObserver, Mockito.never()).onNext("three"); - verify(aObserver, times(1)).onNext("twoResume"); - verify(aObserver, times(1)).onNext("threeResume"); - assertNotNull(receivedException.get()); - } - - /** - * Test that when a function throws an exception this is propagated through onError - */ - @Test - public void testFunctionThrowsError() { - Subscription s = mock(Subscription.class); - TestObservable w = new TestObservable(s, "one"); - Func1> resume = new Func1>() { - - @Override - public Observable call(Throwable t1) { - throw new RuntimeException("exception from function"); - } - - }; - Observable observable = Observable.create(onErrorResumeNextViaFunction(Observable.create(w), resume)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - - try { - w.t.join(); - } catch (InterruptedException e) { - fail(e.getMessage()); - } - - // we should get the "one" value before the error - verify(aObserver, times(1)).onNext("one"); - - // we should have received an onError call on the Observer since the resume function threw an exception - verify(aObserver, times(1)).onError(any(Throwable.class)); - verify(aObserver, times(0)).onCompleted(); - } - - private static class TestObservable implements OnSubscribeFunc { - - final Subscription s; - final String[] values; - Thread t = null; - - public TestObservable(Subscription s, String... values) { - this.s = s; - this.values = values; - } - - @Override - public Subscription onSubscribe(final Observer observer) { - System.out.println("TestObservable subscribed to ..."); - t = new Thread(new Runnable() { - - @Override - public void run() { - try { - System.out.println("running TestObservable thread"); - for (String s : values) { - System.out.println("TestObservable onNext: " + s); - observer.onNext(s); - } - throw new RuntimeException("Forced Failure"); - } catch (Throwable e) { - observer.onError(e); - } - } - - }); - System.out.println("starting TestObservable thread"); - t.start(); - System.out.println("done starting TestObservable thread"); - return s; - } - - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationOnErrorResumeNextViaObservable.java b/rxjava-core/src/main/java/rx/operators/OperationOnErrorResumeNextViaObservable.java index 3b49ce5f9c..8e09ce027a 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationOnErrorResumeNextViaObservable.java +++ b/rxjava-core/src/main/java/rx/operators/OperationOnErrorResumeNextViaObservable.java @@ -15,20 +15,12 @@ */ package rx.operators; -import static org.junit.Assert.*; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.concurrent.atomic.AtomicReference; - -import org.junit.Test; -import org.mockito.Mockito; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; -import rx.util.functions.Func1; + +import java.util.concurrent.atomic.AtomicReference; /** * Instruct an Observable to pass control to another Observable rather than invoking @@ -116,119 +108,4 @@ public void unsubscribe() { }; } } - - public static class UnitTest { - - @Test - public void testResumeNext() { - Subscription s = mock(Subscription.class); - // Trigger failure on second element - TestObservable f = new TestObservable(s, "one", "fail", "two", "three"); - Observable w = Observable.create(f); - Observable resume = Observable.from("twoResume", "threeResume"); - Observable observable = Observable.create(onErrorResumeNextViaObservable(w, resume)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - - try { - f.t.join(); - } catch (InterruptedException e) { - fail(e.getMessage()); - } - - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, Mockito.never()).onNext("two"); - verify(aObserver, Mockito.never()).onNext("three"); - verify(aObserver, times(1)).onNext("twoResume"); - verify(aObserver, times(1)).onNext("threeResume"); - } - - @Test - public void testMapResumeAsyncNext() { - Subscription sr = mock(Subscription.class); - // Trigger multiple failures - Observable w = Observable.from("one", "fail", "two", "three", "fail"); - // Resume Observable is async - TestObservable f = new TestObservable(sr, "twoResume", "threeResume"); - Observable resume = Observable.create(f); - - // Introduce map function that fails intermittently (Map does not prevent this when the observer is a - // rx.operator incl onErrorResumeNextViaObservable) - w = w.map(new Func1() { - public String call(String s) { - if ("fail".equals(s)) - throw new RuntimeException("Forced Failure"); - System.out.println("BadMapper:" + s); - return s; - } - }); - - Observable observable = Observable.create(onErrorResumeNextViaObservable(w, resume)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - - try { - f.t.join(); - } catch (InterruptedException e) { - fail(e.getMessage()); - } - - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, Mockito.never()).onNext("two"); - verify(aObserver, Mockito.never()).onNext("three"); - verify(aObserver, times(1)).onNext("twoResume"); - verify(aObserver, times(1)).onNext("threeResume"); - } - - private static class TestObservable implements OnSubscribeFunc { - - final Subscription s; - final String[] values; - Thread t = null; - - public TestObservable(Subscription s, String... values) { - this.s = s; - this.values = values; - } - - @Override - public Subscription onSubscribe(final Observer observer) { - System.out.println("TestObservable subscribed to ..."); - t = new Thread(new Runnable() { - - @Override - public void run() { - try { - System.out.println("running TestObservable thread"); - for (String s : values) { - if ("fail".equals(s)) - throw new RuntimeException("Forced Failure"); - System.out.println("TestObservable onNext: " + s); - observer.onNext(s); - } - System.out.println("TestObservable onCompleted"); - observer.onCompleted(); - } catch (Throwable e) { - System.out.println("TestObservable onError: " + e); - observer.onError(e); - } - } - - }); - System.out.println("starting TestObservable thread"); - t.start(); - System.out.println("done starting TestObservable thread"); - return s; - } - - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationOnErrorReturn.java b/rxjava-core/src/main/java/rx/operators/OperationOnErrorReturn.java index 02a268c04a..fd04d078b1 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationOnErrorReturn.java +++ b/rxjava-core/src/main/java/rx/operators/OperationOnErrorReturn.java @@ -15,16 +15,6 @@ */ package rx.operators; -import static org.junit.Assert.*; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicReference; - -import org.junit.Test; -import org.mockito.Mockito; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; @@ -32,6 +22,9 @@ import rx.util.CompositeException; import rx.util.functions.Func1; +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicReference; + /** * Instruct an Observable to emit a particular item to its Observer's onNext method * rather than invoking onError if it encounters an error. @@ -125,119 +118,4 @@ public void unsubscribe() { }; } } - - public static class UnitTest { - - @Test - public void testResumeNext() { - Subscription s = mock(Subscription.class); - TestObservable f = new TestObservable(s, "one"); - Observable w = Observable.create(f); - final AtomicReference capturedException = new AtomicReference(); - - Observable observable = Observable.create(onErrorReturn(w, new Func1() { - - @Override - public String call(Throwable e) { - capturedException.set(e); - return "failure"; - } - - })); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - - try { - f.t.join(); - } catch (InterruptedException e) { - fail(e.getMessage()); - } - - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, times(1)).onNext("failure"); - assertNotNull(capturedException.get()); - } - - /** - * Test that when a function throws an exception this is propagated through onError - */ - @Test - public void testFunctionThrowsError() { - Subscription s = mock(Subscription.class); - TestObservable f = new TestObservable(s, "one"); - Observable w = Observable.create(f); - final AtomicReference capturedException = new AtomicReference(); - - Observable observable = Observable.create(onErrorReturn(w, new Func1() { - - @Override - public String call(Throwable e) { - capturedException.set(e); - throw new RuntimeException("exception from function"); - } - - })); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - - try { - f.t.join(); - } catch (InterruptedException e) { - fail(e.getMessage()); - } - - // we should get the "one" value before the error - verify(aObserver, times(1)).onNext("one"); - - // we should have received an onError call on the Observer since the resume function threw an exception - verify(aObserver, times(1)).onError(any(Throwable.class)); - verify(aObserver, times(0)).onCompleted(); - assertNotNull(capturedException.get()); - } - - private static class TestObservable implements OnSubscribeFunc { - - final Subscription s; - final String[] values; - Thread t = null; - - public TestObservable(Subscription s, String... values) { - this.s = s; - this.values = values; - } - - @Override - public Subscription onSubscribe(final Observer observer) { - System.out.println("TestObservable subscribed to ..."); - t = new Thread(new Runnable() { - - @Override - public void run() { - try { - System.out.println("running TestObservable thread"); - for (String s : values) { - System.out.println("TestObservable onNext: " + s); - observer.onNext(s); - } - throw new RuntimeException("Forced Failure"); - } catch (Throwable e) { - observer.onError(e); - } - } - - }); - System.out.println("starting TestObservable thread"); - t.start(); - System.out.println("done starting TestObservable thread"); - return s; - } - - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationOnExceptionResumeNextViaObservable.java b/rxjava-core/src/main/java/rx/operators/OperationOnExceptionResumeNextViaObservable.java index 9642ed9269..20e8fce867 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationOnExceptionResumeNextViaObservable.java +++ b/rxjava-core/src/main/java/rx/operators/OperationOnExceptionResumeNextViaObservable.java @@ -15,20 +15,12 @@ */ package rx.operators; -import static org.junit.Assert.*; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.concurrent.atomic.AtomicReference; - -import org.junit.Test; -import org.mockito.Mockito; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; -import rx.util.functions.Func1; + +import java.util.concurrent.atomic.AtomicReference; /** * Instruct an Observable to pass control to another Observable rather than invoking @@ -123,216 +115,4 @@ public void unsubscribe() { }; } } - - public static class UnitTest { - - @Test - public void testResumeNextWithException() { - Subscription s = mock(Subscription.class); - // Trigger failure on second element - TestObservable f = new TestObservable(s, "one", "EXCEPTION", "two", "three"); - Observable w = Observable.create(f); - Observable resume = Observable.from("twoResume", "threeResume"); - Observable observable = Observable.create(onExceptionResumeNextViaObservable(w, resume)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - - try { - f.t.join(); - } catch (InterruptedException e) { - fail(e.getMessage()); - } - - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, Mockito.never()).onNext("two"); - verify(aObserver, Mockito.never()).onNext("three"); - verify(aObserver, times(1)).onNext("twoResume"); - verify(aObserver, times(1)).onNext("threeResume"); - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - verifyNoMoreInteractions(aObserver); - } - - @Test - public void testResumeNextWithRuntimeException() { - Subscription s = mock(Subscription.class); - // Trigger failure on second element - TestObservable f = new TestObservable(s, "one", "RUNTIMEEXCEPTION", "two", "three"); - Observable w = Observable.create(f); - Observable resume = Observable.from("twoResume", "threeResume"); - Observable observable = Observable.create(onExceptionResumeNextViaObservable(w, resume)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - - try { - f.t.join(); - } catch (InterruptedException e) { - fail(e.getMessage()); - } - - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, Mockito.never()).onNext("two"); - verify(aObserver, Mockito.never()).onNext("three"); - verify(aObserver, times(1)).onNext("twoResume"); - verify(aObserver, times(1)).onNext("threeResume"); - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - verifyNoMoreInteractions(aObserver); - } - - @Test - public void testThrowablePassesThru() { - Subscription s = mock(Subscription.class); - // Trigger failure on second element - TestObservable f = new TestObservable(s, "one", "THROWABLE", "two", "three"); - Observable w = Observable.create(f); - Observable resume = Observable.from("twoResume", "threeResume"); - Observable observable = Observable.create(onExceptionResumeNextViaObservable(w, resume)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - - try { - f.t.join(); - } catch (InterruptedException e) { - fail(e.getMessage()); - } - - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, never()).onNext("two"); - verify(aObserver, never()).onNext("three"); - verify(aObserver, never()).onNext("twoResume"); - verify(aObserver, never()).onNext("threeResume"); - verify(aObserver, times(1)).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - verifyNoMoreInteractions(aObserver); - } - - @Test - public void testErrorPassesThru() { - Subscription s = mock(Subscription.class); - // Trigger failure on second element - TestObservable f = new TestObservable(s, "one", "ERROR", "two", "three"); - Observable w = Observable.create(f); - Observable resume = Observable.from("twoResume", "threeResume"); - Observable observable = Observable.create(onExceptionResumeNextViaObservable(w, resume)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - - try { - f.t.join(); - } catch (InterruptedException e) { - fail(e.getMessage()); - } - - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, never()).onNext("two"); - verify(aObserver, never()).onNext("three"); - verify(aObserver, never()).onNext("twoResume"); - verify(aObserver, never()).onNext("threeResume"); - verify(aObserver, times(1)).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - verifyNoMoreInteractions(aObserver); - } - - @Test - public void testMapResumeAsyncNext() { - Subscription sr = mock(Subscription.class); - // Trigger multiple failures - Observable w = Observable.from("one", "fail", "two", "three", "fail"); - // Resume Observable is async - TestObservable f = new TestObservable(sr, "twoResume", "threeResume"); - Observable resume = Observable.create(f); - - // Introduce map function that fails intermittently (Map does not prevent this when the observer is a - // rx.operator incl onErrorResumeNextViaObservable) - w = w.map(new Func1() { - public String call(String s) { - if ("fail".equals(s)) - throw new RuntimeException("Forced Failure"); - System.out.println("BadMapper:" + s); - return s; - } - }); - - Observable observable = Observable.create(onExceptionResumeNextViaObservable(w, resume)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - - try { - // if the thread gets started (which it shouldn't if it's working correctly) - if (f.t != null) { - f.t.join(); - } - } catch (InterruptedException e) { - fail(e.getMessage()); - } - - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, never()).onNext("two"); - verify(aObserver, never()).onNext("three"); - verify(aObserver, times(1)).onNext("twoResume"); - verify(aObserver, times(1)).onNext("threeResume"); - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - private static class TestObservable implements OnSubscribeFunc { - - final Subscription s; - final String[] values; - Thread t = null; - - public TestObservable(Subscription s, String... values) { - this.s = s; - this.values = values; - } - - @Override - public Subscription onSubscribe(final Observer observer) { - System.out.println("TestObservable subscribed to ..."); - t = new Thread(new Runnable() { - - @Override - public void run() { - try { - System.out.println("running TestObservable thread"); - for (String s : values) { - if ("EXCEPTION".equals(s)) - throw new Exception("Forced Exception"); - else if ("RUNTIMEEXCEPTION".equals(s)) - throw new RuntimeException("Forced RuntimeException"); - else if ("ERROR".equals(s)) - throw new Error("Forced Error"); - else if ("THROWABLE".equals(s)) - throw new Throwable("Forced Throwable"); - System.out.println("TestObservable onNext: " + s); - observer.onNext(s); - } - System.out.println("TestObservable onCompleted"); - observer.onCompleted(); - } catch (Throwable e) { - System.out.println("TestObservable onError: " + e); - observer.onError(e); - } - } - - }); - System.out.println("starting TestObservable thread"); - t.start(); - System.out.println("done starting TestObservable thread"); - return s; - } - - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationParallel.java b/rxjava-core/src/main/java/rx/operators/OperationParallel.java index 125fd2d291..25a955e616 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationParallel.java +++ b/rxjava-core/src/main/java/rx/operators/OperationParallel.java @@ -15,20 +15,15 @@ */ package rx.operators; -import static org.junit.Assert.*; - -import java.util.concurrent.atomic.AtomicInteger; - -import org.junit.Test; - import rx.Observable; import rx.Scheduler; import rx.concurrency.Schedulers; import rx.observables.GroupedObservable; -import rx.util.functions.Action1; import rx.util.functions.Func0; import rx.util.functions.Func1; +import java.util.concurrent.atomic.AtomicInteger; + /** * Identifies unit of work that can be executed in parallel on a given Scheduler. */ @@ -61,39 +56,4 @@ public Observable call(GroupedObservable group) { } }); } - - public static class UnitTest { - - @Test - public void testParallel() { - int NUM = 1000; - final AtomicInteger count = new AtomicInteger(); - Observable.range(1, NUM).parallel( - new Func1, Observable>() { - - @Override - public Observable call(Observable o) { - return o.map(new Func1() { - - @Override - public Integer[] call(Integer t) { - return new Integer[] { t, t * 99 }; - } - - }); - } - }).toBlockingObservable().forEach(new Action1() { - - @Override - public void call(Integer[] v) { - count.incrementAndGet(); - System.out.println("V: " + v[0] + " R: " + v[1] + " Thread: " + Thread.currentThread()); - } - - }); - - // just making sure we finish and get the number we expect - assertEquals(NUM, count.get()); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationRetry.java b/rxjava-core/src/main/java/rx/operators/OperationRetry.java index 0f664ee3ec..864caf3c4e 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationRetry.java +++ b/rxjava-core/src/main/java/rx/operators/OperationRetry.java @@ -15,13 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.concurrent.atomic.AtomicInteger; - -import org.junit.Test; -import org.mockito.InOrder; import rx.Observable; import rx.Observable.OnSubscribeFunc; @@ -31,9 +24,10 @@ import rx.concurrency.Schedulers; import rx.subscriptions.CompositeSubscription; import rx.subscriptions.MultipleAssignmentSubscription; -import rx.subscriptions.Subscriptions; import rx.util.functions.Func2; +import java.util.concurrent.atomic.AtomicInteger; + public class OperationRetry { private static final int INFINITE_RETRY = -1; @@ -103,104 +97,4 @@ public void onNext(T v) { } } - - public static class UnitTest { - - @Test - public void testOriginFails() { - @SuppressWarnings("unchecked") - Observer observer = mock(Observer.class); - Observable origin = Observable.create(new FuncWithErrors(2)); - origin.subscribe(observer); - - InOrder inOrder = inOrder(observer); - inOrder.verify(observer, times(1)).onNext("beginningEveryTime"); - inOrder.verify(observer, times(1)).onError(any(RuntimeException.class)); - inOrder.verify(observer, never()).onNext("onSuccessOnly"); - inOrder.verify(observer, never()).onCompleted(); - } - - @Test - public void testRetryFail() { - int NUM_RETRIES = 1; - int NUM_FAILURES = 2; - @SuppressWarnings("unchecked") - Observer observer = mock(Observer.class); - Observable origin = Observable.create(new FuncWithErrors(NUM_FAILURES)); - Observable.create(retry(origin, NUM_RETRIES)).subscribe(observer); - - InOrder inOrder = inOrder(observer); - // should show 2 attempts (first time fail, second time (1st retry) fail) - inOrder.verify(observer, times(1 + NUM_RETRIES)).onNext("beginningEveryTime"); - // should only retry once, fail again and emit onError - inOrder.verify(observer, times(1)).onError(any(RuntimeException.class)); - // no success - inOrder.verify(observer, never()).onNext("onSuccessOnly"); - inOrder.verify(observer, never()).onCompleted(); - inOrder.verifyNoMoreInteractions(); - } - - @Test - public void testRetrySuccess() { - int NUM_RETRIES = 3; - int NUM_FAILURES = 2; - @SuppressWarnings("unchecked") - Observer observer = mock(Observer.class); - Observable origin = Observable.create(new FuncWithErrors(NUM_FAILURES)); - Observable.create(retry(origin, NUM_RETRIES)).subscribe(observer); - - InOrder inOrder = inOrder(observer); - // should show 3 attempts - inOrder.verify(observer, times(1 + NUM_FAILURES)).onNext("beginningEveryTime"); - // should have no errors - inOrder.verify(observer, never()).onError(any(Throwable.class)); - // should have a single success - inOrder.verify(observer, times(1)).onNext("onSuccessOnly"); - // should have a single successful onCompleted - inOrder.verify(observer, times(1)).onCompleted(); - inOrder.verifyNoMoreInteractions(); - } - - @Test - public void testInfiniteRetry() { - int NUM_FAILURES = 20; - @SuppressWarnings("unchecked") - Observer observer = mock(Observer.class); - Observable origin = Observable.create(new FuncWithErrors(NUM_FAILURES)); - Observable.create(retry(origin)).subscribe(observer); - - InOrder inOrder = inOrder(observer); - // should show 3 attempts - inOrder.verify(observer, times(1 + NUM_FAILURES)).onNext("beginningEveryTime"); - // should have no errors - inOrder.verify(observer, never()).onError(any(Throwable.class)); - // should have a single success - inOrder.verify(observer, times(1)).onNext("onSuccessOnly"); - // should have a single successful onCompleted - inOrder.verify(observer, times(1)).onCompleted(); - inOrder.verifyNoMoreInteractions(); - } - - public static class FuncWithErrors implements OnSubscribeFunc { - - private final int numFailures; - private final AtomicInteger count = new AtomicInteger(0); - - FuncWithErrors(int count) { - this.numFailures = count; - } - - @Override - public Subscription onSubscribe(Observer o) { - o.onNext("beginningEveryTime"); - if (count.incrementAndGet() <= numFailures) { - o.onError(new RuntimeException("forced failure: " + count.get())); - } else { - o.onNext("onSuccessOnly"); - o.onCompleted(); - } - return Subscriptions.empty(); - } - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationSample.java b/rxjava-core/src/main/java/rx/operators/OperationSample.java index 3be189f32b..32c58b1f04 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationSample.java +++ b/rxjava-core/src/main/java/rx/operators/OperationSample.java @@ -15,28 +15,19 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.InOrder; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Scheduler; import rx.Subscription; import rx.concurrency.Schedulers; -import rx.concurrency.TestScheduler; import rx.subscriptions.Subscriptions; import rx.util.functions.Action0; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + /** * Returns an Observable that emits the results of sampling the items emitted by the source * Observable at a specified time interval. @@ -122,79 +113,4 @@ public void call() { }); } } - - public static class UnitTest { - private TestScheduler scheduler; - private Observer observer; - - @Before - @SuppressWarnings("unchecked") // due to mocking - public void before() { - scheduler = new TestScheduler(); - observer = mock(Observer.class); - } - - @Test - public void testSample() { - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(final Observer observer1) { - scheduler.schedule(new Action0() { - @Override - public void call() { - observer1.onNext(1L); - } - }, 1, TimeUnit.SECONDS); - scheduler.schedule(new Action0() { - @Override - public void call() { - observer1.onNext(2L); - } - }, 2, TimeUnit.SECONDS); - scheduler.schedule(new Action0() { - @Override - public void call() { - observer1.onCompleted(); - } - }, 3, TimeUnit.SECONDS); - - return Subscriptions.empty(); - } - }); - - Observable sampled = Observable.create(OperationSample.sample(source, 400L, TimeUnit.MILLISECONDS, scheduler)); - sampled.subscribe(observer); - - InOrder inOrder = inOrder(observer); - - scheduler.advanceTimeTo(800L, TimeUnit.MILLISECONDS); - verify(observer, never()).onNext(any(Long.class)); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - scheduler.advanceTimeTo(1200L, TimeUnit.MILLISECONDS); - inOrder.verify(observer, times(1)).onNext(1L); - verify(observer, never()).onNext(2L); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - scheduler.advanceTimeTo(1600L, TimeUnit.MILLISECONDS); - inOrder.verify(observer, times(1)).onNext(1L); - verify(observer, never()).onNext(2L); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - scheduler.advanceTimeTo(2000L, TimeUnit.MILLISECONDS); - inOrder.verify(observer, never()).onNext(1L); - inOrder.verify(observer, times(1)).onNext(2L); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - scheduler.advanceTimeTo(3000L, TimeUnit.MILLISECONDS); - inOrder.verify(observer, never()).onNext(1L); - inOrder.verify(observer, times(2)).onNext(2L); - verify(observer, times(1)).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationScan.java b/rxjava-core/src/main/java/rx/operators/OperationScan.java index 513646b8ef..4d0cfc95d0 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationScan.java +++ b/rxjava-core/src/main/java/rx/operators/OperationScan.java @@ -15,13 +15,6 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.MockitoAnnotations; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; @@ -171,92 +164,4 @@ public void onCompleted() { observer.onCompleted(); } } - - public static class UnitTest { - - @Before - public void before() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testScanIntegersWithInitialValue() { - @SuppressWarnings("unchecked") - Observer observer = mock(Observer.class); - - Observable observable = Observable.from(1, 2, 3); - - Observable m = Observable.create(scan(observable, "", new Func2() { - - @Override - public String call(String s, Integer n) { - return s + n.toString(); - } - - })); - m.subscribe(observer); - - verify(observer, never()).onError(any(Throwable.class)); - verify(observer, times(1)).onNext(""); - verify(observer, times(1)).onNext("1"); - verify(observer, times(1)).onNext("12"); - verify(observer, times(1)).onNext("123"); - verify(observer, times(4)).onNext(anyString()); - verify(observer, times(1)).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - } - - @Test - public void testScanIntegersWithoutInitialValue() { - @SuppressWarnings("unchecked") - Observer Observer = mock(Observer.class); - - Observable observable = Observable.from(1, 2, 3); - - Observable m = Observable.create(scan(observable, new Func2() { - - @Override - public Integer call(Integer t1, Integer t2) { - return t1 + t2; - } - - })); - m.subscribe(Observer); - - verify(Observer, never()).onError(any(Throwable.class)); - verify(Observer, never()).onNext(0); - verify(Observer, times(1)).onNext(1); - verify(Observer, times(1)).onNext(3); - verify(Observer, times(1)).onNext(6); - verify(Observer, times(3)).onNext(anyInt()); - verify(Observer, times(1)).onCompleted(); - verify(Observer, never()).onError(any(Throwable.class)); - } - - @Test - public void testScanIntegersWithoutInitialValueAndOnlyOneValue() { - @SuppressWarnings("unchecked") - Observer Observer = mock(Observer.class); - - Observable observable = Observable.from(1); - - Observable m = Observable.create(scan(observable, new Func2() { - - @Override - public Integer call(Integer t1, Integer t2) { - return t1 + t2; - } - - })); - m.subscribe(Observer); - - verify(Observer, never()).onError(any(Throwable.class)); - verify(Observer, never()).onNext(0); - verify(Observer, times(1)).onNext(1); - verify(Observer, times(1)).onNext(anyInt()); - verify(Observer, times(1)).onCompleted(); - verify(Observer, never()).onError(any(Throwable.class)); - } - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationSkip.java b/rxjava-core/src/main/java/rx/operators/OperationSkip.java index 11fb10f1b5..63b873d826 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationSkip.java +++ b/rxjava-core/src/main/java/rx/operators/OperationSkip.java @@ -15,18 +15,13 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.concurrent.atomic.AtomicInteger; - -import org.junit.Test; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; +import java.util.concurrent.atomic.AtomicInteger; + /** * Returns an Observable that skips the first num items emitted by the source * Observable. @@ -112,39 +107,4 @@ public void onNext(T args) { } } - - public static class UnitTest { - - @Test - public void testSkip1() { - Observable w = Observable.from("one", "two", "three"); - Observable skip = Observable.create(skip(w, 2)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - skip.subscribe(aObserver); - verify(aObserver, never()).onNext("one"); - verify(aObserver, never()).onNext("two"); - verify(aObserver, times(1)).onNext("three"); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testSkip2() { - Observable w = Observable.from("one", "two", "three"); - Observable skip = Observable.create(skip(w, 1)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - skip.subscribe(aObserver); - verify(aObserver, never()).onNext("one"); - verify(aObserver, times(1)).onNext("two"); - verify(aObserver, times(1)).onNext("three"); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationSkipLast.java b/rxjava-core/src/main/java/rx/operators/OperationSkipLast.java index 10da0c06b4..9bd8253392 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationSkipLast.java +++ b/rxjava-core/src/main/java/rx/operators/OperationSkipLast.java @@ -15,25 +15,15 @@ */ package rx.operators; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.util.Deque; -import java.util.LinkedList; -import java.util.concurrent.locks.ReentrantLock; - -import org.junit.Test; -import org.mockito.InOrder; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; +import java.util.Deque; +import java.util.LinkedList; +import java.util.concurrent.locks.ReentrantLock; + /** * Bypasses a specified number of elements at the end of an observable sequence. */ @@ -133,92 +123,4 @@ public void onNext(T value) { })); } } - - public static class UnitTest { - - @Test - public void testSkipLastEmpty() { - Observable w = Observable.empty(); - Observable observable = Observable.create(skipLast(w, 2)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, never()).onNext(any(String.class)); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testSkipLast1() { - Observable w = Observable.from("one", "two", "three"); - Observable observable = Observable.create(skipLast(w, 2)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - InOrder inOrder = inOrder(aObserver); - observable.subscribe(aObserver); - inOrder.verify(aObserver, never()).onNext("two"); - inOrder.verify(aObserver, never()).onNext("three"); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testSkipLast2() { - Observable w = Observable.from("one", "two"); - Observable observable = Observable.create(skipLast(w, 2)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, never()).onNext(any(String.class)); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testSkipLastWithZeroCount() { - Observable w = Observable.from("one", "two"); - Observable observable = Observable.create(skipLast(w, 0)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, times(1)).onNext("two"); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testSkipLastWithNull() { - Observable w = Observable.from("one", null, "two"); - Observable observable = Observable.create(skipLast(w, 1)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, times(1)).onNext(null); - verify(aObserver, never()).onNext("two"); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testSkipLastWithNegativeCount() { - Observable w = Observable.from("one"); - Observable observable = Observable.create(skipLast(w, -1)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, never()).onNext(any(String.class)); - verify(aObserver, times(1)).onError( - any(IndexOutOfBoundsException.class)); - verify(aObserver, never()).onCompleted(); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationSkipWhile.java b/rxjava-core/src/main/java/rx/operators/OperationSkipWhile.java index 8277f80fc2..bf1528d8a2 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationSkipWhile.java +++ b/rxjava-core/src/main/java/rx/operators/OperationSkipWhile.java @@ -15,16 +15,6 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; -import static rx.Observable.create; - -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -import org.junit.Test; -import org.mockito.InOrder; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; @@ -32,6 +22,9 @@ import rx.util.functions.Func1; import rx.util.functions.Func2; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + /** * Skips any emitted source items as long as the specified condition holds true. Emits all further source items * as soon as the condition becomes false. @@ -102,92 +95,4 @@ public void onNext(T next) { } } - - public static class UnitTest { - @SuppressWarnings("unchecked") - Observer w = mock(Observer.class); - - private static final Func1 LESS_THAN_FIVE = new Func1() { - @Override - public Boolean call(Integer v) { - if (v == 42) throw new RuntimeException("that's not the answer to everything!"); - return v < 5; - } - }; - - private static final Func2 INDEX_LESS_THAN_THREE = new Func2() { - @Override - public Boolean call(Integer value, Integer index) { - return index < 3; - } - }; - - @Test - public void testSkipWithIndex() { - Observable src = Observable.from(1, 2, 3, 4, 5); - create(skipWhileWithIndex(src, INDEX_LESS_THAN_THREE)).subscribe(w); - - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext(4); - inOrder.verify(w, times(1)).onNext(5); - inOrder.verify(w, times(1)).onCompleted(); - inOrder.verify(w, never()).onError(any(Throwable.class)); - } - - @Test - public void testSkipEmpty() { - Observable src = Observable.empty(); - create(skipWhile(src, LESS_THAN_FIVE)).subscribe(w); - verify(w, never()).onNext(anyInt()); - verify(w, never()).onError(any(Throwable.class)); - verify(w, times(1)).onCompleted(); - } - - @Test - public void testSkipEverything() { - Observable src = Observable.from(1, 2, 3, 4, 3, 2, 1); - create(skipWhile(src, LESS_THAN_FIVE)).subscribe(w); - verify(w, never()).onNext(anyInt()); - verify(w, never()).onError(any(Throwable.class)); - verify(w, times(1)).onCompleted(); - } - - @Test - public void testSkipNothing() { - Observable src = Observable.from(5, 3, 1); - create(skipWhile(src, LESS_THAN_FIVE)).subscribe(w); - - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext(5); - inOrder.verify(w, times(1)).onNext(3); - inOrder.verify(w, times(1)).onNext(1); - inOrder.verify(w, times(1)).onCompleted(); - inOrder.verify(w, never()).onError(any(Throwable.class)); - } - - @Test - public void testSkipSome() { - Observable src = Observable.from(1, 2, 3, 4, 5, 3, 1, 5); - create(skipWhile(src, LESS_THAN_FIVE)).subscribe(w); - - InOrder inOrder = inOrder(w); - inOrder.verify(w, times(1)).onNext(5); - inOrder.verify(w, times(1)).onNext(3); - inOrder.verify(w, times(1)).onNext(1); - inOrder.verify(w, times(1)).onNext(5); - inOrder.verify(w, times(1)).onCompleted(); - inOrder.verify(w, never()).onError(any(Throwable.class)); - } - - @Test - public void testSkipError() { - Observable src = Observable.from(1, 2, 42, 5, 3, 1); - create(skipWhile(src, LESS_THAN_FIVE)).subscribe(w); - - InOrder inOrder = inOrder(w); - inOrder.verify(w, never()).onNext(anyInt()); - inOrder.verify(w, never()).onCompleted(); - inOrder.verify(w, times(1)).onError(any(RuntimeException.class)); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationSubscribeOn.java b/rxjava-core/src/main/java/rx/operators/OperationSubscribeOn.java index 6f75a32b57..f1cac4fe9d 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationSubscribeOn.java +++ b/rxjava-core/src/main/java/rx/operators/OperationSubscribeOn.java @@ -15,17 +15,11 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import org.junit.Test; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Scheduler; import rx.Subscription; -import rx.concurrency.Schedulers; import rx.util.functions.Action0; import rx.util.functions.Func2; @@ -79,30 +73,4 @@ public void call() { }); } } - - public static class UnitTest { - - @Test - @SuppressWarnings("unchecked") - public void testSubscribeOn() { - Observable w = Observable.from(1, 2, 3); - - Scheduler scheduler = spy(OperatorTester.UnitTest.forwardingScheduler(Schedulers.immediate())); - - Observer observer = mock(Observer.class); - Subscription subscription = Observable.create(subscribeOn(w, scheduler)).subscribe(observer); - - verify(scheduler, times(1)).schedule(isNull(), any(Func2.class)); - subscription.unsubscribe(); - verify(scheduler, times(1)).schedule(any(Action0.class)); - verifyNoMoreInteractions(scheduler); - - verify(observer, times(1)).onNext(1); - verify(observer, times(1)).onNext(2); - verify(observer, times(1)).onNext(3); - verify(observer, times(1)).onCompleted(); - } - - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationSum.java b/rxjava-core/src/main/java/rx/operators/OperationSum.java index 5892a00520..cc34f79520 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationSum.java +++ b/rxjava-core/src/main/java/rx/operators/OperationSum.java @@ -15,12 +15,7 @@ */ package rx.operators; -import static org.mockito.Mockito.*; - -import org.junit.Test; - import rx.Observable; -import rx.Observer; import rx.util.functions.Func2; /** @@ -63,103 +58,4 @@ public Double call(Double accu, Double next) { } }); } - - public static class UnitTest { - @SuppressWarnings("unchecked") - Observer w = mock(Observer.class); - @SuppressWarnings("unchecked") - Observer wl = mock(Observer.class); - @SuppressWarnings("unchecked") - Observer wf = mock(Observer.class); - @SuppressWarnings("unchecked") - Observer wd = mock(Observer.class); - - @Test - public void testSumOfAFewInts() throws Throwable { - Observable src = Observable.from(1, 2, 3, 4, 5); - sum(src).subscribe(w); - - verify(w, times(1)).onNext(anyInt()); - verify(w).onNext(15); - verify(w, never()).onError(any(Throwable.class)); - verify(w, times(1)).onCompleted(); - } - - @Test - public void testEmptySum() throws Throwable { - Observable src = Observable.empty(); - sum(src).subscribe(w); - - verify(w, times(1)).onNext(anyInt()); - verify(w).onNext(0); - verify(w, never()).onError(any(Throwable.class)); - verify(w, times(1)).onCompleted(); - } - - @Test - public void testSumOfAFewLongs() throws Throwable { - Observable src = Observable.from(1L, 2L, 3L, 4L, 5L); - sumLongs(src).subscribe(wl); - - verify(wl, times(1)).onNext(anyLong()); - verify(wl).onNext(15L); - verify(wl, never()).onError(any(Throwable.class)); - verify(wl, times(1)).onCompleted(); - } - - @Test - public void testEmptySumLongs() throws Throwable { - Observable src = Observable.empty(); - sumLongs(src).subscribe(wl); - - verify(wl, times(1)).onNext(anyLong()); - verify(wl).onNext(0L); - verify(wl, never()).onError(any(Throwable.class)); - verify(wl, times(1)).onCompleted(); - } - - @Test - public void testSumOfAFewFloats() throws Throwable { - Observable src = Observable.from(1.0f); - sumFloats(src).subscribe(wf); - - verify(wf, times(1)).onNext(anyFloat()); - verify(wf).onNext(1.0f); - verify(wf, never()).onError(any(Throwable.class)); - verify(wf, times(1)).onCompleted(); - } - - @Test - public void testEmptySumFloats() throws Throwable { - Observable src = Observable.empty(); - sumFloats(src).subscribe(wf); - - verify(wf, times(1)).onNext(anyFloat()); - verify(wf).onNext(0.0f); - verify(wf, never()).onError(any(Throwable.class)); - verify(wf, times(1)).onCompleted(); - } - - @Test - public void testSumOfAFewDoubles() throws Throwable { - Observable src = Observable.from(0.0d, 1.0d, 0.5d); - sumDoubles(src).subscribe(wd); - - verify(wd, times(1)).onNext(anyDouble()); - verify(wd).onNext(1.5d); - verify(wd, never()).onError(any(Throwable.class)); - verify(wd, times(1)).onCompleted(); - } - - @Test - public void testEmptySumDoubles() throws Throwable { - Observable src = Observable.empty(); - sumDoubles(src).subscribe(wd); - - verify(wd, times(1)).onNext(anyDouble()); - verify(wd).onNext(0.0d); - verify(wd, never()).onError(any(Throwable.class)); - verify(wd, times(1)).onCompleted(); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationSwitch.java b/rxjava-core/src/main/java/rx/operators/OperationSwitch.java index c40864de84..25d94a714a 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationSwitch.java +++ b/rxjava-core/src/main/java/rx/operators/OperationSwitch.java @@ -15,29 +15,12 @@ */ package rx.operators; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.util.concurrent.TimeUnit; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.InOrder; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; -import rx.concurrency.TestScheduler; import rx.subscriptions.CompositeSubscription; import rx.subscriptions.MultipleAssignmentSubscription; -import rx.subscriptions.Subscriptions; -import rx.util.functions.Action0; import rx.util.functions.Func1; /** @@ -182,355 +165,4 @@ public void onCompleted() { } } - - public static class UnitTest { - - private TestScheduler scheduler; - private Observer observer; - - @Before - @SuppressWarnings("unchecked") - public void before() { - scheduler = new TestScheduler(); - observer = mock(Observer.class); - } - - @Test - public void testSwitchWhenOuterCompleteBeforeInner() { - Observable> source = Observable.create(new OnSubscribeFunc>() { - @Override - public Subscription onSubscribe(Observer> observer) { - publishNext(observer, 50, Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - publishNext(observer, 70, "one"); - publishNext(observer, 100, "two"); - publishCompleted(observer, 200); - return Subscriptions.empty(); - } - })); - publishCompleted(observer, 60); - - return Subscriptions.empty(); - } - }); - - Observable sampled = Observable.create(OperationSwitch.switchDo(source)); - sampled.subscribe(observer); - - InOrder inOrder = inOrder(observer); - - scheduler.advanceTimeTo(350, TimeUnit.MILLISECONDS); - inOrder.verify(observer, times(2)).onNext(anyString()); - inOrder.verify(observer, times(1)).onCompleted(); - } - - @Test - public void testSwitchWhenInnerCompleteBeforeOuter() { - Observable> source = Observable.create(new OnSubscribeFunc>() { - @Override - public Subscription onSubscribe(Observer> observer) { - publishNext(observer, 10, Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - publishNext(observer, 0, "one"); - publishNext(observer, 10, "two"); - publishCompleted(observer, 20); - return Subscriptions.empty(); - } - })); - - publishNext(observer, 100, Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - publishNext(observer, 0, "three"); - publishNext(observer, 10, "four"); - publishCompleted(observer, 20); - return Subscriptions.empty(); - } - })); - publishCompleted(observer, 200); - - return Subscriptions.empty(); - } - }); - - Observable sampled = Observable.create(OperationSwitch.switchDo(source)); - sampled.subscribe(observer); - - InOrder inOrder = inOrder(observer); - - scheduler.advanceTimeTo(150, TimeUnit.MILLISECONDS); - inOrder.verify(observer, never()).onCompleted(); - inOrder.verify(observer, times(1)).onNext("one"); - inOrder.verify(observer, times(1)).onNext("two"); - inOrder.verify(observer, times(1)).onNext("three"); - inOrder.verify(observer, times(1)).onNext("four"); - - scheduler.advanceTimeTo(250, TimeUnit.MILLISECONDS); - inOrder.verify(observer, never()).onNext(anyString()); - inOrder.verify(observer, times(1)).onCompleted(); - } - - @Test - public void testSwitchWithComplete() { - Observable> source = Observable.create(new OnSubscribeFunc>() { - @Override - public Subscription onSubscribe(Observer> observer) { - publishNext(observer, 50, Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - publishNext(observer, 60, "one"); - publishNext(observer, 100, "two"); - return Subscriptions.empty(); - } - })); - - publishNext(observer, 200, Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - publishNext(observer, 0, "three"); - publishNext(observer, 100, "four"); - return Subscriptions.empty(); - } - })); - - publishCompleted(observer, 250); - - return Subscriptions.empty(); - } - }); - - Observable sampled = Observable.create(OperationSwitch.switchDo(source)); - sampled.subscribe(observer); - - InOrder inOrder = inOrder(observer); - - scheduler.advanceTimeTo(90, TimeUnit.MILLISECONDS); - inOrder.verify(observer, never()).onNext(anyString()); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - scheduler.advanceTimeTo(125, TimeUnit.MILLISECONDS); - inOrder.verify(observer, times(1)).onNext("one"); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - scheduler.advanceTimeTo(175, TimeUnit.MILLISECONDS); - inOrder.verify(observer, times(1)).onNext("two"); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - scheduler.advanceTimeTo(225, TimeUnit.MILLISECONDS); - inOrder.verify(observer, times(1)).onNext("three"); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - scheduler.advanceTimeTo(350, TimeUnit.MILLISECONDS); - inOrder.verify(observer, times(1)).onNext("four"); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - } - - @Test - public void testSwitchWithError() { - Observable> source = Observable.create(new OnSubscribeFunc>() { - @Override - public Subscription onSubscribe(Observer> observer) { - publishNext(observer, 50, Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - publishNext(observer, 50, "one"); - publishNext(observer, 100, "two"); - return Subscriptions.empty(); - } - })); - - publishNext(observer, 200, Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - publishNext(observer, 0, "three"); - publishNext(observer, 100, "four"); - return Subscriptions.empty(); - } - })); - - publishError(observer, 250, new TestException()); - - return Subscriptions.empty(); - } - }); - - Observable sampled = Observable.create(OperationSwitch.switchDo(source)); - sampled.subscribe(observer); - - InOrder inOrder = inOrder(observer); - - scheduler.advanceTimeTo(90, TimeUnit.MILLISECONDS); - inOrder.verify(observer, never()).onNext(anyString()); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - scheduler.advanceTimeTo(125, TimeUnit.MILLISECONDS); - inOrder.verify(observer, times(1)).onNext("one"); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - scheduler.advanceTimeTo(175, TimeUnit.MILLISECONDS); - inOrder.verify(observer, times(1)).onNext("two"); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - scheduler.advanceTimeTo(225, TimeUnit.MILLISECONDS); - inOrder.verify(observer, times(1)).onNext("three"); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - scheduler.advanceTimeTo(350, TimeUnit.MILLISECONDS); - inOrder.verify(observer, never()).onNext(anyString()); - verify(observer, never()).onCompleted(); - verify(observer, times(1)).onError(any(TestException.class)); - } - - @Test - public void testSwitchWithSubsequenceComplete() { - Observable> source = Observable.create(new OnSubscribeFunc>() { - @Override - public Subscription onSubscribe(Observer> observer) { - publishNext(observer, 50, Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - publishNext(observer, 50, "one"); - publishNext(observer, 100, "two"); - return Subscriptions.empty(); - } - })); - - publishNext(observer, 130, Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - publishCompleted(observer, 0); - return Subscriptions.empty(); - } - })); - - publishNext(observer, 150, Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - publishNext(observer, 50, "three"); - return Subscriptions.empty(); - } - })); - - return Subscriptions.empty(); - } - }); - - Observable sampled = Observable.create(OperationSwitch.switchDo(source)); - sampled.subscribe(observer); - - InOrder inOrder = inOrder(observer); - - scheduler.advanceTimeTo(90, TimeUnit.MILLISECONDS); - inOrder.verify(observer, never()).onNext(anyString()); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - scheduler.advanceTimeTo(125, TimeUnit.MILLISECONDS); - inOrder.verify(observer, times(1)).onNext("one"); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - scheduler.advanceTimeTo(250, TimeUnit.MILLISECONDS); - inOrder.verify(observer, times(1)).onNext("three"); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - } - - @Test - public void testSwitchWithSubsequenceError() { - Observable> source = Observable.create(new OnSubscribeFunc>() { - @Override - public Subscription onSubscribe(Observer> observer) { - publishNext(observer, 50, Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - publishNext(observer, 50, "one"); - publishNext(observer, 100, "two"); - return Subscriptions.empty(); - } - })); - - publishNext(observer, 130, Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - publishError(observer, 0, new TestException()); - return Subscriptions.empty(); - } - })); - - publishNext(observer, 150, Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - publishNext(observer, 50, "three"); - return Subscriptions.empty(); - } - })); - - return Subscriptions.empty(); - } - }); - - Observable sampled = Observable.create(OperationSwitch.switchDo(source)); - sampled.subscribe(observer); - - InOrder inOrder = inOrder(observer); - - scheduler.advanceTimeTo(90, TimeUnit.MILLISECONDS); - inOrder.verify(observer, never()).onNext(anyString()); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - scheduler.advanceTimeTo(125, TimeUnit.MILLISECONDS); - inOrder.verify(observer, times(1)).onNext("one"); - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(Throwable.class)); - - scheduler.advanceTimeTo(250, TimeUnit.MILLISECONDS); - inOrder.verify(observer, never()).onNext("three"); - verify(observer, never()).onCompleted(); - verify(observer, times(1)).onError(any(TestException.class)); - } - - private void publishCompleted(final Observer observer, long delay) { - scheduler.schedule(new Action0() { - @Override - public void call() { - observer.onCompleted(); - } - }, delay, TimeUnit.MILLISECONDS); - } - - private void publishError(final Observer observer, long delay, final Throwable error) { - scheduler.schedule(new Action0() { - @Override - public void call() { - observer.onError(error); - } - }, delay, TimeUnit.MILLISECONDS); - } - - private void publishNext(final Observer observer, long delay, final T value) { - scheduler.schedule(new Action0() { - @Override - public void call() { - observer.onNext(value); - } - }, delay, TimeUnit.MILLISECONDS); - } - - @SuppressWarnings("serial") - private class TestException extends Throwable { - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationSynchronize.java b/rxjava-core/src/main/java/rx/operators/OperationSynchronize.java index b7cd689102..4ec205f156 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationSynchronize.java +++ b/rxjava-core/src/main/java/rx/operators/OperationSynchronize.java @@ -15,12 +15,6 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import org.junit.Test; -import org.mockito.Mockito; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; @@ -102,197 +96,4 @@ public Subscription onSubscribe(Observer observer) { } } - - public static class UnitTest { - - /** - * Ensure onCompleted can not be called after an Unsubscribe - */ - @Test - public void testOnCompletedAfterUnSubscribe() { - TestObservable t = new TestObservable(null); - Observable st = Observable.create(synchronize(Observable.create(t))); - - @SuppressWarnings("unchecked") - Observer w = mock(Observer.class); - Subscription ws = st.subscribe(w); - - t.sendOnNext("one"); - ws.unsubscribe(); - t.sendOnCompleted(); - - verify(w, times(1)).onNext("one"); - verify(w, Mockito.never()).onCompleted(); - } - - /** - * Ensure onNext can not be called after an Unsubscribe - */ - @Test - public void testOnNextAfterUnSubscribe() { - TestObservable t = new TestObservable(null); - Observable st = Observable.create(synchronize(Observable.create(t))); - - @SuppressWarnings("unchecked") - Observer w = mock(Observer.class); - Subscription ws = st.subscribe(w); - - t.sendOnNext("one"); - ws.unsubscribe(); - t.sendOnNext("two"); - - verify(w, times(1)).onNext("one"); - verify(w, Mockito.never()).onNext("two"); - } - - /** - * Ensure onError can not be called after an Unsubscribe - */ - @Test - public void testOnErrorAfterUnSubscribe() { - TestObservable t = new TestObservable(null); - Observable st = Observable.create(synchronize(Observable.create(t))); - - @SuppressWarnings("unchecked") - Observer w = mock(Observer.class); - Subscription ws = st.subscribe(w); - - t.sendOnNext("one"); - ws.unsubscribe(); - t.sendOnError(new RuntimeException("bad")); - - verify(w, times(1)).onNext("one"); - verify(w, Mockito.never()).onError(any(Throwable.class)); - } - - /** - * Ensure onNext can not be called after onError - */ - @Test - public void testOnNextAfterOnError() { - TestObservable t = new TestObservable(null); - Observable st = Observable.create(synchronize(Observable.create(t))); - - @SuppressWarnings("unchecked") - Observer w = mock(Observer.class); - @SuppressWarnings("unused") - Subscription ws = st.subscribe(w); - - t.sendOnNext("one"); - t.sendOnError(new RuntimeException("bad")); - t.sendOnNext("two"); - - verify(w, times(1)).onNext("one"); - verify(w, times(1)).onError(any(Throwable.class)); - verify(w, Mockito.never()).onNext("two"); - } - - /** - * Ensure onCompleted can not be called after onError - */ - @Test - public void testOnCompletedAfterOnError() { - TestObservable t = new TestObservable(null); - Observable st = Observable.create(synchronize(Observable.create(t))); - - @SuppressWarnings("unchecked") - Observer w = mock(Observer.class); - @SuppressWarnings("unused") - Subscription ws = st.subscribe(w); - - t.sendOnNext("one"); - t.sendOnError(new RuntimeException("bad")); - t.sendOnCompleted(); - - verify(w, times(1)).onNext("one"); - verify(w, times(1)).onError(any(Throwable.class)); - verify(w, Mockito.never()).onCompleted(); - } - - /** - * Ensure onNext can not be called after onCompleted - */ - @Test - public void testOnNextAfterOnCompleted() { - TestObservable t = new TestObservable(null); - Observable st = Observable.create(synchronize(Observable.create(t))); - - @SuppressWarnings("unchecked") - Observer w = mock(Observer.class); - @SuppressWarnings("unused") - Subscription ws = st.subscribe(w); - - t.sendOnNext("one"); - t.sendOnCompleted(); - t.sendOnNext("two"); - - verify(w, times(1)).onNext("one"); - verify(w, Mockito.never()).onNext("two"); - verify(w, times(1)).onCompleted(); - verify(w, Mockito.never()).onError(any(Throwable.class)); - } - - /** - * Ensure onError can not be called after onCompleted - */ - @Test - public void testOnErrorAfterOnCompleted() { - TestObservable t = new TestObservable(null); - Observable st = Observable.create(synchronize(Observable.create(t))); - - @SuppressWarnings("unchecked") - Observer w = mock(Observer.class); - @SuppressWarnings("unused") - Subscription ws = st.subscribe(w); - - t.sendOnNext("one"); - t.sendOnCompleted(); - t.sendOnError(new RuntimeException("bad")); - - verify(w, times(1)).onNext("one"); - verify(w, times(1)).onCompleted(); - verify(w, Mockito.never()).onError(any(Throwable.class)); - } - - /** - * A Observable that doesn't do the right thing on UnSubscribe/Error/etc in that it will keep sending events down the pipe regardless of what happens. - */ - private static class TestObservable implements OnSubscribeFunc { - - Observer observer = null; - - public TestObservable(Subscription s) { - } - - /* used to simulate subscription */ - public void sendOnCompleted() { - observer.onCompleted(); - } - - /* used to simulate subscription */ - public void sendOnNext(String value) { - observer.onNext(value); - } - - /* used to simulate subscription */ - public void sendOnError(Throwable e) { - observer.onError(e); - } - - @Override - public Subscription onSubscribe(final Observer observer) { - this.observer = observer; - return new Subscription() { - - @Override - public void unsubscribe() { - // going to do nothing to pretend I'm a bad Observable that keeps allowing events to be sent - } - - }; - } - - } - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationTake.java b/rxjava-core/src/main/java/rx/operators/OperationTake.java index 061e930ff0..6448a628db 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationTake.java +++ b/rxjava-core/src/main/java/rx/operators/OperationTake.java @@ -15,30 +15,13 @@ */ package rx.operators; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; - -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -import org.junit.Test; -import org.mockito.InOrder; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; import rx.subscriptions.Subscriptions; -import rx.util.functions.Func1; + +import java.util.concurrent.atomic.AtomicInteger; /** * Returns an Observable that emits the first num items emitted by the source @@ -178,208 +161,4 @@ public void onNext(T args) { } } - - public static class UnitTest { - - @Test - public void testTake1() { - Observable w = Observable.from("one", "two", "three"); - Observable take = Observable.create(take(w, 2)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - take.subscribe(aObserver); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, times(1)).onNext("two"); - verify(aObserver, never()).onNext("three"); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testTake2() { - Observable w = Observable.from("one", "two", "three"); - Observable take = Observable.create(take(w, 1)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - take.subscribe(aObserver); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, never()).onNext("two"); - verify(aObserver, never()).onNext("three"); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test(expected = IllegalArgumentException.class) - public void testTakeWithError() { - Observable.from(1, 2, 3).take(1).map(new Func1() { - public Integer call(Integer t1) { - throw new IllegalArgumentException("some error"); - } - }).toBlockingObservable().single(); - } - - @Test - public void testTakeWithErrorHappeningInOnNext() { - Observable w = Observable.from(1, 2, 3).take(2).map(new Func1() { - public Integer call(Integer t1) { - throw new IllegalArgumentException("some error"); - } - }); - - @SuppressWarnings("unchecked") - Observer observer = mock(Observer.class); - w.subscribe(observer); - InOrder inOrder = inOrder(observer); - inOrder.verify(observer, times(1)).onError(any(IllegalArgumentException.class)); - inOrder.verifyNoMoreInteractions(); - } - - @Test - public void testTakeWithErrorHappeningInTheLastOnNext() { - Observable w = Observable.from(1, 2, 3).take(1).map(new Func1() { - public Integer call(Integer t1) { - throw new IllegalArgumentException("some error"); - } - }); - - @SuppressWarnings("unchecked") - Observer observer = mock(Observer.class); - w.subscribe(observer); - InOrder inOrder = inOrder(observer); - inOrder.verify(observer, times(1)).onError(any(IllegalArgumentException.class)); - inOrder.verifyNoMoreInteractions(); - } - - @Test - public void testTakeDoesntLeakErrors() { - Observable source = Observable.create(new OnSubscribeFunc() - { - @Override - public Subscription onSubscribe(Observer observer) - { - observer.onNext("one"); - observer.onError(new Throwable("test failed")); - return Subscriptions.empty(); - } - }); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - - Observable.create(take(source, 1)).subscribe(aObserver); - - verify(aObserver, times(1)).onNext("one"); - // even though onError is called we take(1) so shouldn't see it - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - verifyNoMoreInteractions(aObserver); - } - - @Test - public void testTakeZeroDoesntLeakError() { - final AtomicBoolean subscribed = new AtomicBoolean(false); - final AtomicBoolean unSubscribed = new AtomicBoolean(false); - Observable source = Observable.create(new OnSubscribeFunc() - { - @Override - public Subscription onSubscribe(Observer observer) - { - subscribed.set(true); - observer.onError(new Throwable("test failed")); - return new Subscription() - { - @Override - public void unsubscribe() - { - unSubscribed.set(true); - } - }; - } - }); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - - Observable.create(take(source, 0)).subscribe(aObserver); - assertTrue("source subscribed", subscribed.get()); - assertTrue("source unsubscribed", unSubscribed.get()); - - verify(aObserver, never()).onNext(anyString()); - // even though onError is called we take(0) so shouldn't see it - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - verifyNoMoreInteractions(aObserver); - } - - @Test - public void testUnsubscribeAfterTake() { - final Subscription s = mock(Subscription.class); - TestObservableFunc f = new TestObservableFunc(s, "one", "two", "three"); - Observable w = Observable.create(f); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - Observable take = Observable.create(take(w, 1)); - take.subscribe(aObserver); - - // wait for the Observable to complete - try { - f.t.join(); - } catch (Throwable e) { - e.printStackTrace(); - fail(e.getMessage()); - } - - System.out.println("TestObservable thread finished"); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, never()).onNext("two"); - verify(aObserver, never()).onNext("three"); - verify(aObserver, times(1)).onCompleted(); - verify(s, times(1)).unsubscribe(); - verifyNoMoreInteractions(aObserver); - } - - private static class TestObservableFunc implements OnSubscribeFunc { - - final Subscription s; - final String[] values; - Thread t = null; - - public TestObservableFunc(Subscription s, String... values) { - this.s = s; - this.values = values; - } - - @Override - public Subscription onSubscribe(final Observer observer) { - System.out.println("TestObservable subscribed to ..."); - t = new Thread(new Runnable() { - - @Override - public void run() { - try { - System.out.println("running TestObservable thread"); - for (String s : values) { - System.out.println("TestObservable onNext: " + s); - observer.onNext(s); - } - observer.onCompleted(); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - }); - System.out.println("starting TestObservable thread"); - t.start(); - System.out.println("done starting TestObservable thread"); - return s; - } - - } - - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationTakeLast.java b/rxjava-core/src/main/java/rx/operators/OperationTakeLast.java index e83f5dc432..d608552315 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationTakeLast.java +++ b/rxjava-core/src/main/java/rx/operators/OperationTakeLast.java @@ -15,25 +15,15 @@ */ package rx.operators; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.util.Deque; -import java.util.LinkedList; -import java.util.concurrent.locks.ReentrantLock; - -import org.junit.Test; -import org.mockito.InOrder; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; +import java.util.Deque; +import java.util.LinkedList; +import java.util.concurrent.locks.ReentrantLock; + /** * Returns an Observable that emits the last count items emitted by the source * Observable. @@ -129,93 +119,4 @@ public void onNext(T value) { } } - - public static class UnitTest { - - @Test - public void testTakeLastEmpty() { - Observable w = Observable.empty(); - Observable take = Observable.create(takeLast(w, 2)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - take.subscribe(aObserver); - verify(aObserver, never()).onNext(any(String.class)); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testTakeLast1() { - Observable w = Observable.from("one", "two", "three"); - Observable take = Observable.create(takeLast(w, 2)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - InOrder inOrder = inOrder(aObserver); - take.subscribe(aObserver); - inOrder.verify(aObserver, times(1)).onNext("two"); - inOrder.verify(aObserver, times(1)).onNext("three"); - verify(aObserver, never()).onNext("one"); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testTakeLast2() { - Observable w = Observable.from("one"); - Observable take = Observable.create(takeLast(w, 10)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - take.subscribe(aObserver); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testTakeLastWithZeroCount() { - Observable w = Observable.from("one"); - Observable take = Observable.create(takeLast(w, 0)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - take.subscribe(aObserver); - verify(aObserver, never()).onNext("one"); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testTakeLastWithNull() { - Observable w = Observable.from("one", null, "three"); - Observable take = Observable.create(takeLast(w, 2)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - take.subscribe(aObserver); - verify(aObserver, never()).onNext("one"); - verify(aObserver, times(1)).onNext(null); - verify(aObserver, times(1)).onNext("three"); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testTakeLastWithNegativeCount() { - Observable w = Observable.from("one"); - Observable take = Observable.create(takeLast(w, -1)); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - take.subscribe(aObserver); - verify(aObserver, never()).onNext("one"); - verify(aObserver, times(1)).onError( - any(IndexOutOfBoundsException.class)); - verify(aObserver, never()).onCompleted(); - } - - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationTakeUntil.java b/rxjava-core/src/main/java/rx/operators/OperationTakeUntil.java index 841190f023..4f344d72a1 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationTakeUntil.java +++ b/rxjava-core/src/main/java/rx/operators/OperationTakeUntil.java @@ -15,10 +15,6 @@ */ package rx.operators; -import static org.mockito.Mockito.*; - -import org.junit.Test; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; @@ -139,160 +135,4 @@ public void onNext(E args) { }); } } - - public static class UnitTest { - - @Test - @SuppressWarnings("unchecked") - public void testTakeUntil() { - Subscription sSource = mock(Subscription.class); - Subscription sOther = mock(Subscription.class); - TestObservable source = new TestObservable(sSource); - TestObservable other = new TestObservable(sOther); - - Observer result = mock(Observer.class); - Observable stringObservable = takeUntil(Observable.create(source), Observable.create(other)); - stringObservable.subscribe(result); - source.sendOnNext("one"); - source.sendOnNext("two"); - other.sendOnNext("three"); - source.sendOnNext("four"); - source.sendOnCompleted(); - other.sendOnCompleted(); - - verify(result, times(1)).onNext("one"); - verify(result, times(1)).onNext("two"); - verify(result, times(0)).onNext("three"); - verify(result, times(0)).onNext("four"); - verify(sSource, times(1)).unsubscribe(); - verify(sOther, times(1)).unsubscribe(); - - } - - @Test - @SuppressWarnings("unchecked") - public void testTakeUntilSourceCompleted() { - Subscription sSource = mock(Subscription.class); - Subscription sOther = mock(Subscription.class); - TestObservable source = new TestObservable(sSource); - TestObservable other = new TestObservable(sOther); - - Observer result = mock(Observer.class); - Observable stringObservable = takeUntil(Observable.create(source), Observable.create(other)); - stringObservable.subscribe(result); - source.sendOnNext("one"); - source.sendOnNext("two"); - source.sendOnCompleted(); - - verify(result, times(1)).onNext("one"); - verify(result, times(1)).onNext("two"); - verify(sSource, times(1)).unsubscribe(); - verify(sOther, times(1)).unsubscribe(); - - } - - @Test - @SuppressWarnings("unchecked") - public void testTakeUntilSourceError() { - Subscription sSource = mock(Subscription.class); - Subscription sOther = mock(Subscription.class); - TestObservable source = new TestObservable(sSource); - TestObservable other = new TestObservable(sOther); - Throwable error = new Throwable(); - - Observer result = mock(Observer.class); - Observable stringObservable = takeUntil(Observable.create(source), Observable.create(other)); - stringObservable.subscribe(result); - source.sendOnNext("one"); - source.sendOnNext("two"); - source.sendOnError(error); - - verify(result, times(1)).onNext("one"); - verify(result, times(1)).onNext("two"); - verify(result, times(1)).onError(error); - verify(sSource, times(1)).unsubscribe(); - verify(sOther, times(1)).unsubscribe(); - - } - - @Test - @SuppressWarnings("unchecked") - public void testTakeUntilOtherError() { - Subscription sSource = mock(Subscription.class); - Subscription sOther = mock(Subscription.class); - TestObservable source = new TestObservable(sSource); - TestObservable other = new TestObservable(sOther); - Throwable error = new Throwable(); - - Observer result = mock(Observer.class); - Observable stringObservable = takeUntil(Observable.create(source), Observable.create(other)); - stringObservable.subscribe(result); - source.sendOnNext("one"); - source.sendOnNext("two"); - other.sendOnError(error); - - verify(result, times(1)).onNext("one"); - verify(result, times(1)).onNext("two"); - verify(result, times(1)).onError(error); - verify(result, times(0)).onCompleted(); - verify(sSource, times(1)).unsubscribe(); - verify(sOther, times(1)).unsubscribe(); - - } - - @Test - @SuppressWarnings("unchecked") - public void testTakeUntilOtherCompleted() { - Subscription sSource = mock(Subscription.class); - Subscription sOther = mock(Subscription.class); - TestObservable source = new TestObservable(sSource); - TestObservable other = new TestObservable(sOther); - - Observer result = mock(Observer.class); - Observable stringObservable = takeUntil(Observable.create(source), Observable.create(other)); - stringObservable.subscribe(result); - source.sendOnNext("one"); - source.sendOnNext("two"); - other.sendOnCompleted(); - - verify(result, times(1)).onNext("one"); - verify(result, times(1)).onNext("two"); - verify(result, times(0)).onCompleted(); - verify(sSource, times(0)).unsubscribe(); - verify(sOther, times(0)).unsubscribe(); - - } - - private static class TestObservable implements OnSubscribeFunc { - - Observer observer = null; - Subscription s; - - public TestObservable(Subscription s) { - this.s = s; - } - - /* used to simulate subscription */ - public void sendOnCompleted() { - observer.onCompleted(); - } - - /* used to simulate subscription */ - public void sendOnNext(String value) { - observer.onNext(value); - } - - /* used to simulate subscription */ - public void sendOnError(Throwable e) { - observer.onError(e); - } - - @Override - public Subscription onSubscribe(final Observer observer) { - this.observer = observer; - return s; - } - } - - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationTakeWhile.java b/rxjava-core/src/main/java/rx/operators/OperationTakeWhile.java index 5b833b22a1..b56029bcae 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationTakeWhile.java +++ b/rxjava-core/src/main/java/rx/operators/OperationTakeWhile.java @@ -15,24 +15,15 @@ */ package rx.operators; -import static org.junit.Assert.*; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.concurrent.atomic.AtomicInteger; - -import org.junit.Test; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; -import rx.subjects.PublishSubject; -import rx.subjects.Subject; -import rx.subscriptions.Subscriptions; import rx.util.functions.Func1; import rx.util.functions.Func2; +import java.util.concurrent.atomic.AtomicInteger; + /** * Returns an Observable that emits items emitted by the source Observable as long as a specified * condition is true. @@ -151,207 +142,4 @@ public void onNext(T args) { } } - - public static class UnitTest { - - @Test - public void testTakeWhile1() { - Observable w = Observable.from(1, 2, 3); - Observable take = Observable.create(takeWhile(w, new Func1() - { - @Override - public Boolean call(Integer input) - { - return input < 3; - } - })); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - take.subscribe(aObserver); - verify(aObserver, times(1)).onNext(1); - verify(aObserver, times(1)).onNext(2); - verify(aObserver, never()).onNext(3); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testTakeWhileOnSubject1() { - Subject s = PublishSubject.create(); - Observable take = Observable.create(takeWhile(s, new Func1() - { - @Override - public Boolean call(Integer input) - { - return input < 3; - } - })); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - take.subscribe(aObserver); - - s.onNext(1); - s.onNext(2); - s.onNext(3); - s.onNext(4); - s.onNext(5); - s.onCompleted(); - - verify(aObserver, times(1)).onNext(1); - verify(aObserver, times(1)).onNext(2); - verify(aObserver, never()).onNext(3); - verify(aObserver, never()).onNext(4); - verify(aObserver, never()).onNext(5); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testTakeWhile2() { - Observable w = Observable.from("one", "two", "three"); - Observable take = Observable.create(takeWhileWithIndex(w, new Func2() - { - @Override - public Boolean call(String input, Integer index) - { - return index < 2; - } - })); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - take.subscribe(aObserver); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, times(1)).onNext("two"); - verify(aObserver, never()).onNext("three"); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testTakeWhileDoesntLeakErrors() { - Observable source = Observable.create(new OnSubscribeFunc() - { - @Override - public Subscription onSubscribe(Observer observer) - { - observer.onNext("one"); - observer.onError(new Throwable("test failed")); - return Subscriptions.empty(); - } - }); - - Observable.create(takeWhile(source, new Func1() - { - @Override - public Boolean call(String s) - { - return false; - } - })).toBlockingObservable().last(); - } - - @Test - public void testTakeWhileProtectsPredicateCall() { - TestObservable source = new TestObservable(mock(Subscription.class), "one"); - final RuntimeException testException = new RuntimeException("test exception"); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - Observable take = Observable.create(takeWhile(Observable.create(source), new Func1() - { - @Override - public Boolean call(String s) - { - throw testException; - } - })); - take.subscribe(aObserver); - - // wait for the Observable to complete - try { - source.t.join(); - } catch (Throwable e) { - e.printStackTrace(); - fail(e.getMessage()); - } - - verify(aObserver, never()).onNext(any(String.class)); - verify(aObserver, times(1)).onError(testException); - } - - @Test - public void testUnsubscribeAfterTake() { - Subscription s = mock(Subscription.class); - TestObservable w = new TestObservable(s, "one", "two", "three"); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - Observable take = Observable.create(takeWhileWithIndex(Observable.create(w), new Func2() - { - @Override - public Boolean call(String s, Integer index) - { - return index < 1; - } - })); - take.subscribe(aObserver); - - // wait for the Observable to complete - try { - w.t.join(); - } catch (Throwable e) { - e.printStackTrace(); - fail(e.getMessage()); - } - - System.out.println("TestObservable thread finished"); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, never()).onNext("two"); - verify(aObserver, never()).onNext("three"); - verify(s, times(1)).unsubscribe(); - } - - private static class TestObservable implements OnSubscribeFunc { - - final Subscription s; - final String[] values; - Thread t = null; - - public TestObservable(Subscription s, String... values) { - this.s = s; - this.values = values; - } - - @Override - public Subscription onSubscribe(final Observer observer) { - System.out.println("TestObservable subscribed to ..."); - t = new Thread(new Runnable() { - - @Override - public void run() { - try { - System.out.println("running TestObservable thread"); - for (String s : values) { - System.out.println("TestObservable onNext: " + s); - observer.onNext(s); - } - observer.onCompleted(); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - }); - System.out.println("starting TestObservable thread"); - t.start(); - System.out.println("done starting TestObservable thread"); - return s; - } - - } - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationThrottleFirst.java b/rxjava-core/src/main/java/rx/operators/OperationThrottleFirst.java index 4c3a1ea8d4..ebc6bf55d9 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationThrottleFirst.java +++ b/rxjava-core/src/main/java/rx/operators/OperationThrottleFirst.java @@ -15,27 +15,17 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.InOrder; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Scheduler; import rx.Subscription; import rx.concurrency.Schedulers; -import rx.concurrency.TestScheduler; -import rx.subscriptions.Subscriptions; -import rx.util.functions.Action0; import rx.util.functions.Func1; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + /** * Throttle by windowing a stream and returning the first value in each window. */ @@ -94,104 +84,4 @@ public Boolean call(T value) { } }; } - - public static class UnitTest { - - private TestScheduler scheduler; - private Observer observer; - - @Before - @SuppressWarnings("unchecked") - public void before() { - scheduler = new TestScheduler(); - observer = mock(Observer.class); - } - - @Test - public void testThrottlingWithCompleted() { - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - publishNext(observer, 100, "one"); // publish as it's first - publishNext(observer, 300, "two"); // skip as it's last within the first 400 - publishNext(observer, 900, "three"); // publish - publishNext(observer, 905, "four"); // skip - publishCompleted(observer, 1000); // Should be published as soon as the timeout expires. - - return Subscriptions.empty(); - } - }); - - Observable sampled = Observable.create(OperationThrottleFirst.throttleFirst(source, 400, TimeUnit.MILLISECONDS, scheduler)); - sampled.subscribe(observer); - - InOrder inOrder = inOrder(observer); - - scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS); - inOrder.verify(observer, times(1)).onNext("one"); - inOrder.verify(observer, times(0)).onNext("two"); - inOrder.verify(observer, times(1)).onNext("three"); - inOrder.verify(observer, times(0)).onNext("four"); - inOrder.verify(observer, times(1)).onCompleted(); - inOrder.verifyNoMoreInteractions(); - } - - @Test - public void testThrottlingWithError() { - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - Exception error = new TestException(); - publishNext(observer, 100, "one"); // Should be published since it is first - publishNext(observer, 200, "two"); // Should be skipped since onError will arrive before the timeout expires - publishError(observer, 300, error); // Should be published as soon as the timeout expires. - - return Subscriptions.empty(); - } - }); - - Observable sampled = Observable.create(OperationThrottleFirst.throttleFirst(source, 400, TimeUnit.MILLISECONDS, scheduler)); - sampled.subscribe(observer); - - InOrder inOrder = inOrder(observer); - - scheduler.advanceTimeTo(400, TimeUnit.MILLISECONDS); - inOrder.verify(observer).onNext("one"); - inOrder.verify(observer).onError(any(TestException.class)); - inOrder.verifyNoMoreInteractions(); - } - - private void publishCompleted(final Observer observer, long delay) { - scheduler.schedule(new Action0() { - @Override - public void call() { - observer.onCompleted(); - } - }, delay, TimeUnit.MILLISECONDS); - } - - private void publishError(final Observer observer, long delay, final Exception error) { - scheduler.schedule(new Action0() { - @Override - public void call() { - observer.onError(error); - } - }, delay, TimeUnit.MILLISECONDS); - } - - private void publishNext(final Observer observer, long delay, final T value) { - scheduler.schedule(new Action0() { - @Override - public void call() { - observer.onNext(value); - } - }, delay, TimeUnit.MILLISECONDS); - } - - @SuppressWarnings("serial") - private class TestException extends Exception { - } - - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationTimeInterval.java b/rxjava-core/src/main/java/rx/operators/OperationTimeInterval.java index 7b70818bc1..874cb9dd39 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationTimeInterval.java +++ b/rxjava-core/src/main/java/rx/operators/OperationTimeInterval.java @@ -15,25 +15,12 @@ */ package rx.operators; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.times; - -import java.util.concurrent.TimeUnit; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Scheduler; import rx.Subscription; import rx.concurrency.Schedulers; -import rx.concurrency.TestScheduler; -import rx.subjects.PublishSubject; import rx.util.TimeInterval; /** @@ -93,48 +80,4 @@ public void onError(Throwable e) { observer.onCompleted(); } } - - public static class UnitTest { - - private static final TimeUnit TIME_UNIT = TimeUnit.MILLISECONDS; - - @Mock - private Observer> observer; - - private TestScheduler testScheduler; - private PublishSubject subject; - private Observable> observable; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - testScheduler = new TestScheduler(); - subject = PublishSubject.create(); - observable = subject.timeInterval(testScheduler); - } - - @Test - public void testTimeInterval() { - InOrder inOrder = inOrder(observer); - observable.subscribe(observer); - - testScheduler.advanceTimeBy(1000, TIME_UNIT); - subject.onNext(1); - testScheduler.advanceTimeBy(2000, TIME_UNIT); - subject.onNext(2); - testScheduler.advanceTimeBy(3000, TIME_UNIT); - subject.onNext(3); - subject.onCompleted(); - - inOrder.verify(observer, times(1)).onNext( - new TimeInterval(1000, 1)); - inOrder.verify(observer, times(1)).onNext( - new TimeInterval(2000, 2)); - inOrder.verify(observer, times(1)).onNext( - new TimeInterval(3000, 3)); - inOrder.verify(observer, times(1)).onCompleted(); - inOrder.verifyNoMoreInteractions(); - } - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperationToObservableFuture.java b/rxjava-core/src/main/java/rx/operators/OperationToObservableFuture.java index 958aa9ad3f..af2f0b1a3f 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationToObservableFuture.java +++ b/rxjava-core/src/main/java/rx/operators/OperationToObservableFuture.java @@ -15,18 +15,14 @@ */ package rx.operators; -import static org.mockito.Mockito.*; - -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import org.junit.Test; - import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; import rx.subscriptions.Subscriptions; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + /** * Converts a Future into an Observable. *

@@ -39,7 +35,7 @@ * Observable.subscribe(Observer) does nothing. */ public class OperationToObservableFuture { - private static class ToObservableFuture implements OnSubscribeFunc { + static class ToObservableFuture implements OnSubscribeFunc { private final Future that; private final Long time; private final TimeUnit unit; @@ -82,41 +78,4 @@ public static OnSubscribeFunc toObservableFuture(final Future OnSubscribeFunc toObservableFuture(final Future that, long time, TimeUnit unit) { return new ToObservableFuture(that, time, unit); } - - @SuppressWarnings("unchecked") - public static class UnitTest { - @Test - public void testSuccess() throws Exception { - Future future = mock(Future.class); - Object value = new Object(); - when(future.get()).thenReturn(value); - ToObservableFuture ob = new ToObservableFuture(future); - Observer o = mock(Observer.class); - - Subscription sub = ob.onSubscribe(o); - sub.unsubscribe(); - - verify(o, times(1)).onNext(value); - verify(o, times(1)).onCompleted(); - verify(o, never()).onError(null); - verify(future, never()).cancel(true); - } - - @Test - public void testFailure() throws Exception { - Future future = mock(Future.class); - RuntimeException e = new RuntimeException(); - when(future.get()).thenThrow(e); - ToObservableFuture ob = new ToObservableFuture(future); - Observer o = mock(Observer.class); - - Subscription sub = ob.onSubscribe(o); - sub.unsubscribe(); - - verify(o, never()).onNext(null); - verify(o, never()).onCompleted(); - verify(o, times(1)).onError(e); - verify(future, never()).cancel(true); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationToObservableIterable.java b/rxjava-core/src/main/java/rx/operators/OperationToObservableIterable.java index bebc31550a..a8a970bdd8 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationToObservableIterable.java +++ b/rxjava-core/src/main/java/rx/operators/OperationToObservableIterable.java @@ -15,15 +15,6 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.Arrays; - -import org.junit.Test; -import org.mockito.Mockito; - -import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; @@ -59,21 +50,4 @@ public Subscription onSubscribe(Observer observer) { return Subscriptions.empty(); } } - - public static class UnitTest { - - @Test - public void testIterable() { - Observable observable = Observable.create(toObservableIterable(Arrays. asList("one", "two", "three"))); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, times(1)).onNext("two"); - verify(aObserver, times(1)).onNext("three"); - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationToObservableList.java b/rxjava-core/src/main/java/rx/operators/OperationToObservableList.java index f6bc080211..c798cf8cc1 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationToObservableList.java +++ b/rxjava-core/src/main/java/rx/operators/OperationToObservableList.java @@ -15,22 +15,15 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.ConcurrentLinkedQueue; - -import org.junit.Test; -import org.mockito.Mockito; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; + /** * Returns an Observable that emits a single item, a list composed of all the items emitted by the * source Observable. @@ -93,44 +86,4 @@ public void onCompleted() { }); } } - - public static class UnitTest { - - @Test - public void testList() { - Observable w = Observable.from("one", "two", "three"); - Observable> observable = Observable.create(toObservableList(w)); - - @SuppressWarnings("unchecked") - Observer> aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, times(1)).onNext(Arrays.asList("one", "two", "three")); - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testListMultipleObservers() { - Observable w = Observable.from("one", "two", "three"); - Observable> observable = Observable.create(toObservableList(w)); - - @SuppressWarnings("unchecked") - Observer> o1 = mock(Observer.class); - observable.subscribe(o1); - - @SuppressWarnings("unchecked") - Observer> o2 = mock(Observer.class); - observable.subscribe(o2); - - List expected = Arrays.asList("one", "two", "three"); - - verify(o1, times(1)).onNext(expected); - verify(o1, Mockito.never()).onError(any(Throwable.class)); - verify(o1, times(1)).onCompleted(); - - verify(o2, times(1)).onNext(expected); - verify(o2, Mockito.never()).onError(any(Throwable.class)); - verify(o2, times(1)).onCompleted(); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationToObservableSortedList.java b/rxjava-core/src/main/java/rx/operators/OperationToObservableSortedList.java index 655f833a5d..cf3ffac636 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationToObservableSortedList.java +++ b/rxjava-core/src/main/java/rx/operators/OperationToObservableSortedList.java @@ -15,25 +15,18 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; +import rx.Observable; +import rx.Observable.OnSubscribeFunc; +import rx.Observer; +import rx.Subscription; +import rx.util.functions.Func2; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; -import org.junit.Test; -import org.mockito.Mockito; - -import rx.Observable; -import rx.Observable.OnSubscribeFunc; -import rx.Observer; -import rx.Subscription; -import rx.util.functions.Func2; - /** * Return an Observable that emits the items emitted by the source Observable, in a sorted order * (each item emitted by the Observable must implement Comparable with respect to all other items @@ -142,41 +135,4 @@ public Integer call(Object t1, Object t2) { } } - - public static class UnitTest { - - @Test - public void testSortedList() { - Observable w = Observable.from(1, 3, 2, 5, 4); - Observable> observable = Observable.create(toSortedList(w)); - - @SuppressWarnings("unchecked") - Observer> aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, times(1)).onNext(Arrays.asList(1, 2, 3, 4, 5)); - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testSortedListWithCustomFunction() { - Observable w = Observable.from(1, 3, 2, 5, 4); - Observable> observable = Observable.create(toSortedList(w, new Func2() { - - @Override - public Integer call(Integer t1, Integer t2) { - return t2 - t1; - } - - })); - - @SuppressWarnings("unchecked") - Observer> aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, times(1)).onNext(Arrays.asList(5, 4, 3, 2, 1)); - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationWindow.java b/rxjava-core/src/main/java/rx/operators/OperationWindow.java index 5cffda9661..61d1839f32 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationWindow.java +++ b/rxjava-core/src/main/java/rx/operators/OperationWindow.java @@ -15,32 +15,19 @@ */ package rx.operators; -import static org.junit.Assert.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import org.junit.Before; -import org.junit.Test; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Scheduler; import rx.Subscription; import rx.concurrency.Schedulers; -import rx.concurrency.TestScheduler; -import rx.subscriptions.Subscriptions; import rx.util.Closing; -import rx.util.Closings; import rx.util.Opening; -import rx.util.Openings; -import rx.util.functions.Action0; -import rx.util.functions.Action1; import rx.util.functions.Func0; import rx.util.functions.Func1; +import java.util.concurrent.TimeUnit; + public final class OperationWindow extends ChunkedOperation { public static Func0> windowMaker() { @@ -369,295 +356,4 @@ public Observable getContents() { return Observable.from(contents); } } - - public static class UnitTest { - - private TestScheduler scheduler; - - @Before - public void before() { - scheduler = new TestScheduler(); - } - - private static List> toLists(Observable> observable) { - final List list = new ArrayList(); - final List> lists = new ArrayList>(); - - observable.subscribe(new Action1>() { - @Override - public void call(Observable tObservable) { - tObservable.subscribe(new Action1() { - @Override - public void call(T t) { - list.add(t); - } - }); - lists.add(new ArrayList(list)); - list.clear(); - } - }); - return lists; - } - - @Test - public void testNonOverlappingWindows() { - Observable subject = Observable.from("one", "two", "three", "four", "five"); - Observable> windowed = Observable.create(window(subject, 3)); - - List> windows = toLists(windowed); - - assertEquals(2, windows.size()); - assertEquals(list("one", "two", "three"), windows.get(0)); - assertEquals(list("four", "five"), windows.get(1)); - } - - @Test - public void testSkipAndCountGaplessEindows() { - Observable subject = Observable.from("one", "two", "three", "four", "five"); - Observable> windowed = Observable.create(window(subject, 3, 3)); - - List> windows = toLists(windowed); - - assertEquals(2, windows.size()); - assertEquals(list("one", "two", "three"), windows.get(0)); - assertEquals(list("four", "five"), windows.get(1)); - } - - @Test - public void testOverlappingWindows() { - Observable subject = Observable.from("zero", "one", "two", "three", "four", "five"); - Observable> windowed = Observable.create(window(subject, 3, 1)); - - List> windows = toLists(windowed); - - assertEquals(6, windows.size()); - assertEquals(list("zero", "one", "two"), windows.get(0)); - assertEquals(list("one", "two", "three"), windows.get(1)); - assertEquals(list("two", "three", "four"), windows.get(2)); - assertEquals(list("three", "four", "five"), windows.get(3)); - assertEquals(list("four", "five"), windows.get(4)); - assertEquals(list("five"), windows.get(5)); - } - - @Test - public void testSkipAndCountWindowsWithGaps() { - Observable subject = Observable.from("one", "two", "three", "four", "five"); - Observable> windowed = Observable.create(window(subject, 2, 3)); - - List> windows = toLists(windowed); - - assertEquals(2, windows.size()); - assertEquals(list("one", "two"), windows.get(0)); - assertEquals(list("four", "five"), windows.get(1)); - } - - @Test - public void testTimedAndCount() { - final List list = new ArrayList(); - final List> lists = new ArrayList>(); - - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - push(observer, "one", 10); - push(observer, "two", 90); - push(observer, "three", 110); - push(observer, "four", 190); - push(observer, "five", 210); - complete(observer, 250); - return Subscriptions.empty(); - } - }); - - Observable> windowed = Observable.create(window(source, 100, TimeUnit.MILLISECONDS, 2, scheduler)); - windowed.subscribe(observeWindow(list, lists)); - - scheduler.advanceTimeTo(100, TimeUnit.MILLISECONDS); - assertEquals(1, lists.size()); - assertEquals(lists.get(0), list("one", "two")); - - scheduler.advanceTimeTo(200, TimeUnit.MILLISECONDS); - assertEquals(2, lists.size()); - assertEquals(lists.get(1), list("three", "four")); - - scheduler.advanceTimeTo(300, TimeUnit.MILLISECONDS); - assertEquals(3, lists.size()); - assertEquals(lists.get(2), list("five")); - } - - @Test - public void testTimed() { - final List list = new ArrayList(); - final List> lists = new ArrayList>(); - - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - push(observer, "one", 98); - push(observer, "two", 99); - push(observer, "three", 100); - push(observer, "four", 101); - push(observer, "five", 102); - complete(observer, 150); - return Subscriptions.empty(); - } - }); - - Observable> windowed = Observable.create(window(source, 100, TimeUnit.MILLISECONDS, scheduler)); - windowed.subscribe(observeWindow(list, lists)); - - scheduler.advanceTimeTo(101, TimeUnit.MILLISECONDS); - assertEquals(1, lists.size()); - assertEquals(lists.get(0), list("one", "two", "three")); - - scheduler.advanceTimeTo(201, TimeUnit.MILLISECONDS); - assertEquals(2, lists.size()); - assertEquals(lists.get(1), list("four", "five")); - } - - @Test - public void testObservableBasedOpenerAndCloser() { - final List list = new ArrayList(); - final List> lists = new ArrayList>(); - - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - push(observer, "one", 10); - push(observer, "two", 60); - push(observer, "three", 110); - push(observer, "four", 160); - push(observer, "five", 210); - complete(observer, 500); - return Subscriptions.empty(); - } - }); - - Observable openings = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - push(observer, Openings.create(), 50); - push(observer, Openings.create(), 200); - complete(observer, 250); - return Subscriptions.empty(); - } - }); - - Func1> closer = new Func1>() { - @Override - public Observable call(Opening opening) { - return Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - push(observer, Closings.create(), 100); - complete(observer, 101); - return Subscriptions.empty(); - } - }); - } - }; - - Observable> windowed = Observable.create(window(source, openings, closer)); - windowed.subscribe(observeWindow(list, lists)); - - scheduler.advanceTimeTo(500, TimeUnit.MILLISECONDS); - assertEquals(2, lists.size()); - assertEquals(lists.get(0), list("two", "three")); - assertEquals(lists.get(1), list("five")); - } - - @Test - public void testObservableBasedCloser() { - final List list = new ArrayList(); - final List> lists = new ArrayList>(); - - Observable source = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - push(observer, "one", 10); - push(observer, "two", 60); - push(observer, "three", 110); - push(observer, "four", 160); - push(observer, "five", 210); - complete(observer, 250); - return Subscriptions.empty(); - } - }); - - Func0> closer = new Func0>() { - @Override - public Observable call() { - return Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(Observer observer) { - push(observer, Closings.create(), 100); - complete(observer, 101); - return Subscriptions.empty(); - } - }); - } - }; - - Observable> windowed = Observable.create(window(source, closer)); - windowed.subscribe(observeWindow(list, lists)); - - scheduler.advanceTimeTo(500, TimeUnit.MILLISECONDS); - assertEquals(3, lists.size()); - assertEquals(lists.get(0), list("one", "two")); - assertEquals(lists.get(1), list("three", "four")); - assertEquals(lists.get(2), list("five")); - } - - private List list(String... args) { - List list = new ArrayList(); - for (String arg : args) { - list.add(arg); - } - return list; - } - - private void push(final Observer observer, final T value, int delay) { - scheduler.schedule(new Action0() { - @Override - public void call() { - observer.onNext(value); - } - }, delay, TimeUnit.MILLISECONDS); - } - - private void complete(final Observer observer, int delay) { - scheduler.schedule(new Action0() { - @Override - public void call() { - observer.onCompleted(); - } - }, delay, TimeUnit.MILLISECONDS); - } - - private Action1> observeWindow(final List list, final List> lists) { - return new Action1>() { - @Override - public void call(Observable stringObservable) { - stringObservable.subscribe(new Observer() { - @Override - public void onCompleted() { - lists.add(new ArrayList(list)); - list.clear(); - } - - @Override - public void onError(Throwable e) { - fail(e.getMessage()); - } - - @Override - public void onNext(String args) { - list.add(args); - } - }); - } - }; - } - - } } diff --git a/rxjava-core/src/main/java/rx/operators/OperationZip.java b/rxjava-core/src/main/java/rx/operators/OperationZip.java index 517a1faecc..eb07f87738 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationZip.java +++ b/rxjava-core/src/main/java/rx/operators/OperationZip.java @@ -15,33 +15,15 @@ */ package rx.operators; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.Arrays; -import java.util.Collection; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.junit.Test; -import org.mockito.InOrder; - import rx.Observable; import rx.Observable.OnSubscribeFunc; import rx.Observer; import rx.Subscription; -import rx.subscriptions.Subscriptions; -import rx.util.functions.Func2; -import rx.util.functions.Func3; -import rx.util.functions.Func4; -import rx.util.functions.Func5; -import rx.util.functions.Func6; -import rx.util.functions.Func7; -import rx.util.functions.Func8; -import rx.util.functions.Func9; -import rx.util.functions.FuncN; -import rx.util.functions.Functions; +import rx.util.functions.*; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicBoolean; /** * Returns an Observable that emits the results of a function applied to sets of items emitted, in @@ -159,7 +141,7 @@ public static OnSubscribeFunc zip(Iterable> ws, F /* * ThreadSafe */ - private static class ZipObserver implements Observer { + static class ZipObserver implements Observer { final Observable w; final Aggregator a; private final SafeObservableSubscription subscription = new SafeObservableSubscription(); @@ -204,7 +186,7 @@ public void onNext(T args) { * * @param */ - private static class Aggregator implements OnSubscribeFunc { + static class Aggregator implements OnSubscribeFunc { private volatile SynchronizedObserver observer; private final FuncN zipFunction; @@ -228,7 +210,7 @@ public Aggregator(FuncN zipFunction) { * * @param w */ - private void addObserver(ZipObserver w) { + void addObserver(ZipObserver w) { // initialize this ZipObserver observers.add(w); receivedValuesPerObserver.put(w, new ConcurrentLinkedQueue()); @@ -361,566 +343,4 @@ private void stop() { } } - - public static class UnitTest { - - @SuppressWarnings("unchecked") - @Test - public void testCollectionSizeDifferentThanFunction() { - FuncN zipr = Functions.fromFunc(getConcatStringIntegerIntArrayZipr()); - //Func3 - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - - @SuppressWarnings("rawtypes") - Collection ws = java.util.Collections.singleton(Observable.from("one", "two")); - Observable w = Observable.create(zip(ws, zipr)); - w.subscribe(aObserver); - - verify(aObserver, times(1)).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - verify(aObserver, never()).onNext(any(String.class)); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testZippingDifferentLengthObservableSequences1() { - Observer w = mock(Observer.class); - - TestObservable w1 = new TestObservable(); - TestObservable w2 = new TestObservable(); - TestObservable w3 = new TestObservable(); - - Observable zipW = Observable.create(zip(Observable.create(w1), Observable.create(w2), Observable.create(w3), getConcat3StringsZipr())); - zipW.subscribe(w); - - /* simulate sending data */ - // once for w1 - w1.observer.onNext("1a"); - w1.observer.onCompleted(); - // twice for w2 - w2.observer.onNext("2a"); - w2.observer.onNext("2b"); - w2.observer.onCompleted(); - // 4 times for w3 - w3.observer.onNext("3a"); - w3.observer.onNext("3b"); - w3.observer.onNext("3c"); - w3.observer.onNext("3d"); - w3.observer.onCompleted(); - - /* we should have been called 1 time on the Observer */ - InOrder inOrder = inOrder(w); - inOrder.verify(w).onNext("1a2a3a"); - - inOrder.verify(w, times(1)).onCompleted(); - } - - @Test - public void testZippingDifferentLengthObservableSequences2() { - @SuppressWarnings("unchecked") - Observer w = mock(Observer.class); - - TestObservable w1 = new TestObservable(); - TestObservable w2 = new TestObservable(); - TestObservable w3 = new TestObservable(); - - Observable zipW = Observable.create(zip(Observable.create(w1), Observable.create(w2), Observable.create(w3), getConcat3StringsZipr())); - zipW.subscribe(w); - - /* simulate sending data */ - // 4 times for w1 - w1.observer.onNext("1a"); - w1.observer.onNext("1b"); - w1.observer.onNext("1c"); - w1.observer.onNext("1d"); - w1.observer.onCompleted(); - // twice for w2 - w2.observer.onNext("2a"); - w2.observer.onNext("2b"); - w2.observer.onCompleted(); - // 1 times for w3 - w3.observer.onNext("3a"); - w3.observer.onCompleted(); - - /* we should have been called 1 time on the Observer */ - InOrder inOrder = inOrder(w); - inOrder.verify(w).onNext("1a2a3a"); - - inOrder.verify(w, times(1)).onCompleted(); - - } - - /** - * Testing internal private logic due to the complexity so I want to use TDD to test as a I build it rather than relying purely on the overall functionality expected by the public methods. - */ - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testAggregatorSimple() { - FuncN zipr = getConcatZipr(); - /* create the aggregator which will execute the zip function when all Observables provide values */ - Aggregator a = new Aggregator(zipr); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - a.onSubscribe(aObserver); - - /* mock the Observable Observers that are 'pushing' data for us */ - ZipObserver r1 = mock(ZipObserver.class); - ZipObserver r2 = mock(ZipObserver.class); - - /* pretend we're starting up */ - a.addObserver(r1); - a.addObserver(r2); - - /* simulate the Observables pushing data into the aggregator */ - a.next(r1, "hello"); - a.next(r2, "world"); - - InOrder inOrder = inOrder(aObserver); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - inOrder.verify(aObserver, times(1)).onNext("helloworld"); - - a.next(r1, "hello "); - a.next(r2, "again"); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - inOrder.verify(aObserver, times(1)).onNext("hello again"); - - a.complete(r1); - a.complete(r2); - - inOrder.verify(aObserver, never()).onNext(anyString()); - verify(aObserver, times(1)).onCompleted(); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testAggregatorDifferentSizedResultsWithOnComplete() { - FuncN zipr = getConcatZipr(); - /* create the aggregator which will execute the zip function when all Observables provide values */ - Aggregator a = new Aggregator(zipr); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - a.onSubscribe(aObserver); - - /* mock the Observable Observers that are 'pushing' data for us */ - ZipObserver r1 = mock(ZipObserver.class); - ZipObserver r2 = mock(ZipObserver.class); - - /* pretend we're starting up */ - a.addObserver(r1); - a.addObserver(r2); - - /* simulate the Observables pushing data into the aggregator */ - a.next(r1, "hello"); - a.next(r2, "world"); - a.complete(r2); - - InOrder inOrder = inOrder(aObserver); - - inOrder.verify(aObserver, never()).onError(any(Throwable.class)); - inOrder.verify(aObserver, never()).onCompleted(); - inOrder.verify(aObserver, times(1)).onNext("helloworld"); - - a.next(r1, "hi"); - a.complete(r1); - - inOrder.verify(aObserver, never()).onError(any(Throwable.class)); - inOrder.verify(aObserver, times(1)).onCompleted(); - inOrder.verify(aObserver, never()).onNext(anyString()); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testAggregateMultipleTypes() { - FuncN zipr = getConcatZipr(); - /* create the aggregator which will execute the zip function when all Observables provide values */ - Aggregator a = new Aggregator(zipr); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - a.onSubscribe(aObserver); - - /* mock the Observable Observers that are 'pushing' data for us */ - ZipObserver r1 = mock(ZipObserver.class); - ZipObserver r2 = mock(ZipObserver.class); - - /* pretend we're starting up */ - a.addObserver(r1); - a.addObserver(r2); - - /* simulate the Observables pushing data into the aggregator */ - a.next(r1, "hello"); - a.next(r2, "world"); - a.complete(r2); - - InOrder inOrder = inOrder(aObserver); - - inOrder.verify(aObserver, never()).onError(any(Throwable.class)); - inOrder.verify(aObserver, never()).onCompleted(); - inOrder.verify(aObserver, times(1)).onNext("helloworld"); - - a.next(r1, "hi"); - a.complete(r1); - - inOrder.verify(aObserver, never()).onError(any(Throwable.class)); - inOrder.verify(aObserver, times(1)).onCompleted(); - inOrder.verify(aObserver, never()).onNext(anyString()); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testAggregate3Types() { - FuncN zipr = getConcatZipr(); - /* create the aggregator which will execute the zip function when all Observables provide values */ - Aggregator a = new Aggregator(zipr); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - a.onSubscribe(aObserver); - - /* mock the Observable Observers that are 'pushing' data for us */ - ZipObserver r1 = mock(ZipObserver.class); - ZipObserver r2 = mock(ZipObserver.class); - ZipObserver r3 = mock(ZipObserver.class); - - /* pretend we're starting up */ - a.addObserver(r1); - a.addObserver(r2); - a.addObserver(r3); - - /* simulate the Observables pushing data into the aggregator */ - a.next(r1, "hello"); - a.next(r2, 2); - a.next(r3, new int[] { 5, 6, 7 }); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - verify(aObserver, times(1)).onNext("hello2[5, 6, 7]"); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testAggregatorsWithDifferentSizesAndTiming() { - FuncN zipr = getConcatZipr(); - /* create the aggregator which will execute the zip function when all Observables provide values */ - Aggregator a = new Aggregator(zipr); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - a.onSubscribe(aObserver); - - /* mock the Observable Observers that are 'pushing' data for us */ - ZipObserver r1 = mock(ZipObserver.class); - ZipObserver r2 = mock(ZipObserver.class); - - /* pretend we're starting up */ - a.addObserver(r1); - a.addObserver(r2); - - /* simulate the Observables pushing data into the aggregator */ - a.next(r1, "one"); - a.next(r1, "two"); - a.next(r1, "three"); - a.next(r2, "A"); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - verify(aObserver, times(1)).onNext("oneA"); - - a.next(r1, "four"); - a.complete(r1); - a.next(r2, "B"); - verify(aObserver, times(1)).onNext("twoB"); - a.next(r2, "C"); - verify(aObserver, times(1)).onNext("threeC"); - a.next(r2, "D"); - verify(aObserver, times(1)).onNext("fourD"); - a.next(r2, "E"); - verify(aObserver, never()).onNext("E"); - a.complete(r2); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testAggregatorError() { - FuncN zipr = getConcatZipr(); - /* create the aggregator which will execute the zip function when all Observables provide values */ - Aggregator a = new Aggregator(zipr); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - a.onSubscribe(aObserver); - - /* mock the Observable Observers that are 'pushing' data for us */ - ZipObserver r1 = mock(ZipObserver.class); - ZipObserver r2 = mock(ZipObserver.class); - - /* pretend we're starting up */ - a.addObserver(r1); - a.addObserver(r2); - - /* simulate the Observables pushing data into the aggregator */ - a.next(r1, "hello"); - a.next(r2, "world"); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - verify(aObserver, times(1)).onNext("helloworld"); - - a.error(r1, new RuntimeException("")); - a.next(r1, "hello"); - a.next(r2, "again"); - - verify(aObserver, times(1)).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - // we don't want to be called again after an error - verify(aObserver, times(0)).onNext("helloagain"); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testAggregatorUnsubscribe() { - FuncN zipr = getConcatZipr(); - /* create the aggregator which will execute the zip function when all Observables provide values */ - Aggregator a = new Aggregator(zipr); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - Subscription subscription = a.onSubscribe(aObserver); - - /* mock the Observable Observers that are 'pushing' data for us */ - ZipObserver r1 = mock(ZipObserver.class); - ZipObserver r2 = mock(ZipObserver.class); - - /* pretend we're starting up */ - a.addObserver(r1); - a.addObserver(r2); - - /* simulate the Observables pushing data into the aggregator */ - a.next(r1, "hello"); - a.next(r2, "world"); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - verify(aObserver, times(1)).onNext("helloworld"); - - subscription.unsubscribe(); - a.next(r1, "hello"); - a.next(r2, "again"); - - verify(aObserver, times(0)).onError(any(Throwable.class)); - verify(aObserver, never()).onCompleted(); - // we don't want to be called again after an error - verify(aObserver, times(0)).onNext("helloagain"); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testAggregatorEarlyCompletion() { - FuncN zipr = getConcatZipr(); - /* create the aggregator which will execute the zip function when all Observables provide values */ - Aggregator a = new Aggregator(zipr); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - a.onSubscribe(aObserver); - - /* mock the Observable Observers that are 'pushing' data for us */ - ZipObserver r1 = mock(ZipObserver.class); - ZipObserver r2 = mock(ZipObserver.class); - - /* pretend we're starting up */ - a.addObserver(r1); - a.addObserver(r2); - - /* simulate the Observables pushing data into the aggregator */ - a.next(r1, "one"); - a.next(r1, "two"); - a.complete(r1); - a.next(r2, "A"); - - InOrder inOrder = inOrder(aObserver); - - inOrder.verify(aObserver, never()).onError(any(Throwable.class)); - inOrder.verify(aObserver, never()).onCompleted(); - inOrder.verify(aObserver, times(1)).onNext("oneA"); - - a.complete(r2); - - inOrder.verify(aObserver, never()).onError(any(Throwable.class)); - inOrder.verify(aObserver, times(1)).onCompleted(); - inOrder.verify(aObserver, never()).onNext(anyString()); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testZip2Types() { - Func2 zipr = getConcatStringIntegerZipr(); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - - Observable w = Observable.create(zip(Observable.from("one", "two"), Observable.from(2, 3, 4), zipr)); - w.subscribe(aObserver); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - verify(aObserver, times(1)).onNext("one2"); - verify(aObserver, times(1)).onNext("two3"); - verify(aObserver, never()).onNext("4"); - } - - @SuppressWarnings("unchecked") - /* mock calls don't do generics */ - @Test - public void testZip3Types() { - Func3 zipr = getConcatStringIntegerIntArrayZipr(); - - /* define a Observer to receive aggregated events */ - Observer aObserver = mock(Observer.class); - - Observable w = Observable.create(zip(Observable.from("one", "two"), Observable.from(2), Observable.from(new int[] { 4, 5, 6 }), zipr)); - w.subscribe(aObserver); - - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - verify(aObserver, times(1)).onNext("one2[4, 5, 6]"); - verify(aObserver, never()).onNext("two"); - } - - @Test - public void testOnNextExceptionInvokesOnError() { - Func2 zipr = getDivideZipr(); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - - Observable w = Observable.create(zip(Observable.from(10, 20, 30), Observable.from(0, 1, 2), zipr)); - w.subscribe(aObserver); - - verify(aObserver, times(1)).onError(any(Throwable.class)); - } - - private Func2 getDivideZipr() { - Func2 zipr = new Func2() { - - @Override - public Integer call(Integer i1, Integer i2) { - return i1 / i2; - } - - }; - return zipr; - } - - private Func3 getConcat3StringsZipr() { - Func3 zipr = new Func3() { - - @Override - public String call(String a1, String a2, String a3) { - if (a1 == null) { - a1 = ""; - } - if (a2 == null) { - a2 = ""; - } - if (a3 == null) { - a3 = ""; - } - return a1 + a2 + a3; - } - - }; - return zipr; - } - - private FuncN getConcatZipr() { - FuncN zipr = new FuncN() { - - @Override - public String call(Object... args) { - String returnValue = ""; - for (Object o : args) { - if (o != null) { - returnValue += getStringValue(o); - } - } - System.out.println("returning: " + returnValue); - return returnValue; - } - - }; - return zipr; - } - - private Func2 getConcatStringIntegerZipr() { - Func2 zipr = new Func2() { - - @Override - public String call(String s, Integer i) { - return getStringValue(s) + getStringValue(i); - } - - }; - return zipr; - } - - private Func3 getConcatStringIntegerIntArrayZipr() { - Func3 zipr = new Func3() { - - @Override - public String call(String s, Integer i, int[] iArray) { - return getStringValue(s) + getStringValue(i) + getStringValue(iArray); - } - - }; - return zipr; - } - - private static String getStringValue(Object o) { - if (o == null) { - return ""; - } else { - if (o instanceof int[]) { - return Arrays.toString((int[]) o); - } else { - return String.valueOf(o); - } - } - } - - private static class TestObservable implements OnSubscribeFunc { - - Observer observer; - - @Override - public Subscription onSubscribe(Observer Observer) { - // just store the variable where it can be accessed so we can manually trigger it - this.observer = Observer; - return Subscriptions.empty(); - } - - } - } - } diff --git a/rxjava-core/src/main/java/rx/operators/OperatorTester.java b/rxjava-core/src/main/java/rx/operators/OperatorTester.java deleted file mode 100644 index 62b41a0567..0000000000 --- a/rxjava-core/src/main/java/rx/operators/OperatorTester.java +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright 2013 Netflix, Inc. - * - * 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 rx.operators; - -import java.util.concurrent.TimeUnit; - -import rx.Scheduler; -import rx.Subscription; -import rx.util.functions.Action0; -import rx.util.functions.Func2; - -/** - * Common utility functions for testing operator implementations. - */ -/* package */class OperatorTester { - /* - * This is purposefully package-only so it does not leak into the public API outside of this package. - * - * This package is implementation details and not part of the Javadocs and thus can change without breaking backwards compatibility. - * - * benjchristensen => I'm procrastinating the decision of where and how these types of classes (see rx.subjects.UnsubscribeTester) should exist. - * If they are only for internal implementations then I don't want them as part of the API. - * If they are truly useful for everyone to use then an "rx.testing" package may make sense. - */ - - private OperatorTester() { - } - - public static class UnitTest { - - /** - * Used for mocking of Schedulers since many Scheduler implementations are static/final. - * - * @param underlying - * @return - */ - public static Scheduler forwardingScheduler(Scheduler underlying) { - return new ForwardingScheduler(underlying); - } - - public static class ForwardingScheduler extends Scheduler { - private final Scheduler underlying; - - public ForwardingScheduler(Scheduler underlying) { - this.underlying = underlying; - } - - @Override - public Subscription schedule(Action0 action) { - return underlying.schedule(action); - } - - @Override - public Subscription schedule(T state, Func2 action) { - return underlying.schedule(state, action); - } - - @Override - public Subscription schedule(Action0 action, long dueTime, TimeUnit unit) { - return underlying.schedule(action, dueTime, unit); - } - - @Override - public Subscription schedule(T state, Func2 action, long dueTime, TimeUnit unit) { - return underlying.schedule(state, action, dueTime, unit); - } - - @Override - public Subscription schedulePeriodically(Action0 action, long initialDelay, long period, TimeUnit unit) { - return underlying.schedulePeriodically(action, initialDelay, period, unit); - } - - @Override - public Subscription schedulePeriodically(T state, Func2 action, long initialDelay, long period, TimeUnit unit) { - return underlying.schedulePeriodically(state, action, initialDelay, period, unit); - } - - @Override - public long now() { - return underlying.now(); - } - } - } -} \ No newline at end of file diff --git a/rxjava-core/src/main/java/rx/operators/SafeObservableSubscription.java b/rxjava-core/src/main/java/rx/operators/SafeObservableSubscription.java index a94f658708..69e22def56 100644 --- a/rxjava-core/src/main/java/rx/operators/SafeObservableSubscription.java +++ b/rxjava-core/src/main/java/rx/operators/SafeObservableSubscription.java @@ -15,14 +15,10 @@ */ package rx.operators; -import static org.mockito.Mockito.*; +import rx.Subscription; import java.util.concurrent.atomic.AtomicReference; -import org.junit.Test; - -import rx.Subscription; - /** * Thread-safe wrapper around Observable Subscription that ensures unsubscribe can be called only once. *

@@ -82,15 +78,4 @@ public void unsubscribe() { public boolean isUnsubscribed() { return actualSubscription.get() == UNSUBSCRIBED; } - - public static class UnitTest { - @Test - public void testWrapAfterUnsubscribe() { - SafeObservableSubscription atomicObservableSubscription = new SafeObservableSubscription(); - atomicObservableSubscription.unsubscribe(); - Subscription innerSubscription = mock(Subscription.class); - atomicObservableSubscription.wrap(innerSubscription); - verify(innerSubscription, times(1)).unsubscribe(); - } - } } diff --git a/rxjava-core/src/main/java/rx/operators/SynchronizedObserver.java b/rxjava-core/src/main/java/rx/operators/SynchronizedObserver.java index 9a6b14d09f..c8b4fac812 100644 --- a/rxjava-core/src/main/java/rx/operators/SynchronizedObserver.java +++ b/rxjava-core/src/main/java/rx/operators/SynchronizedObserver.java @@ -15,27 +15,7 @@ */ package rx.operators; -import static org.junit.Assert.*; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.Random; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import rx.Observable; -import rx.Observable.OnSubscribeFunc; import rx.Observer; -import rx.Subscription; /** * A thread-safe Observer for transitioning states in operators. @@ -138,740 +118,4 @@ public void onCompleted() { finished = true; } } - - public static class UnitTest { - @Mock - Observer aObserver; - - @Before - public void before() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testSingleThreadedBasic() { - Subscription s = mock(Subscription.class); - TestSingleThreadedObservable onSubscribe = new TestSingleThreadedObservable(s, "one", "two", "three"); - Observable w = Observable.create(onSubscribe); - - SafeObservableSubscription as = new SafeObservableSubscription(s); - SynchronizedObserver aw = new SynchronizedObserver(aObserver, as); - - w.subscribe(aw); - onSubscribe.waitToFinish(); - - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, times(1)).onNext("two"); - verify(aObserver, times(1)).onNext("three"); - verify(aObserver, never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - // non-deterministic because unsubscribe happens after 'waitToFinish' releases - // so commenting out for now as this is not a critical thing to test here - // verify(s, times(1)).unsubscribe(); - } - - @Test - public void testMultiThreadedBasic() { - Subscription s = mock(Subscription.class); - TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable(s, "one", "two", "three"); - Observable w = Observable.create(onSubscribe); - - SafeObservableSubscription as = new SafeObservableSubscription(s); - BusyObserver busyObserver = new BusyObserver(); - SynchronizedObserver aw = new SynchronizedObserver(busyObserver, as); - - w.subscribe(aw); - onSubscribe.waitToFinish(); - - assertEquals(3, busyObserver.onNextCount.get()); - assertFalse(busyObserver.onError); - assertTrue(busyObserver.onCompleted); - // non-deterministic because unsubscribe happens after 'waitToFinish' releases - // so commenting out for now as this is not a critical thing to test here - // verify(s, times(1)).unsubscribe(); - - // we can have concurrency ... - assertTrue(onSubscribe.maxConcurrentThreads.get() > 1); - // ... but the onNext execution should be single threaded - assertEquals(1, busyObserver.maxConcurrentThreads.get()); - } - - @Test - public void testMultiThreadedBasicWithLock() { - Subscription s = mock(Subscription.class); - TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable(s, "one", "two", "three"); - Observable w = Observable.create(onSubscribe); - - SafeObservableSubscription as = new SafeObservableSubscription(s); - BusyObserver busyObserver = new BusyObserver(); - - Object lock = new Object(); - ExternalBusyThread externalBusyThread = new ExternalBusyThread(busyObserver, lock, 10, 100); - - SynchronizedObserver aw = new SynchronizedObserver(busyObserver, as, lock); - - externalBusyThread.start(); - - w.subscribe(aw); - onSubscribe.waitToFinish(); - - try { - externalBusyThread.join(10000); - assertFalse(externalBusyThread.isAlive()); - assertFalse(externalBusyThread.fail); - } catch (InterruptedException e) { - // ignore - } - - assertEquals(3, busyObserver.onNextCount.get()); - assertFalse(busyObserver.onError); - assertTrue(busyObserver.onCompleted); - // non-deterministic because unsubscribe happens after 'waitToFinish' releases - // so commenting out for now as this is not a critical thing to test here - // verify(s, times(1)).unsubscribe(); - - // we can have concurrency ... - assertTrue(onSubscribe.maxConcurrentThreads.get() > 1); - // ... but the onNext execution should be single threaded - assertEquals(1, busyObserver.maxConcurrentThreads.get()); - } - - @Test - public void testMultiThreadedWithNPE() { - Subscription s = mock(Subscription.class); - TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable(s, "one", "two", "three", null); - Observable w = Observable.create(onSubscribe); - - SafeObservableSubscription as = new SafeObservableSubscription(s); - BusyObserver busyObserver = new BusyObserver(); - SynchronizedObserver aw = new SynchronizedObserver(busyObserver, as); - - w.subscribe(aw); - onSubscribe.waitToFinish(); - - System.out.println("maxConcurrentThreads: " + onSubscribe.maxConcurrentThreads.get()); - - // we can't know how many onNext calls will occur since they each run on a separate thread - // that depends on thread scheduling so 0, 1, 2 and 3 are all valid options - // assertEquals(3, busyObserver.onNextCount.get()); - assertTrue(busyObserver.onNextCount.get() < 4); - assertTrue(busyObserver.onError); - // no onCompleted because onError was invoked - assertFalse(busyObserver.onCompleted); - // non-deterministic because unsubscribe happens after 'waitToFinish' releases - // so commenting out for now as this is not a critical thing to test here - //verify(s, times(1)).unsubscribe(); - - // we can have concurrency ... - assertTrue(onSubscribe.maxConcurrentThreads.get() > 1); - // ... but the onNext execution should be single threaded - assertEquals(1, busyObserver.maxConcurrentThreads.get()); - } - - @Test - public void testMultiThreadedWithNPEAndLock() { - Subscription s = mock(Subscription.class); - TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable(s, "one", "two", "three", null); - Observable w = Observable.create(onSubscribe); - - SafeObservableSubscription as = new SafeObservableSubscription(s); - BusyObserver busyObserver = new BusyObserver(); - - Object lock = new Object(); - ExternalBusyThread externalBusyThread = new ExternalBusyThread(busyObserver, lock, 10, 100); - - SynchronizedObserver aw = new SynchronizedObserver(busyObserver, as, lock); - - externalBusyThread.start(); - - w.subscribe(aw); - onSubscribe.waitToFinish(); - - try { - externalBusyThread.join(10000); - assertFalse(externalBusyThread.isAlive()); - assertFalse(externalBusyThread.fail); - } catch (InterruptedException e) { - // ignore - } - - System.out.println("maxConcurrentThreads: " + onSubscribe.maxConcurrentThreads.get()); - - // we can't know how many onNext calls will occur since they each run on a separate thread - // that depends on thread scheduling so 0, 1, 2 and 3 are all valid options - // assertEquals(3, busyObserver.onNextCount.get()); - assertTrue(busyObserver.onNextCount.get() < 4); - assertTrue(busyObserver.onError); - // no onCompleted because onError was invoked - assertFalse(busyObserver.onCompleted); - // non-deterministic because unsubscribe happens after 'waitToFinish' releases - // so commenting out for now as this is not a critical thing to test here - //verify(s, times(1)).unsubscribe(); - - // we can have concurrency ... - assertTrue(onSubscribe.maxConcurrentThreads.get() > 1); - // ... but the onNext execution should be single threaded - assertEquals(1, busyObserver.maxConcurrentThreads.get()); - } - - @Test - public void testMultiThreadedWithNPEinMiddle() { - Subscription s = mock(Subscription.class); - TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable(s, "one", "two", "three", null, "four", "five", "six", "seven", "eight", "nine"); - Observable w = Observable.create(onSubscribe); - - SafeObservableSubscription as = new SafeObservableSubscription(s); - BusyObserver busyObserver = new BusyObserver(); - SynchronizedObserver aw = new SynchronizedObserver(busyObserver, as); - - w.subscribe(aw); - onSubscribe.waitToFinish(); - - System.out.println("maxConcurrentThreads: " + onSubscribe.maxConcurrentThreads.get()); - // this should not be the full number of items since the error should stop it before it completes all 9 - System.out.println("onNext count: " + busyObserver.onNextCount.get()); - assertTrue(busyObserver.onNextCount.get() < 9); - assertTrue(busyObserver.onError); - // no onCompleted because onError was invoked - assertFalse(busyObserver.onCompleted); - // non-deterministic because unsubscribe happens after 'waitToFinish' releases - // so commenting out for now as this is not a critical thing to test here - // verify(s, times(1)).unsubscribe(); - - // we can have concurrency ... - assertTrue(onSubscribe.maxConcurrentThreads.get() > 1); - // ... but the onNext execution should be single threaded - assertEquals(1, busyObserver.maxConcurrentThreads.get()); - } - - @Test - public void testMultiThreadedWithNPEinMiddleAndLock() { - Subscription s = mock(Subscription.class); - TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable(s, "one", "two", "three", null, "four", "five", "six", "seven", "eight", "nine"); - Observable w = Observable.create(onSubscribe); - - SafeObservableSubscription as = new SafeObservableSubscription(s); - BusyObserver busyObserver = new BusyObserver(); - - Object lock = new Object(); - ExternalBusyThread externalBusyThread = new ExternalBusyThread(busyObserver, lock, 10, 100); - - SynchronizedObserver aw = new SynchronizedObserver(busyObserver, as, lock); - - externalBusyThread.start(); - - w.subscribe(aw); - onSubscribe.waitToFinish(); - - try { - externalBusyThread.join(10000); - assertFalse(externalBusyThread.isAlive()); - assertFalse(externalBusyThread.fail); - } catch (InterruptedException e) { - // ignore - } - - System.out.println("maxConcurrentThreads: " + onSubscribe.maxConcurrentThreads.get()); - // this should not be the full number of items since the error should stop it before it completes all 9 - System.out.println("onNext count: " + busyObserver.onNextCount.get()); - assertTrue(busyObserver.onNextCount.get() < 9); - assertTrue(busyObserver.onError); - // no onCompleted because onError was invoked - assertFalse(busyObserver.onCompleted); - // non-deterministic because unsubscribe happens after 'waitToFinish' releases - // so commenting out for now as this is not a critical thing to test here - // verify(s, times(1)).unsubscribe(); - - // we can have concurrency ... - assertTrue(onSubscribe.maxConcurrentThreads.get() > 1); - // ... but the onNext execution should be single threaded - assertEquals(1, busyObserver.maxConcurrentThreads.get()); - } - - /** - * A non-realistic use case that tries to expose thread-safety issues by throwing lots of out-of-order - * events on many threads. - * - * @param w - * @param tw - */ - @Test - public void runConcurrencyTest() { - ExecutorService tp = Executors.newFixedThreadPool(20); - try { - TestConcurrencyObserver tw = new TestConcurrencyObserver(); - SafeObservableSubscription s = new SafeObservableSubscription(); - SynchronizedObserver w = new SynchronizedObserver(tw, s); - - Future f1 = tp.submit(new OnNextThread(w, 12000)); - Future f2 = tp.submit(new OnNextThread(w, 5000)); - Future f3 = tp.submit(new OnNextThread(w, 75000)); - Future f4 = tp.submit(new OnNextThread(w, 13500)); - Future f5 = tp.submit(new OnNextThread(w, 22000)); - Future f6 = tp.submit(new OnNextThread(w, 15000)); - Future f7 = tp.submit(new OnNextThread(w, 7500)); - Future f8 = tp.submit(new OnNextThread(w, 23500)); - - Future f10 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onCompleted, f1, f2, f3, f4)); - try { - Thread.sleep(1); - } catch (InterruptedException e) { - // ignore - } - Future f11 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onCompleted, f4, f6, f7)); - Future f12 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onCompleted, f4, f6, f7)); - Future f13 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onCompleted, f4, f6, f7)); - Future f14 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onCompleted, f4, f6, f7)); - // // the next 4 onError events should wait on same as f10 - Future f15 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onError, f1, f2, f3, f4)); - Future f16 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onError, f1, f2, f3, f4)); - Future f17 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onError, f1, f2, f3, f4)); - Future f18 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onError, f1, f2, f3, f4)); - - waitOnThreads(f1, f2, f3, f4, f5, f6, f7, f8, f10, f11, f12, f13, f14, f15, f16, f17, f18); - @SuppressWarnings("unused") - int numNextEvents = tw.assertEvents(null); // no check of type since we don't want to test barging results here, just interleaving behavior - // System.out.println("Number of events executed: " + numNextEvents); - } catch (Throwable e) { - fail("Concurrency test failed: " + e.getMessage()); - e.printStackTrace(); - } finally { - tp.shutdown(); - try { - tp.awaitTermination(5000, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - private static void waitOnThreads(Future... futures) { - for (Future f : futures) { - try { - f.get(10, TimeUnit.SECONDS); - } catch (Throwable e) { - System.err.println("Failed while waiting on future."); - e.printStackTrace(); - } - } - } - - /** - * A thread that will pass data to onNext - */ - public static class OnNextThread implements Runnable { - - private final Observer Observer; - private final int numStringsToSend; - - OnNextThread(Observer Observer, int numStringsToSend) { - this.Observer = Observer; - this.numStringsToSend = numStringsToSend; - } - - @Override - public void run() { - for (int i = 0; i < numStringsToSend; i++) { - Observer.onNext("aString"); - } - } - } - - /** - * A thread that will call onError or onNext - */ - public static class CompletionThread implements Runnable { - - private final Observer Observer; - private final TestConcurrencyObserverEvent event; - private final Future[] waitOnThese; - - CompletionThread(Observer Observer, TestConcurrencyObserverEvent event, Future... waitOnThese) { - this.Observer = Observer; - this.event = event; - this.waitOnThese = waitOnThese; - } - - @Override - public void run() { - /* if we have 'waitOnThese' futures, we'll wait on them before proceeding */ - if (waitOnThese != null) { - for (Future f : waitOnThese) { - try { - f.get(); - } catch (Throwable e) { - System.err.println("Error while waiting on future in CompletionThread"); - } - } - } - - /* send the event */ - if (event == TestConcurrencyObserverEvent.onError) { - Observer.onError(new RuntimeException("mocked exception")); - } else if (event == TestConcurrencyObserverEvent.onCompleted) { - Observer.onCompleted(); - - } else { - throw new IllegalArgumentException("Expecting either onError or onCompleted"); - } - } - } - - private static enum TestConcurrencyObserverEvent { - onCompleted, onError, onNext - } - - private static class TestConcurrencyObserver implements Observer { - - /** used to store the order and number of events received */ - private final LinkedBlockingQueue events = new LinkedBlockingQueue(); - private final int waitTime; - - @SuppressWarnings("unused") - public TestConcurrencyObserver(int waitTimeInNext) { - this.waitTime = waitTimeInNext; - } - - public TestConcurrencyObserver() { - this.waitTime = 0; - } - - @Override - public void onCompleted() { - events.add(TestConcurrencyObserverEvent.onCompleted); - } - - @Override - public void onError(Throwable e) { - events.add(TestConcurrencyObserverEvent.onError); - } - - @Override - public void onNext(String args) { - events.add(TestConcurrencyObserverEvent.onNext); - // do some artificial work to make the thread scheduling/timing vary - int s = 0; - for (int i = 0; i < 20; i++) { - s += s * i; - } - - if (waitTime > 0) { - try { - Thread.sleep(waitTime); - } catch (InterruptedException e) { - // ignore - } - } - } - - /** - * Assert the order of events is correct and return the number of onNext executions. - * - * @param expectedEndingEvent - * @return int count of onNext calls - * @throws IllegalStateException - * If order of events was invalid. - */ - public int assertEvents(TestConcurrencyObserverEvent expectedEndingEvent) throws IllegalStateException { - int nextCount = 0; - boolean finished = false; - for (TestConcurrencyObserverEvent e : events) { - if (e == TestConcurrencyObserverEvent.onNext) { - if (finished) { - // already finished, we shouldn't get this again - throw new IllegalStateException("Received onNext but we're already finished."); - } - nextCount++; - } else if (e == TestConcurrencyObserverEvent.onError) { - if (finished) { - // already finished, we shouldn't get this again - throw new IllegalStateException("Received onError but we're already finished."); - } - if (expectedEndingEvent != null && TestConcurrencyObserverEvent.onError != expectedEndingEvent) { - throw new IllegalStateException("Received onError ending event but expected " + expectedEndingEvent); - } - finished = true; - } else if (e == TestConcurrencyObserverEvent.onCompleted) { - if (finished) { - // already finished, we shouldn't get this again - throw new IllegalStateException("Received onCompleted but we're already finished."); - } - if (expectedEndingEvent != null && TestConcurrencyObserverEvent.onCompleted != expectedEndingEvent) { - throw new IllegalStateException("Received onCompleted ending event but expected " + expectedEndingEvent); - } - finished = true; - } - } - - return nextCount; - } - - } - - /** - * This spawns a single thread for the subscribe execution - * - */ - private static class TestSingleThreadedObservable implements OnSubscribeFunc { - - final Subscription s; - final String[] values; - private Thread t = null; - - public TestSingleThreadedObservable(final Subscription s, final String... values) { - this.s = s; - this.values = values; - - } - - public Subscription onSubscribe(final Observer observer) { - System.out.println("TestSingleThreadedObservable subscribed to ..."); - t = new Thread(new Runnable() { - - @Override - public void run() { - try { - System.out.println("running TestSingleThreadedObservable thread"); - for (String s : values) { - System.out.println("TestSingleThreadedObservable onNext: " + s); - observer.onNext(s); - } - observer.onCompleted(); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - }); - System.out.println("starting TestSingleThreadedObservable thread"); - t.start(); - System.out.println("done starting TestSingleThreadedObservable thread"); - return s; - } - - public void waitToFinish() { - try { - t.join(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - - } - - /** - * This spawns a thread for the subscription, then a separate thread for each onNext call. - * - */ - private static class TestMultiThreadedObservable implements OnSubscribeFunc { - - final Subscription s; - final String[] values; - Thread t = null; - AtomicInteger threadsRunning = new AtomicInteger(); - AtomicInteger maxConcurrentThreads = new AtomicInteger(); - ExecutorService threadPool; - - public TestMultiThreadedObservable(Subscription s, String... values) { - this.s = s; - this.values = values; - this.threadPool = Executors.newCachedThreadPool(); - } - - @Override - public Subscription onSubscribe(final Observer observer) { - System.out.println("TestMultiThreadedObservable subscribed to ..."); - t = new Thread(new Runnable() { - - @Override - public void run() { - try { - System.out.println("running TestMultiThreadedObservable thread"); - for (final String s : values) { - threadPool.execute(new Runnable() { - - @Override - public void run() { - threadsRunning.incrementAndGet(); - try { - // perform onNext call - System.out.println("TestMultiThreadedObservable onNext: " + s); - if (s == null) { - // force an error - throw new NullPointerException(); - } - observer.onNext(s); - // capture 'maxThreads' - int concurrentThreads = threadsRunning.get(); - int maxThreads = maxConcurrentThreads.get(); - if (concurrentThreads > maxThreads) { - maxConcurrentThreads.compareAndSet(maxThreads, concurrentThreads); - } - } catch (Throwable e) { - observer.onError(e); - } finally { - threadsRunning.decrementAndGet(); - } - } - }); - } - // we are done spawning threads - threadPool.shutdown(); - } catch (Throwable e) { - throw new RuntimeException(e); - } - - // wait until all threads are done, then mark it as COMPLETED - try { - // wait for all the threads to finish - threadPool.awaitTermination(2, TimeUnit.SECONDS); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - observer.onCompleted(); - } - }); - System.out.println("starting TestMultiThreadedObservable thread"); - t.start(); - System.out.println("done starting TestMultiThreadedObservable thread"); - return s; - } - - public void waitToFinish() { - try { - t.join(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - } - - private static class BusyObserver implements Observer { - volatile boolean onCompleted = false; - volatile boolean onError = false; - AtomicInteger onNextCount = new AtomicInteger(); - AtomicInteger threadsRunning = new AtomicInteger(); - AtomicInteger maxConcurrentThreads = new AtomicInteger(); - - @Override - public void onCompleted() { - threadsRunning.incrementAndGet(); - - System.out.println(">>> BusyObserver received onCompleted"); - onCompleted = true; - - int concurrentThreads = threadsRunning.get(); - int maxThreads = maxConcurrentThreads.get(); - if (concurrentThreads > maxThreads) { - maxConcurrentThreads.compareAndSet(maxThreads, concurrentThreads); - } - threadsRunning.decrementAndGet(); - } - - @Override - public void onError(Throwable e) { - threadsRunning.incrementAndGet(); - - System.out.println(">>> BusyObserver received onError: " + e.getMessage()); - onError = true; - - int concurrentThreads = threadsRunning.get(); - int maxThreads = maxConcurrentThreads.get(); - if (concurrentThreads > maxThreads) { - maxConcurrentThreads.compareAndSet(maxThreads, concurrentThreads); - } - threadsRunning.decrementAndGet(); - } - - @Override - public void onNext(String args) { - threadsRunning.incrementAndGet(); - try { - onNextCount.incrementAndGet(); - System.out.println(">>> BusyObserver received onNext: " + args); - try { - // simulate doing something computational - Thread.sleep(200); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } finally { - // capture 'maxThreads' - int concurrentThreads = threadsRunning.get(); - int maxThreads = maxConcurrentThreads.get(); - if (concurrentThreads > maxThreads) { - maxConcurrentThreads.compareAndSet(maxThreads, concurrentThreads); - } - threadsRunning.decrementAndGet(); - } - } - - } - - private static class ExternalBusyThread extends Thread { - - private BusyObserver observer; - private Object lock; - private int lockTimes; - private int waitTime; - public volatile boolean fail; - - public ExternalBusyThread(BusyObserver observer, Object lock, int lockTimes, int waitTime) { - this.observer = observer; - this.lock = lock; - this.lockTimes = lockTimes; - this.waitTime = waitTime; - this.fail = false; - } - - @Override - public void run() { - Random r = new Random(); - for (int i = 0; i < lockTimes; i++) { - synchronized (lock) { - int oldOnNextCount = observer.onNextCount.get(); - boolean oldOnCompleted = observer.onCompleted; - boolean oldOnError = observer.onError; - try { - Thread.sleep(r.nextInt(waitTime)); - } catch (InterruptedException e) { - // ignore - } - // Since we own the lock, onNextCount, onCompleted and - // onError must not be changed. - int newOnNextCount = observer.onNextCount.get(); - boolean newOnCompleted = observer.onCompleted; - boolean newOnError = observer.onError; - if (oldOnNextCount != newOnNextCount) { - System.out.println(">>> ExternalBusyThread received different onNextCount: " - + oldOnNextCount - + " -> " - + newOnNextCount); - fail = true; - break; - } - if (oldOnCompleted != newOnCompleted) { - System.out.println(">>> ExternalBusyThread received different onCompleted: " - + oldOnCompleted - + " -> " - + newOnCompleted); - fail = true; - break; - } - if (oldOnError != newOnError) { - System.out.println(">>> ExternalBusyThread received different onError: " - + oldOnError - + " -> " - + newOnError); - fail = true; - break; - } - } - } - } - - } - - } - } \ No newline at end of file diff --git a/rxjava-core/src/main/java/rx/plugins/RxJavaPlugins.java b/rxjava-core/src/main/java/rx/plugins/RxJavaPlugins.java index e27c343815..1e049732ff 100644 --- a/rxjava-core/src/main/java/rx/plugins/RxJavaPlugins.java +++ b/rxjava-core/src/main/java/rx/plugins/RxJavaPlugins.java @@ -15,12 +15,8 @@ */ package rx.plugins; -import static org.junit.Assert.*; - import java.util.concurrent.atomic.AtomicReference; -import org.junit.Test; - /** * Registry for plugin implementations that allows global override and handles the retrieval of correct implementation based on order of precedence: *

    @@ -36,7 +32,7 @@ public class RxJavaPlugins { private final AtomicReference errorHandler = new AtomicReference(); private final AtomicReference observableExecutionHook = new AtomicReference(); - private RxJavaPlugins() { + RxJavaPlugins() { } @@ -148,77 +144,4 @@ private static Object getPluginImplementationViaProperty(Class pluginClass) { return null; } } - - public static class UnitTest { - - @Test - public void testErrorHandlerDefaultImpl() { - RxJavaErrorHandler impl = new RxJavaPlugins().getErrorHandler(); - assertTrue(impl instanceof RxJavaErrorHandlerDefault); - } - - @Test - public void testErrorHandlerViaRegisterMethod() { - RxJavaPlugins p = new RxJavaPlugins(); - p.registerErrorHandler(new RxJavaErrorHandlerTestImpl()); - RxJavaErrorHandler impl = p.getErrorHandler(); - assertTrue(impl instanceof RxJavaErrorHandlerTestImpl); - } - - @Test - public void testErrorHandlerViaProperty() { - try { - RxJavaPlugins p = new RxJavaPlugins(); - String fullClass = getFullClassNameForTestClass(RxJavaErrorHandlerTestImpl.class); - System.setProperty("rxjava.plugin.RxJavaErrorHandler.implementation", fullClass); - RxJavaErrorHandler impl = p.getErrorHandler(); - assertTrue(impl instanceof RxJavaErrorHandlerTestImpl); - } finally { - System.clearProperty("rxjava.plugin.RxJavaErrorHandler.implementation"); - } - } - - // inside UnitTest so it is stripped from Javadocs - public static class RxJavaErrorHandlerTestImpl extends RxJavaErrorHandler { - // just use defaults - } - - @Test - public void testObservableExecutionHookDefaultImpl() { - RxJavaPlugins p = new RxJavaPlugins(); - RxJavaObservableExecutionHook impl = p.getObservableExecutionHook(); - assertTrue(impl instanceof RxJavaObservableExecutionHookDefault); - } - - @Test - public void testObservableExecutionHookViaRegisterMethod() { - RxJavaPlugins p = new RxJavaPlugins(); - p.registerObservableExecutionHook(new RxJavaObservableExecutionHookTestImpl()); - RxJavaObservableExecutionHook impl = p.getObservableExecutionHook(); - assertTrue(impl instanceof RxJavaObservableExecutionHookTestImpl); - } - - @Test - public void testObservableExecutionHookViaProperty() { - try { - RxJavaPlugins p = new RxJavaPlugins(); - String fullClass = getFullClassNameForTestClass(RxJavaObservableExecutionHookTestImpl.class); - System.setProperty("rxjava.plugin.RxJavaObservableExecutionHook.implementation", fullClass); - RxJavaObservableExecutionHook impl = p.getObservableExecutionHook(); - assertTrue(impl instanceof RxJavaObservableExecutionHookTestImpl); - } finally { - System.clearProperty("rxjava.plugin.RxJavaObservableExecutionHook.implementation"); - } - } - - // inside UnitTest so it is stripped from Javadocs - public static class RxJavaObservableExecutionHookTestImpl extends RxJavaObservableExecutionHook { - // just use defaults - } - - private static String getFullClassNameForTestClass(Class cls) { - return RxJavaPlugins.class.getPackage().getName() + "." + RxJavaPlugins.class.getSimpleName() + "$UnitTest$" + cls.getSimpleName(); - } - } - } diff --git a/rxjava-core/src/main/java/rx/subjects/AsyncSubject.java b/rxjava-core/src/main/java/rx/subjects/AsyncSubject.java index f50ff21322..7e4357c696 100644 --- a/rxjava-core/src/main/java/rx/subjects/AsyncSubject.java +++ b/rxjava-core/src/main/java/rx/subjects/AsyncSubject.java @@ -15,20 +15,12 @@ */ package rx.subjects; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicReference; - -import org.junit.Test; -import org.mockito.Mockito; - import rx.Observer; import rx.Subscription; import rx.operators.SafeObservableSubscription; -import rx.util.functions.Action1; -import rx.util.functions.Func0; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; /** * Subject that publishes only the last event to each {@link Observer} that has subscribed when the @@ -123,135 +115,4 @@ public void onError(Throwable e) { public void onNext(T args) { currentValue.set(args); } - - public static class UnitTest { - - private final Throwable testException = new Throwable(); - - @Test - public void testNeverCompleted() { - AsyncSubject subject = AsyncSubject.create(); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - subject.subscribe(aObserver); - - subject.onNext("one"); - subject.onNext("two"); - subject.onNext("three"); - - assertNeverCompletedObserver(aObserver); - } - - private void assertNeverCompletedObserver(Observer aObserver) - { - verify(aObserver, Mockito.never()).onNext(anyString()); - verify(aObserver, Mockito.never()).onError(testException); - verify(aObserver, Mockito.never()).onCompleted(); - } - - @Test - public void testCompleted() { - AsyncSubject subject = AsyncSubject.create(); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - subject.subscribe(aObserver); - - subject.onNext("one"); - subject.onNext("two"); - subject.onNext("three"); - subject.onCompleted(); - - assertCompletedObserver(aObserver); - } - - private void assertCompletedObserver(Observer aObserver) - { - verify(aObserver, times(1)).onNext("three"); - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testError() { - AsyncSubject subject = AsyncSubject.create(); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - subject.subscribe(aObserver); - - subject.onNext("one"); - subject.onNext("two"); - subject.onNext("three"); - subject.onError(testException); - subject.onNext("four"); - subject.onError(new Throwable()); - subject.onCompleted(); - - assertErrorObserver(aObserver); - } - - private void assertErrorObserver(Observer aObserver) - { - verify(aObserver, Mockito.never()).onNext(anyString()); - verify(aObserver, times(1)).onError(testException); - verify(aObserver, Mockito.never()).onCompleted(); - } - - @Test - public void testUnsubscribeBeforeCompleted() { - AsyncSubject subject = AsyncSubject.create(); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - Subscription subscription = subject.subscribe(aObserver); - - subject.onNext("one"); - subject.onNext("two"); - - subscription.unsubscribe(); - assertNoOnNextEventsReceived(aObserver); - - subject.onNext("three"); - subject.onCompleted(); - - assertNoOnNextEventsReceived(aObserver); - } - - private void assertNoOnNextEventsReceived(Observer aObserver) - { - verify(aObserver, Mockito.never()).onNext(anyString()); - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, Mockito.never()).onCompleted(); - } - - @Test - public void testUnsubscribe() - { - UnsubscribeTester.test(new Func0>() - { - @Override - public AsyncSubject call() - { - return AsyncSubject.create(); - } - }, new Action1>() - { - @Override - public void call(AsyncSubject DefaultSubject) - { - DefaultSubject.onCompleted(); - } - }, new Action1>() - { - @Override - public void call(AsyncSubject DefaultSubject) - { - DefaultSubject.onError(new Throwable()); - } - }, - null); - } - } } diff --git a/rxjava-core/src/main/java/rx/subjects/BehaviorSubject.java b/rxjava-core/src/main/java/rx/subjects/BehaviorSubject.java index 1efe3571bd..5ea3c52146 100644 --- a/rxjava-core/src/main/java/rx/subjects/BehaviorSubject.java +++ b/rxjava-core/src/main/java/rx/subjects/BehaviorSubject.java @@ -15,19 +15,12 @@ */ package rx.subjects; -import static org.mockito.Mockito.*; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicReference; - -import org.junit.Test; -import org.mockito.Mockito; - import rx.Observer; import rx.Subscription; import rx.operators.SafeObservableSubscription; -import rx.util.functions.Action1; -import rx.util.functions.Func0; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; /** * Subject that publishes the most recent and all subsequent events to each subscribed {@link Observer}. @@ -127,137 +120,4 @@ public void onNext(T args) { observer.onNext(args); } } - - public static class UnitTest { - - private final Throwable testException = new Throwable(); - - @Test - public void testThatObserverReceivesDefaultValueIfNothingWasPublished() { - BehaviorSubject subject = BehaviorSubject.createWithDefaultValue("default"); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - subject.subscribe(aObserver); - - subject.onNext("one"); - subject.onNext("two"); - subject.onNext("three"); - - assertReceivedAllEvents(aObserver); - } - - private void assertReceivedAllEvents(Observer aObserver) { - verify(aObserver, times(1)).onNext("default"); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, times(1)).onNext("two"); - verify(aObserver, times(1)).onNext("three"); - verify(aObserver, Mockito.never()).onError(testException); - verify(aObserver, Mockito.never()).onCompleted(); - } - - @Test - public void testThatObserverDoesNotReceiveDefaultValueIfSomethingWasPublished() { - BehaviorSubject subject = BehaviorSubject.createWithDefaultValue("default"); - - subject.onNext("one"); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - subject.subscribe(aObserver); - - subject.onNext("two"); - subject.onNext("three"); - - assertDidNotReceiveTheDefaultValue(aObserver); - } - - private void assertDidNotReceiveTheDefaultValue(Observer aObserver) { - verify(aObserver, Mockito.never()).onNext("default"); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, times(1)).onNext("two"); - verify(aObserver, times(1)).onNext("three"); - verify(aObserver, Mockito.never()).onError(testException); - verify(aObserver, Mockito.never()).onCompleted(); - } - - @Test - public void testCompleted() { - BehaviorSubject subject = BehaviorSubject.createWithDefaultValue("default"); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - subject.subscribe(aObserver); - - subject.onNext("one"); - subject.onCompleted(); - - assertCompletedObserver(aObserver); - } - - private void assertCompletedObserver(Observer aObserver) - { - verify(aObserver, times(1)).onNext("default"); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testCompletedAfterError() { - BehaviorSubject subject = BehaviorSubject.createWithDefaultValue("default"); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - subject.subscribe(aObserver); - - subject.onNext("one"); - subject.onError(testException); - subject.onNext("two"); - subject.onCompleted(); - - assertErrorObserver(aObserver); - } - - private void assertErrorObserver(Observer aObserver) - { - verify(aObserver, times(1)).onNext("default"); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, times(1)).onError(testException); - } - - @Test - public void testUnsubscribe() - { - UnsubscribeTester.test(new Func0>() - { - @Override - public BehaviorSubject call() - { - return BehaviorSubject.createWithDefaultValue("default"); - } - }, new Action1>() - { - @Override - public void call(BehaviorSubject DefaultSubject) - { - DefaultSubject.onCompleted(); - } - }, new Action1>() - { - @Override - public void call(BehaviorSubject DefaultSubject) - { - DefaultSubject.onError(new Throwable()); - } - }, new Action1>() - { - @Override - public void call(BehaviorSubject DefaultSubject) - { - DefaultSubject.onNext("one"); - } - }); - } - } } diff --git a/rxjava-core/src/main/java/rx/subjects/PublishSubject.java b/rxjava-core/src/main/java/rx/subjects/PublishSubject.java index 5588dd485b..ca248ea231 100644 --- a/rxjava-core/src/main/java/rx/subjects/PublishSubject.java +++ b/rxjava-core/src/main/java/rx/subjects/PublishSubject.java @@ -15,32 +15,13 @@ */ package rx.subjects; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; +import rx.Observer; +import rx.Subscription; +import rx.operators.SafeObservableSubscription; import java.util.ArrayList; import java.util.Collection; -import java.util.List; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -import junit.framework.Assert; - -import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.Mockito; - -import rx.Notification; -import rx.Observable; -import rx.Observer; -import rx.Subscription; -import rx.operators.SafeObservableSubscription; -import rx.subscriptions.Subscriptions; -import rx.util.functions.Action1; -import rx.util.functions.Func0; -import rx.util.functions.Func1; /** * Subject that, once and {@link Observer} has subscribed, publishes all subsequent events to the subscriber. @@ -136,356 +117,4 @@ public void onNext(T args) { private Collection> snapshotOfValues() { return new ArrayList>(observers.values()); } - - public static class UnitTest { - @Test - public void test() { - PublishSubject subject = PublishSubject.create(); - final AtomicReference>> actualRef = new AtomicReference>>(); - - Observable>> wNotificationsList = subject.materialize().toList(); - wNotificationsList.subscribe(new Action1>>() { - @Override - public void call(List> actual) { - actualRef.set(actual); - } - }); - - Subscription sub = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(final Observer observer) { - final AtomicBoolean stop = new AtomicBoolean(false); - new Thread() { - @Override - public void run() { - int i = 1; - while (!stop.get()) { - observer.onNext(i++); - } - observer.onCompleted(); - } - }.start(); - return new Subscription() { - @Override - public void unsubscribe() { - stop.set(true); - } - }; - } - }).subscribe(subject); - // the subject has received an onComplete from the first subscribe because - // it is synchronous and the next subscribe won't do anything. - Observable.from(-1, -2, -3).subscribe(subject); - - List> expected = new ArrayList>(); - expected.add(new Notification(-1)); - expected.add(new Notification(-2)); - expected.add(new Notification(-3)); - expected.add(new Notification()); - Assert.assertTrue(actualRef.get().containsAll(expected)); - - sub.unsubscribe(); - } - - private final Throwable testException = new Throwable(); - - @Test - public void testCompleted() { - PublishSubject subject = PublishSubject.create(); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - subject.subscribe(aObserver); - - subject.onNext("one"); - subject.onNext("two"); - subject.onNext("three"); - subject.onCompleted(); - - @SuppressWarnings("unchecked") - Observer anotherObserver = mock(Observer.class); - subject.subscribe(anotherObserver); - - subject.onNext("four"); - subject.onCompleted(); - subject.onError(new Throwable()); - - assertCompletedObserver(aObserver); - // todo bug? assertNeverObserver(anotherObserver); - } - - private void assertCompletedObserver(Observer aObserver) - { - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, times(1)).onNext("two"); - verify(aObserver, times(1)).onNext("three"); - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testError() { - PublishSubject subject = PublishSubject.create(); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - subject.subscribe(aObserver); - - subject.onNext("one"); - subject.onNext("two"); - subject.onNext("three"); - subject.onError(testException); - - @SuppressWarnings("unchecked") - Observer anotherObserver = mock(Observer.class); - subject.subscribe(anotherObserver); - - subject.onNext("four"); - subject.onError(new Throwable()); - subject.onCompleted(); - - assertErrorObserver(aObserver); - // todo bug? assertNeverObserver(anotherObserver); - } - - private void assertErrorObserver(Observer aObserver) - { - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, times(1)).onNext("two"); - verify(aObserver, times(1)).onNext("three"); - verify(aObserver, times(1)).onError(testException); - verify(aObserver, Mockito.never()).onCompleted(); - } - - @Test - public void testSubscribeMidSequence() { - PublishSubject subject = PublishSubject.create(); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - subject.subscribe(aObserver); - - subject.onNext("one"); - subject.onNext("two"); - - assertObservedUntilTwo(aObserver); - - @SuppressWarnings("unchecked") - Observer anotherObserver = mock(Observer.class); - subject.subscribe(anotherObserver); - - subject.onNext("three"); - subject.onCompleted(); - - assertCompletedObserver(aObserver); - assertCompletedStartingWithThreeObserver(anotherObserver); - } - - private void assertCompletedStartingWithThreeObserver(Observer aObserver) - { - verify(aObserver, Mockito.never()).onNext("one"); - verify(aObserver, Mockito.never()).onNext("two"); - verify(aObserver, times(1)).onNext("three"); - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testUnsubscribeFirstObserver() { - PublishSubject subject = PublishSubject.create(); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - Subscription subscription = subject.subscribe(aObserver); - - subject.onNext("one"); - subject.onNext("two"); - - subscription.unsubscribe(); - assertObservedUntilTwo(aObserver); - - @SuppressWarnings("unchecked") - Observer anotherObserver = mock(Observer.class); - subject.subscribe(anotherObserver); - - subject.onNext("three"); - subject.onCompleted(); - - assertObservedUntilTwo(aObserver); - assertCompletedStartingWithThreeObserver(anotherObserver); - } - - private void assertObservedUntilTwo(Observer aObserver) - { - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, times(1)).onNext("two"); - verify(aObserver, Mockito.never()).onNext("three"); - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, Mockito.never()).onCompleted(); - } - - @Test - public void testUnsubscribe() - { - UnsubscribeTester.test(new Func0>() - { - @Override - public PublishSubject call() - { - return PublishSubject.create(); - } - }, new Action1>() - { - @Override - public void call(PublishSubject DefaultSubject) - { - DefaultSubject.onCompleted(); - } - }, new Action1>() - { - @Override - public void call(PublishSubject DefaultSubject) - { - DefaultSubject.onError(new Throwable()); - } - }, new Action1>() - { - @Override - public void call(PublishSubject DefaultSubject) - { - DefaultSubject.onNext("one"); - } - }); - } - - @Test - public void testNestedSubscribe() { - final PublishSubject s = PublishSubject.create(); - - final AtomicInteger countParent = new AtomicInteger(); - final AtomicInteger countChildren = new AtomicInteger(); - final AtomicInteger countTotal = new AtomicInteger(); - - final ArrayList list = new ArrayList(); - - s.mapMany(new Func1>() { - - @Override - public Observable call(final Integer v) { - countParent.incrementAndGet(); - - // then subscribe to subject again (it will not receive the previous value) - return s.map(new Func1() { - - @Override - public String call(Integer v2) { - countChildren.incrementAndGet(); - return "Parent: " + v + " Child: " + v2; - } - - }); - } - - }).subscribe(new Action1() { - - @Override - public void call(String v) { - countTotal.incrementAndGet(); - list.add(v); - } - - }); - - for (int i = 0; i < 10; i++) { - s.onNext(i); - } - s.onCompleted(); - - // System.out.println("countParent: " + countParent.get()); - // System.out.println("countChildren: " + countChildren.get()); - // System.out.println("countTotal: " + countTotal.get()); - - // 9+8+7+6+5+4+3+2+1+0 == 45 - assertEquals(45, list.size()); - } - - /** - * Should be able to unsubscribe all Observers, have it stop emitting, then subscribe new ones and it start emitting again. - */ - @Test - public void testReSubscribe() { - final PublishSubject ps = PublishSubject.create(); - - Observer o1 = mock(Observer.class); - Subscription s1 = ps.subscribe(o1); - - // emit - ps.onNext(1); - - // validate we got it - InOrder inOrder1 = inOrder(o1); - inOrder1.verify(o1, times(1)).onNext(1); - inOrder1.verifyNoMoreInteractions(); - - // unsubscribe - s1.unsubscribe(); - - // emit again but nothing will be there to receive it - ps.onNext(2); - - Observer o2 = mock(Observer.class); - Subscription s2 = ps.subscribe(o2); - - // emit - ps.onNext(3); - - // validate we got it - InOrder inOrder2 = inOrder(o2); - inOrder2.verify(o2, times(1)).onNext(3); - inOrder2.verifyNoMoreInteractions(); - - s2.unsubscribe(); - } - - /** - * Even if subject received an onError/onCompleted, new subscriptions should be able to restart it. - */ - @Test - public void testReSubscribeAfterTerminalState() { - final PublishSubject ps = PublishSubject.create(); - - Observer o1 = mock(Observer.class); - Subscription s1 = ps.subscribe(o1); - - // emit - ps.onNext(1); - - // validate we got it - InOrder inOrder1 = inOrder(o1); - inOrder1.verify(o1, times(1)).onNext(1); - inOrder1.verifyNoMoreInteractions(); - - // unsubscribe - s1.unsubscribe(); - - ps.onCompleted(); - - // emit again but nothing will be there to receive it - ps.onNext(2); - - Observer o2 = mock(Observer.class); - Subscription s2 = ps.subscribe(o2); - - // emit - ps.onNext(3); - - // validate we got it - InOrder inOrder2 = inOrder(o2); - inOrder2.verify(o2, times(1)).onNext(3); - inOrder2.verifyNoMoreInteractions(); - - s2.unsubscribe(); - } - - } } diff --git a/rxjava-core/src/main/java/rx/subjects/ReplaySubject.java b/rxjava-core/src/main/java/rx/subjects/ReplaySubject.java index 3c106e30bc..e103e5fe3b 100644 --- a/rxjava-core/src/main/java/rx/subjects/ReplaySubject.java +++ b/rxjava-core/src/main/java/rx/subjects/ReplaySubject.java @@ -15,25 +15,13 @@ */ package rx.subjects; -import static org.mockito.Mockito.*; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.Mockito; - import rx.Observer; import rx.Subscription; import rx.subscriptions.Subscriptions; -import rx.util.functions.Action1; -import rx.util.functions.Func0; import rx.util.functions.Func1; +import java.util.*; + /** * Subject that retains all events and will replay them to an {@link Observer} that subscribes. *

    @@ -178,172 +166,4 @@ public void onNext(T args) } } } - - public static class UnitTest { - - private final Throwable testException = new Throwable(); - - @SuppressWarnings("unchecked") - @Test - public void testCompleted() { - ReplaySubject subject = ReplaySubject.create(); - - Observer o1 = mock(Observer.class); - subject.subscribe(o1); - - subject.onNext("one"); - subject.onNext("two"); - subject.onNext("three"); - subject.onCompleted(); - - subject.onNext("four"); - subject.onCompleted(); - subject.onError(new Throwable()); - - assertCompletedObserver(o1); - - // assert that subscribing a 2nd time gets the same data - Observer o2 = mock(Observer.class); - subject.subscribe(o2); - assertCompletedObserver(o2); - } - - private void assertCompletedObserver(Observer aObserver) - { - InOrder inOrder = inOrder(aObserver); - - inOrder.verify(aObserver, times(1)).onNext("one"); - inOrder.verify(aObserver, times(1)).onNext("two"); - inOrder.verify(aObserver, times(1)).onNext("three"); - inOrder.verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - inOrder.verify(aObserver, times(1)).onCompleted(); - inOrder.verifyNoMoreInteractions(); - } - - @SuppressWarnings("unchecked") - @Test - public void testError() { - ReplaySubject subject = ReplaySubject.create(); - - Observer aObserver = mock(Observer.class); - subject.subscribe(aObserver); - - subject.onNext("one"); - subject.onNext("two"); - subject.onNext("three"); - subject.onError(testException); - - subject.onNext("four"); - subject.onError(new Throwable()); - subject.onCompleted(); - - assertErrorObserver(aObserver); - - aObserver = mock(Observer.class); - subject.subscribe(aObserver); - assertErrorObserver(aObserver); - } - - private void assertErrorObserver(Observer aObserver) - { - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, times(1)).onNext("two"); - verify(aObserver, times(1)).onNext("three"); - verify(aObserver, times(1)).onError(testException); - verify(aObserver, Mockito.never()).onCompleted(); - } - - @SuppressWarnings("unchecked") - @Test - public void testSubscribeMidSequence() { - ReplaySubject subject = ReplaySubject.create(); - - Observer aObserver = mock(Observer.class); - subject.subscribe(aObserver); - - subject.onNext("one"); - subject.onNext("two"); - - assertObservedUntilTwo(aObserver); - - Observer anotherObserver = mock(Observer.class); - subject.subscribe(anotherObserver); - assertObservedUntilTwo(anotherObserver); - - subject.onNext("three"); - subject.onCompleted(); - - assertCompletedObserver(aObserver); - assertCompletedObserver(anotherObserver); - } - - @SuppressWarnings("unchecked") - @Test - public void testUnsubscribeFirstObserver() { - ReplaySubject subject = ReplaySubject.create(); - - Observer aObserver = mock(Observer.class); - Subscription subscription = subject.subscribe(aObserver); - - subject.onNext("one"); - subject.onNext("two"); - - subscription.unsubscribe(); - assertObservedUntilTwo(aObserver); - - Observer anotherObserver = mock(Observer.class); - subject.subscribe(anotherObserver); - assertObservedUntilTwo(anotherObserver); - - subject.onNext("three"); - subject.onCompleted(); - - assertObservedUntilTwo(aObserver); - assertCompletedObserver(anotherObserver); - } - - private void assertObservedUntilTwo(Observer aObserver) - { - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, times(1)).onNext("two"); - verify(aObserver, Mockito.never()).onNext("three"); - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, Mockito.never()).onCompleted(); - } - - @Test - public void testUnsubscribe() - { - UnsubscribeTester.test(new Func0>() - { - @Override - public ReplaySubject call() - { - return ReplaySubject.create(); - } - }, new Action1>() - { - @Override - public void call(ReplaySubject repeatSubject) - { - repeatSubject.onCompleted(); - } - }, new Action1>() - { - @Override - public void call(ReplaySubject repeatSubject) - { - repeatSubject.onError(new Throwable()); - } - }, new Action1>() - { - @Override - public void call(ReplaySubject repeatSubject) - { - repeatSubject.onNext("one"); - } - } - ); - } - } } diff --git a/rxjava-core/src/main/java/rx/subscriptions/CompositeSubscription.java b/rxjava-core/src/main/java/rx/subscriptions/CompositeSubscription.java index 6ca5c8a699..480da47178 100644 --- a/rxjava-core/src/main/java/rx/subscriptions/CompositeSubscription.java +++ b/rxjava-core/src/main/java/rx/subscriptions/CompositeSubscription.java @@ -15,19 +15,14 @@ */ package rx.subscriptions; -import static org.junit.Assert.*; +import rx.Subscription; +import rx.util.CompositeException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -import org.junit.Test; - -import rx.Subscription; -import rx.util.CompositeException; /** * Subscription that represents a group of Subscriptions that are unsubscribed together. @@ -91,65 +86,4 @@ public synchronized void unsubscribe() { } } } - - public static class UnitTest { - - @Test - public void testSuccess() { - final AtomicInteger counter = new AtomicInteger(); - CompositeSubscription s = new CompositeSubscription(); - s.add(new Subscription() { - - @Override - public void unsubscribe() { - counter.incrementAndGet(); - } - }); - - s.add(new Subscription() { - - @Override - public void unsubscribe() { - counter.incrementAndGet(); - } - }); - - s.unsubscribe(); - - assertEquals(2, counter.get()); - } - - @Test - public void testException() { - final AtomicInteger counter = new AtomicInteger(); - CompositeSubscription s = new CompositeSubscription(); - s.add(new Subscription() { - - @Override - public void unsubscribe() { - throw new RuntimeException("failed on first one"); - } - }); - - s.add(new Subscription() { - - @Override - public void unsubscribe() { - counter.incrementAndGet(); - } - }); - - try { - s.unsubscribe(); - fail("Expecting an exception"); - } catch (CompositeException e) { - // we expect this - assertEquals(1, e.getExceptions().size()); - } - - // we should still have unsubscribed to the second one - assertEquals(1, counter.get()); - } - } - } diff --git a/rxjava-core/src/main/java/rx/subscriptions/Subscriptions.java b/rxjava-core/src/main/java/rx/subscriptions/Subscriptions.java index 5febe4f46a..bb85ed7a15 100644 --- a/rxjava-core/src/main/java/rx/subscriptions/Subscriptions.java +++ b/rxjava-core/src/main/java/rx/subscriptions/Subscriptions.java @@ -15,18 +15,12 @@ */ package rx.subscriptions; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.util.concurrent.Future; - -import org.junit.Test; - import rx.Subscription; import rx.operators.SafeObservableSubscription; import rx.util.functions.Action0; +import java.util.concurrent.Future; + /** * Helper methods and utilities for creating and working with {@link Subscription} objects */ @@ -129,15 +123,4 @@ public static CompositeSubscription create(Subscription... subscriptions) { public void unsubscribe() { } }; - - public static class UnitTest { - @Test - public void testUnsubscribeOnlyOnce() { - Action0 unsubscribe = mock(Action0.class); - Subscription subscription = create(unsubscribe); - subscription.unsubscribe(); - subscription.unsubscribe(); - verify(unsubscribe, times(1)).call(); - } - } } diff --git a/rxjava-core/src/main/java/rx/util/Range.java b/rxjava-core/src/main/java/rx/util/Range.java index c263c53471..5f7418b218 100644 --- a/rxjava-core/src/main/java/rx/util/Range.java +++ b/rxjava-core/src/main/java/rx/util/Range.java @@ -15,16 +15,9 @@ */ package rx.util; -import static org.junit.Assert.*; - -import java.util.ArrayList; -import java.util.Arrays; import java.util.Iterator; -import java.util.List; import java.util.NoSuchElementException; -import org.junit.Test; - public final class Range implements Iterable { private final int start; private final int end; @@ -79,46 +72,4 @@ public void remove() { public String toString() { return "Range (" + start + ", " + end + "), step " + step; } - - public static class UnitTest { - - @Test - public void testSimpleRange() { - assertEquals(Arrays.asList(1, 2, 3, 4), toList(Range.create(1, 5))); - } - - @Test - public void testRangeWithStep() { - assertEquals(Arrays.asList(1, 3, 5, 7, 9), toList(Range.createWithStep(1, 10, 2))); - } - - @Test - public void testRangeWithCount() { - assertEquals(Arrays.asList(1, 2, 3, 4, 5), toList(Range.createWithCount(1, 5))); - } - - @Test - public void testRangeWithCount2() { - assertEquals(Arrays.asList(2, 3, 4, 5), toList(Range.createWithCount(2, 4))); - } - - @Test - public void testRangeWithCount3() { - assertEquals(Arrays.asList(0, 1, 2, 3), toList(Range.createWithCount(0, 4))); - } - - @Test - public void testRangeWithCount4() { - assertEquals(Arrays.asList(10, 11, 12, 13, 14), toList(Range.createWithCount(10, 5))); - } - - private static List toList(Iterable iterable) { - List result = new ArrayList(); - for (T element : iterable) { - result.add(element); - } - return result; - } - - } } \ No newline at end of file diff --git a/rxjava-core/src/test/java/rx/SchedulersTest.java b/rxjava-core/src/test/java/rx/SchedulersTest.java index d2ac58e61f..4150686d74 100644 --- a/rxjava-core/src/test/java/rx/SchedulersTest.java +++ b/rxjava-core/src/test/java/rx/SchedulersTest.java @@ -16,6 +16,8 @@ package rx; import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mockito; import rx.Observable.OnSubscribeFunc; import rx.concurrency.Schedulers; import rx.concurrency.TestScheduler; @@ -34,505 +36,547 @@ import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.*; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Mockito.*; public class SchedulersTest { - @Test - public void testComputationThreadPool1() { + @SuppressWarnings("unchecked") + // mocking is unchecked, unfortunately + @Test + public void testPeriodicScheduling() { + final Func1 calledOp = mock(Func1.class); - Observable o1 = Observable. from(1, 2, 3, 4, 5); - Observable o2 = Observable. from(6, 7, 8, 9, 10); - Observable o = Observable. merge(o1, o2).map(new Func1() { + final TestScheduler scheduler = new TestScheduler(); + Subscription subscription = scheduler.schedulePeriodically(new Action0() { + @Override + public void call() { + System.out.println(scheduler.now()); + calledOp.call(scheduler.now()); + } + }, 1, 2, TimeUnit.SECONDS); + + verify(calledOp, never()).call(anyLong()); - @Override - public String call(Integer t) { - assertTrue(Thread.currentThread().getName().startsWith("RxComputationThreadPool")); - return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); - } - }); - - o.subscribeOn(Schedulers.threadPoolForComputation()).toBlockingObservable().forEach(new Action1() { + InOrder inOrder = Mockito.inOrder(calledOp); + + scheduler.advanceTimeBy(999L, TimeUnit.MILLISECONDS); + inOrder.verify(calledOp, never()).call(anyLong()); - @Override - public void call(String t) { - System.out.println("t: " + t); - } - }); - } + scheduler.advanceTimeBy(1L, TimeUnit.MILLISECONDS); + inOrder.verify(calledOp, times(1)).call(1000L); + + scheduler.advanceTimeBy(1999L, TimeUnit.MILLISECONDS); + inOrder.verify(calledOp, never()).call(3000L); + + scheduler.advanceTimeBy(1L, TimeUnit.MILLISECONDS); + inOrder.verify(calledOp, times(1)).call(3000L); + + scheduler.advanceTimeBy(5L, TimeUnit.SECONDS); + inOrder.verify(calledOp, times(1)).call(5000L); + inOrder.verify(calledOp, times(1)).call(7000L); + + subscription.unsubscribe(); + scheduler.advanceTimeBy(11L, TimeUnit.SECONDS); + inOrder.verify(calledOp, never()).call(anyLong()); + } + + @Test + public void testComputationThreadPool1() { + + Observable o1 = Observable.from(1, 2, 3, 4, 5); + Observable o2 = Observable.from(6, 7, 8, 9, 10); + Observable o = Observable.merge(o1, o2).map(new Func1() { + + @Override + public String call(Integer t) { + assertTrue(Thread.currentThread().getName().startsWith("RxComputationThreadPool")); + return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); + } + }); - @Test - public void testIOThreadPool1() { + o.subscribeOn(Schedulers.threadPoolForComputation()).toBlockingObservable().forEach(new Action1() { + + @Override + public void call(String t) { + System.out.println("t: " + t); + } + }); + } + + @Test + public void testIOThreadPool1() { - Observable o1 = Observable. from(1, 2, 3, 4, 5); - Observable o2 = Observable. from(6, 7, 8, 9, 10); - Observable o = Observable. merge(o1, o2).map(new Func1() { + Observable o1 = Observable.from(1, 2, 3, 4, 5); + Observable o2 = Observable.from(6, 7, 8, 9, 10); + Observable o = Observable.merge(o1, o2).map(new Func1() { - @Override - public String call(Integer t) { - assertTrue(Thread.currentThread().getName().startsWith("RxIOThreadPool")); - return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); - } - }); + @Override + public String call(Integer t) { + assertTrue(Thread.currentThread().getName().startsWith("RxIOThreadPool")); + return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); + } + }); + + o.subscribeOn(Schedulers.threadPoolForIO()).toBlockingObservable().forEach(new Action1() { + + @Override + public void call(String t) { + System.out.println("t: " + t); + } + }); + } + + @Test + public void testMergeWithoutScheduler1() { + + final String currentThreadName = Thread.currentThread().getName(); + + Observable o1 = Observable.from(1, 2, 3, 4, 5); + Observable o2 = Observable.from(6, 7, 8, 9, 10); + Observable o = Observable.merge(o1, o2).map(new Func1() { + + @Override + public String call(Integer t) { + assertTrue(Thread.currentThread().getName().equals(currentThreadName)); + return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); + } + }); + + o.toBlockingObservable().forEach(new Action1() { + + @Override + public void call(String t) { + System.out.println("t: " + t); + } + }); + } - o.subscribeOn(Schedulers.threadPoolForIO()).toBlockingObservable().forEach(new Action1() { + @Test + public void testMergeWithImmediateScheduler1() { - @Override - public void call(String t) { - System.out.println("t: " + t); - } - }); - } + final String currentThreadName = Thread.currentThread().getName(); - @Test - public void testMergeWithoutScheduler1() { + Observable o1 = Observable.from(1, 2, 3, 4, 5); + Observable o2 = Observable.from(6, 7, 8, 9, 10); + Observable o = Observable.merge(o1, o2).subscribeOn(Schedulers.immediate()).map(new Func1() { - final String currentThreadName = Thread.currentThread().getName(); + @Override + public String call(Integer t) { + assertTrue(Thread.currentThread().getName().equals(currentThreadName)); + return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); + } + }); + + o.toBlockingObservable().forEach(new Action1() { + + @Override + public void call(String t) { + System.out.println("t: " + t); + } + }); + } + + @Test + public void testMergeWithCurrentThreadScheduler1() { + + final String currentThreadName = Thread.currentThread().getName(); + + Observable o1 = Observable.from(1, 2, 3, 4, 5); + Observable o2 = Observable.from(6, 7, 8, 9, 10); + Observable o = Observable.merge(o1, o2).subscribeOn(Schedulers.currentThread()).map(new Func1() { + + @Override + public String call(Integer t) { + assertTrue(Thread.currentThread().getName().equals(currentThreadName)); + return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); + } + }); - Observable o1 = Observable. from(1, 2, 3, 4, 5); - Observable o2 = Observable. from(6, 7, 8, 9, 10); - Observable o = Observable. merge(o1, o2).map(new Func1() { + o.toBlockingObservable().forEach(new Action1() { - @Override - public String call(Integer t) { - assertTrue(Thread.currentThread().getName().equals(currentThreadName)); - return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); - } - }); + @Override + public void call(String t) { + System.out.println("t: " + t); + } + }); + } - o.toBlockingObservable().forEach(new Action1() { + @Test + public void testMergeWithScheduler1() { - @Override - public void call(String t) { - System.out.println("t: " + t); - } - }); - } + final String currentThreadName = Thread.currentThread().getName(); - @Test - public void testMergeWithImmediateScheduler1() { + Observable o1 = Observable.from(1, 2, 3, 4, 5); + Observable o2 = Observable.from(6, 7, 8, 9, 10); + Observable o = Observable.merge(o1, o2).subscribeOn(Schedulers.threadPoolForComputation()).map(new Func1() { - final String currentThreadName = Thread.currentThread().getName(); + @Override + public String call(Integer t) { + assertFalse(Thread.currentThread().getName().equals(currentThreadName)); + assertTrue(Thread.currentThread().getName().startsWith("RxComputationThreadPool")); + return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); + } + }); - Observable o1 = Observable. from(1, 2, 3, 4, 5); - Observable o2 = Observable. from(6, 7, 8, 9, 10); - Observable o = Observable. merge(o1, o2).subscribeOn(Schedulers.immediate()).map(new Func1() { + o.toBlockingObservable().forEach(new Action1() { - @Override - public String call(Integer t) { - assertTrue(Thread.currentThread().getName().equals(currentThreadName)); - return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); - } - }); + @Override + public void call(String t) { + System.out.println("t: " + t); + } + }); + } - o.toBlockingObservable().forEach(new Action1() { + @Test + public void testSubscribeWithScheduler1() throws InterruptedException { - @Override - public void call(String t) { - System.out.println("t: " + t); - } - }); - } + final AtomicInteger count = new AtomicInteger(); - @Test - public void testMergeWithCurrentThreadScheduler1() { + Observable o1 = Observable.from(1, 2, 3, 4, 5); - final String currentThreadName = Thread.currentThread().getName(); + o1.subscribe(new Action1() { - Observable o1 = Observable. from(1, 2, 3, 4, 5); - Observable o2 = Observable. from(6, 7, 8, 9, 10); - Observable o = Observable. merge(o1, o2).subscribeOn(Schedulers.currentThread()).map(new Func1() { + @Override + public void call(Integer t) { + System.out.println("Thread: " + Thread.currentThread().getName()); + System.out.println("t: " + t); + count.incrementAndGet(); + } + }); - @Override - public String call(Integer t) { - assertTrue(Thread.currentThread().getName().equals(currentThreadName)); - return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); - } - }); + // the above should be blocking so we should see a count of 5 + assertEquals(5, count.get()); - o.toBlockingObservable().forEach(new Action1() { + count.set(0); - @Override - public void call(String t) { - System.out.println("t: " + t); - } - }); - } + // now we'll subscribe with a scheduler and it should be async - @Test - public void testMergeWithScheduler1() { + final String currentThreadName = Thread.currentThread().getName(); - final String currentThreadName = Thread.currentThread().getName(); + // latches for deterministically controlling the test below across threads + final CountDownLatch latch = new CountDownLatch(5); + final CountDownLatch first = new CountDownLatch(1); - Observable o1 = Observable. from(1, 2, 3, 4, 5); - Observable o2 = Observable. from(6, 7, 8, 9, 10); - Observable o = Observable. merge(o1, o2).subscribeOn(Schedulers.threadPoolForComputation()).map(new Func1() { + o1.subscribe(new Action1() { - @Override - public String call(Integer t) { - assertFalse(Thread.currentThread().getName().equals(currentThreadName)); - assertTrue(Thread.currentThread().getName().startsWith("RxComputationThreadPool")); - return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); + @Override + public void call(Integer t) { + try { + // we block the first one so we can assert this executes asynchronously with a count + first.await(1000, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new RuntimeException("The latch should have released if we are async.", e); + } + assertFalse(Thread.currentThread().getName().equals(currentThreadName)); + assertTrue(Thread.currentThread().getName().startsWith("RxComputationThreadPool")); + System.out.println("Thread: " + Thread.currentThread().getName()); + System.out.println("t: " + t); + count.incrementAndGet(); + latch.countDown(); + } + }, Schedulers.threadPoolForComputation()); + + // assert we are async + assertEquals(0, count.get()); + // release the latch so it can go forward + first.countDown(); + + // wait for all 5 responses + latch.await(); + assertEquals(5, count.get()); + } + + @Test + public void testRecursiveScheduler1() { + Observable obs = Observable.create(new OnSubscribeFunc() { + @Override + public Subscription onSubscribe(final Observer observer) { + return Schedulers.currentThread().schedule(0, new Func2() { + @Override + public Subscription call(Scheduler scheduler, Integer i) { + if (i > 42) { + observer.onCompleted(); + return Subscriptions.empty(); } - }); - o.toBlockingObservable().forEach(new Action1() { + observer.onNext(i); - @Override - public void call(String t) { - System.out.println("t: " + t); - } + return scheduler.schedule(i + 1, this); + } }); - } - - @Test - public void testSubscribeWithScheduler1() throws InterruptedException { - - final AtomicInteger count = new AtomicInteger(); + } + }); + + final AtomicInteger lastValue = new AtomicInteger(); + obs.toBlockingObservable().forEach(new Action1() { + + @Override + public void call(Integer v) { + System.out.println("Value: " + v); + lastValue.set(v); + } + }); + + assertEquals(42, lastValue.get()); + } + + @Test + public void testRecursiveScheduler2() throws InterruptedException { + // use latches instead of Thread.sleep + final CountDownLatch latch = new CountDownLatch(10); + final CountDownLatch completionLatch = new CountDownLatch(1); + + Observable obs = Observable.create(new OnSubscribeFunc() { + @Override + public Subscription onSubscribe(final Observer observer) { + + return Schedulers.threadPoolForComputation().schedule(new BooleanSubscription(), new Func2() { + @Override + public Subscription call(Scheduler scheduler, BooleanSubscription cancel) { + if (cancel.isUnsubscribed()) { + observer.onCompleted(); + completionLatch.countDown(); + return Subscriptions.empty(); + } - Observable o1 = Observable. from(1, 2, 3, 4, 5); + observer.onNext(42); + latch.countDown(); - o1.subscribe(new Action1() { + // this will recursively schedule this task for execution again + scheduler.schedule(cancel, this); - @Override - public void call(Integer t) { - System.out.println("Thread: " + Thread.currentThread().getName()); - System.out.println("t: " + t); - count.incrementAndGet(); - } + return cancel; + } }); + } + }); + + final AtomicInteger count = new AtomicInteger(); + final AtomicBoolean completed = new AtomicBoolean(false); + Subscription subscribe = obs.subscribe(new Observer() { + @Override + public void onCompleted() { + System.out.println("Completed"); + completed.set(true); + } + + @Override + public void onError(Throwable e) { + System.out.println("Error"); + } + + @Override + public void onNext(Integer args) { + count.incrementAndGet(); + System.out.println(args); + } + }); + + if (!latch.await(5000, TimeUnit.MILLISECONDS)) { + fail("Timed out waiting on onNext latch"); + } - // the above should be blocking so we should see a count of 5 - assertEquals(5, count.get()); + // now unsubscribe and ensure it stops the recursive loop + subscribe.unsubscribe(); + System.out.println("unsubscribe"); - count.set(0); + if (!completionLatch.await(5000, TimeUnit.MILLISECONDS)) { + fail("Timed out waiting on completion latch"); + } - // now we'll subscribe with a scheduler and it should be async + // the count can be 10 or higher due to thread scheduling of the unsubscribe vs the scheduler looping to emit the count + assertTrue(count.get() >= 10); + assertTrue(completed.get()); + } - final String currentThreadName = Thread.currentThread().getName(); + @Test + public void testSchedulingWithDueTime() throws InterruptedException { - // latches for deterministically controlling the test below across threads - final CountDownLatch latch = new CountDownLatch(5); - final CountDownLatch first = new CountDownLatch(1); + final CountDownLatch latch = new CountDownLatch(5); + final AtomicInteger counter = new AtomicInteger(); - o1.subscribe(new Action1() { + long start = System.currentTimeMillis(); - @Override - public void call(Integer t) { - try { - // we block the first one so we can assert this executes asynchronously with a count - first.await(1000, TimeUnit.SECONDS); - } catch (InterruptedException e) { - throw new RuntimeException("The latch should have released if we are async.", e); - } - assertFalse(Thread.currentThread().getName().equals(currentThreadName)); - assertTrue(Thread.currentThread().getName().startsWith("RxComputationThreadPool")); - System.out.println("Thread: " + Thread.currentThread().getName()); - System.out.println("t: " + t); - count.incrementAndGet(); - latch.countDown(); - } - }, Schedulers.threadPoolForComputation()); + Schedulers.threadPoolForComputation().schedule(null, new Func2() { - // assert we are async - assertEquals(0, count.get()); - // release the latch so it can go forward - first.countDown(); + @Override + public Subscription call(Scheduler scheduler, String state) { + System.out.println("doing work"); + counter.incrementAndGet(); + latch.countDown(); + if (latch.getCount() == 0) { + return Subscriptions.empty(); + } else { + return scheduler.schedule(state, this, new Date(System.currentTimeMillis() + 50)); + } + } + }, new Date(System.currentTimeMillis() + 100)); - // wait for all 5 responses - latch.await(); - assertEquals(5, count.get()); + if (!latch.await(3000, TimeUnit.MILLISECONDS)) { + fail("didn't execute ... timed out"); } - @Test - public void testRecursiveScheduler1() { - Observable obs = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(final Observer observer) { - return Schedulers.currentThread().schedule(0, new Func2() { - @Override - public Subscription call(Scheduler scheduler, Integer i) { - if (i > 42) { - observer.onCompleted(); - return Subscriptions.empty(); - } - - observer.onNext(i); - - return scheduler.schedule(i + 1, this); - } - }); - } - }); - - final AtomicInteger lastValue = new AtomicInteger(); - obs.toBlockingObservable().forEach(new Action1() { + long end = System.currentTimeMillis(); - @Override - public void call(Integer v) { - System.out.println("Value: " + v); - lastValue.set(v); - } - }); - - assertEquals(42, lastValue.get()); + assertEquals(5, counter.get()); + if ((end - start) < 250) { + fail("it should have taken over 250ms since each step was scheduled 50ms in the future"); } + } - @Test - public void testRecursiveScheduler2() throws InterruptedException { - // use latches instead of Thread.sleep - final CountDownLatch latch = new CountDownLatch(10); - final CountDownLatch completionLatch = new CountDownLatch(1); + @Test + public void testConcurrentOnNextFailsValidation() throws InterruptedException { - Observable obs = Observable.create(new OnSubscribeFunc() { - @Override - public Subscription onSubscribe(final Observer observer) { - - return Schedulers.threadPoolForComputation().schedule(new BooleanSubscription(), new Func2() { - @Override - public Subscription call(Scheduler scheduler, BooleanSubscription cancel) { - if (cancel.isUnsubscribed()) { - observer.onCompleted(); - completionLatch.countDown(); - return Subscriptions.empty(); - } - - observer.onNext(42); - latch.countDown(); - - // this will recursively schedule this task for execution again - scheduler.schedule(cancel, this); - - return cancel; - } - }); - } - }); + final int count = 10; + final CountDownLatch latch = new CountDownLatch(count); + Observable o = Observable.create(new OnSubscribeFunc() { - final AtomicInteger count = new AtomicInteger(); - final AtomicBoolean completed = new AtomicBoolean(false); - Subscription subscribe = obs.subscribe(new Observer() { - @Override - public void onCompleted() { - System.out.println("Completed"); - completed.set(true); - } + @Override + public Subscription onSubscribe(final Observer observer) { + for (int i = 0; i < count; i++) { + final int v = i; + new Thread(new Runnable() { @Override - public void onError(Throwable e) { - System.out.println("Error"); - } + public void run() { + observer.onNext("v: " + v); - @Override - public void onNext(Integer args) { - count.incrementAndGet(); - System.out.println(args); + latch.countDown(); } - }); - - if (!latch.await(5000, TimeUnit.MILLISECONDS)) { - fail("Timed out waiting on onNext latch"); + }).start(); } + return Subscriptions.empty(); + } + }); - // now unsubscribe and ensure it stops the recursive loop - subscribe.unsubscribe(); - System.out.println("unsubscribe"); - - if (!completionLatch.await(5000, TimeUnit.MILLISECONDS)) { - fail("Timed out waiting on completion latch"); - } + ConcurrentObserverValidator observer = new ConcurrentObserverValidator(); + // this should call onNext concurrently + o.subscribe(observer); - // the count can be 10 or higher due to thread scheduling of the unsubscribe vs the scheduler looping to emit the count - assertTrue(count.get() >= 10); - assertTrue(completed.get()); + if (!observer.completed.await(3000, TimeUnit.MILLISECONDS)) { + fail("timed out"); } - @Test - public void testSchedulingWithDueTime() throws InterruptedException { + if (observer.error.get() == null) { + fail("We expected error messages due to concurrency"); + } + } - final CountDownLatch latch = new CountDownLatch(5); - final AtomicInteger counter = new AtomicInteger(); + @Test + public void testObserveOn() throws InterruptedException { - long start = System.currentTimeMillis(); + Observable o = Observable.from("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"); - Schedulers.threadPoolForComputation().schedule(null, new Func2() { + ConcurrentObserverValidator observer = new ConcurrentObserverValidator(); - @Override - public Subscription call(Scheduler scheduler, String state) { - System.out.println("doing work"); - counter.incrementAndGet(); - latch.countDown(); - if (latch.getCount() == 0) { - return Subscriptions.empty(); - } else { - return scheduler.schedule(state, this, new Date(System.currentTimeMillis() + 50)); - } - } - }, new Date(System.currentTimeMillis() + 100)); + o.observeOn(Schedulers.threadPoolForComputation()).subscribe(observer); - if (!latch.await(3000, TimeUnit.MILLISECONDS)) { - fail("didn't execute ... timed out"); - } - - long end = System.currentTimeMillis(); + if (!observer.completed.await(3000, TimeUnit.MILLISECONDS)) { + fail("timed out"); + } - assertEquals(5, counter.get()); - if ((end - start) < 250) { - fail("it should have taken over 250ms since each step was scheduled 50ms in the future"); - } + if (observer.error.get() != null) { + observer.error.get().printStackTrace(); + fail("Error: " + observer.error.get().getMessage()); } + } - @Test - public void testConcurrentOnNextFailsValidation() throws InterruptedException { + @Test + public void testSubscribeOnNestedConcurrency() throws InterruptedException { - final int count = 10; - final CountDownLatch latch = new CountDownLatch(count); - Observable o = Observable.create(new OnSubscribeFunc() { + Observable o = Observable.from("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten") + .mapMany(new Func1>() { - @Override - public Subscription onSubscribe(final Observer observer) { - for (int i = 0; i < count; i++) { - final int v = i; - new Thread(new Runnable() { - - @Override - public void run() { - observer.onNext("v: " + v); - - latch.countDown(); - } - }).start(); - } + @Override + public Observable call(final String v) { + return Observable.create(new OnSubscribeFunc() { + + @Override + public Subscription onSubscribe(final Observer observer) { + observer.onNext("value_after_map-" + v); + observer.onCompleted(); return Subscriptions.empty(); - } + } + }).subscribeOn(Schedulers.newThread()); // subscribe on a new thread + } }); - ConcurrentObserverValidator observer = new ConcurrentObserverValidator(); - // this should call onNext concurrently - o.subscribe(observer); + ConcurrentObserverValidator observer = new ConcurrentObserverValidator(); - if (!observer.completed.await(3000, TimeUnit.MILLISECONDS)) { - fail("timed out"); - } + o.subscribe(observer); - if (observer.error.get() == null) { - fail("We expected error messages due to concurrency"); - } + if (!observer.completed.await(3000, TimeUnit.MILLISECONDS)) { + fail("timed out"); } - @Test - public void testObserveOn() throws InterruptedException { - - Observable o = Observable.from("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"); - - ConcurrentObserverValidator observer = new ConcurrentObserverValidator(); - - o.observeOn(Schedulers.threadPoolForComputation()).subscribe(observer); - - if (!observer.completed.await(3000, TimeUnit.MILLISECONDS)) { - fail("timed out"); - } - - if (observer.error.get() != null) { - observer.error.get().printStackTrace(); - fail("Error: " + observer.error.get().getMessage()); - } + if (observer.error.get() != null) { + observer.error.get().printStackTrace(); + fail("Error: " + observer.error.get().getMessage()); } + } - @Test - public void testSubscribeOnNestedConcurrency() throws InterruptedException { - - Observable o = Observable.from("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten") - .mapMany(new Func1>() { + @Test + public void testRecursion() { + TestScheduler s = new TestScheduler(); - @Override - public Observable call(final String v) { - return Observable.create(new OnSubscribeFunc() { + final AtomicInteger counter = new AtomicInteger(0); - @Override - public Subscription onSubscribe(final Observer observer) { - observer.onNext("value_after_map-" + v); - observer.onCompleted(); - return Subscriptions.empty(); - } - }).subscribeOn(Schedulers.newThread()); // subscribe on a new thread - } - }); + Subscription subscription = s.schedule(new Action1() { - ConcurrentObserverValidator observer = new ConcurrentObserverValidator(); + @Override + public void call(Action0 self) { + counter.incrementAndGet(); + System.out.println("counter: " + counter.get()); + self.call(); + } - o.subscribe(observer); + }); + subscription.unsubscribe(); + assertEquals(0, counter.get()); + } - if (!observer.completed.await(3000, TimeUnit.MILLISECONDS)) { - fail("timed out"); - } - - if (observer.error.get() != null) { - observer.error.get().printStackTrace(); - fail("Error: " + observer.error.get().getMessage()); - } - } - @Test - public void testRecursion() { - TestScheduler s = new TestScheduler(); + /** + * Used to determine if onNext is being invoked concurrently. + * + * @param + */ + private static class ConcurrentObserverValidator implements Observer { - final AtomicInteger counter = new AtomicInteger(0); + final AtomicInteger concurrentCounter = new AtomicInteger(); + final AtomicReference error = new AtomicReference(); + final CountDownLatch completed = new CountDownLatch(1); - Subscription subscription = s.schedule(new Action1() { - - @Override - public void call(Action0 self) { - counter.incrementAndGet(); - System.out.println("counter: " + counter.get()); - self.call(); - } - - }); - subscription.unsubscribe(); - assertEquals(0, counter.get()); + @Override + public void onCompleted() { + completed.countDown(); } + @Override + public void onError(Throwable e) { + completed.countDown(); + error.set(e); + } - /** - * Used to determine if onNext is being invoked concurrently. - * - * @param - */ - private static class ConcurrentObserverValidator implements Observer { - - final AtomicInteger concurrentCounter = new AtomicInteger(); - final AtomicReference error = new AtomicReference(); - final CountDownLatch completed = new CountDownLatch(1); - - @Override - public void onCompleted() { - completed.countDown(); - } - - @Override - public void onError(Throwable e) { - completed.countDown(); - error.set(e); - } - - @Override - public void onNext(T args) { - int count = concurrentCounter.incrementAndGet(); - System.out.println("ConcurrentObserverValidator.onNext: " + args); - if (count > 1) { - onError(new RuntimeException("we should not have concurrent execution of onNext")); - } - try { - try { - // take some time so other onNext calls could pile up (I haven't yet thought of a way to do this without sleeping) - Thread.sleep(50); - } catch (InterruptedException e) { - // ignore - } - } finally { - concurrentCounter.decrementAndGet(); - } + @Override + public void onNext(T args) { + int count = concurrentCounter.incrementAndGet(); + System.out.println("ConcurrentObserverValidator.onNext: " + args); + if (count > 1) { + onError(new RuntimeException("we should not have concurrent execution of onNext")); + } + try { + try { + // take some time so other onNext calls could pile up (I haven't yet thought of a way to do this without sleeping) + Thread.sleep(50); + } catch (InterruptedException e) { + // ignore } - + } finally { + concurrentCounter.decrementAndGet(); + } } + + } } diff --git a/rxjava-core/src/test/java/rx/concurrency/CurrentThreadSchedulerTest.java b/rxjava-core/src/test/java/rx/concurrency/CurrentThreadSchedulerTest.java index b9a9b1a1c2..de34142a93 100644 --- a/rxjava-core/src/test/java/rx/concurrency/CurrentThreadSchedulerTest.java +++ b/rxjava-core/src/test/java/rx/concurrency/CurrentThreadSchedulerTest.java @@ -1,7 +1,129 @@ package rx.concurrency; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.InOrder; +import rx.util.functions.Action0; + +import java.util.concurrent.TimeUnit; + +import static org.mockito.Mockito.*; -@Ignore("WIP") public class CurrentThreadSchedulerTest { + + @Test + public void testNestedActions() { + final CurrentThreadScheduler scheduler = new CurrentThreadScheduler(); + + final Action0 firstStepStart = mock(Action0.class); + final Action0 firstStepEnd = mock(Action0.class); + + final Action0 secondStepStart = mock(Action0.class); + final Action0 secondStepEnd = mock(Action0.class); + + final Action0 thirdStepStart = mock(Action0.class); + final Action0 thirdStepEnd = mock(Action0.class); + + final Action0 firstAction = new Action0() { + @Override + public void call() { + firstStepStart.call(); + firstStepEnd.call(); + } + }; + final Action0 secondAction = new Action0() { + @Override + public void call() { + secondStepStart.call(); + scheduler.schedule(firstAction); + secondStepEnd.call(); + + } + }; + final Action0 thirdAction = new Action0() { + @Override + public void call() { + thirdStepStart.call(); + scheduler.schedule(secondAction); + thirdStepEnd.call(); + } + }; + + InOrder inOrder = inOrder(firstStepStart, firstStepEnd, secondStepStart, secondStepEnd, thirdStepStart, thirdStepEnd); + + scheduler.schedule(thirdAction); + + inOrder.verify(thirdStepStart, times(1)).call(); + inOrder.verify(thirdStepEnd, times(1)).call(); + inOrder.verify(secondStepStart, times(1)).call(); + inOrder.verify(secondStepEnd, times(1)).call(); + inOrder.verify(firstStepStart, times(1)).call(); + inOrder.verify(firstStepEnd, times(1)).call(); + } + + @Test + public void testSequenceOfActions() { + final CurrentThreadScheduler scheduler = new CurrentThreadScheduler(); + + final Action0 first = mock(Action0.class); + final Action0 second = mock(Action0.class); + + scheduler.schedule(first); + scheduler.schedule(second); + + verify(first, times(1)).call(); + verify(second, times(1)).call(); + + } + + @Test + public void testSequenceOfDelayedActions() { + final CurrentThreadScheduler scheduler = new CurrentThreadScheduler(); + + final Action0 first = mock(Action0.class); + final Action0 second = mock(Action0.class); + + scheduler.schedule(new Action0() { + @Override + public void call() { + scheduler.schedule(first, 30, TimeUnit.MILLISECONDS); + scheduler.schedule(second, 10, TimeUnit.MILLISECONDS); + } + }); + + InOrder inOrder = inOrder(first, second); + + inOrder.verify(second, times(1)).call(); + inOrder.verify(first, times(1)).call(); + + + } + + @Test + public void testMixOfDelayedAndNonDelayedActions() { + final CurrentThreadScheduler scheduler = new CurrentThreadScheduler(); + + final Action0 first = mock(Action0.class); + final Action0 second = mock(Action0.class); + final Action0 third = mock(Action0.class); + final Action0 fourth = mock(Action0.class); + + scheduler.schedule(new Action0() { + @Override + public void call() { + scheduler.schedule(first); + scheduler.schedule(second, 300, TimeUnit.MILLISECONDS); + scheduler.schedule(third, 100, TimeUnit.MILLISECONDS); + scheduler.schedule(fourth); + } + }); + + InOrder inOrder = inOrder(first, second, third, fourth); + + inOrder.verify(first, times(1)).call(); + inOrder.verify(fourth, times(1)).call(); + inOrder.verify(third, times(1)).call(); + inOrder.verify(second, times(1)).call(); + + + } } diff --git a/rxjava-core/src/test/java/rx/concurrency/ImmediateSchedulerTest.java b/rxjava-core/src/test/java/rx/concurrency/ImmediateSchedulerTest.java index 036103e540..df08b8aa31 100644 --- a/rxjava-core/src/test/java/rx/concurrency/ImmediateSchedulerTest.java +++ b/rxjava-core/src/test/java/rx/concurrency/ImmediateSchedulerTest.java @@ -1,7 +1,59 @@ package rx.concurrency; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.InOrder; +import rx.util.functions.Action0; + +import static org.mockito.Mockito.*; -@Ignore("WIP") public class ImmediateSchedulerTest { + @Test + public void testNestedActions() { + final ImmediateScheduler scheduler = new ImmediateScheduler(); + + final Action0 firstStepStart = mock(Action0.class); + final Action0 firstStepEnd = mock(Action0.class); + + final Action0 secondStepStart = mock(Action0.class); + final Action0 secondStepEnd = mock(Action0.class); + + final Action0 thirdStepStart = mock(Action0.class); + final Action0 thirdStepEnd = mock(Action0.class); + + final Action0 firstAction = new Action0() { + @Override + public void call() { + firstStepStart.call(); + firstStepEnd.call(); + } + }; + final Action0 secondAction = new Action0() { + @Override + public void call() { + secondStepStart.call(); + scheduler.schedule(firstAction); + secondStepEnd.call(); + + } + }; + final Action0 thirdAction = new Action0() { + @Override + public void call() { + thirdStepStart.call(); + scheduler.schedule(secondAction); + thirdStepEnd.call(); + } + }; + + InOrder inOrder = inOrder(firstStepStart, firstStepEnd, secondStepStart, secondStepEnd, thirdStepStart, thirdStepEnd); + + scheduler.schedule(thirdAction); + + inOrder.verify(thirdStepStart, times(1)).call(); + inOrder.verify(secondStepStart, times(1)).call(); + inOrder.verify(firstStepStart, times(1)).call(); + inOrder.verify(firstStepEnd, times(1)).call(); + inOrder.verify(secondStepEnd, times(1)).call(); + inOrder.verify(thirdStepEnd, times(1)).call(); + } } diff --git a/rxjava-core/src/test/java/rx/observables/BlockingObservableTest.java b/rxjava-core/src/test/java/rx/observables/BlockingObservableTest.java index aa38f711ad..0c6f885de9 100644 --- a/rxjava-core/src/test/java/rx/observables/BlockingObservableTest.java +++ b/rxjava-core/src/test/java/rx/observables/BlockingObservableTest.java @@ -1,7 +1,248 @@ package rx.observables; -import org.junit.Ignore; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.subscriptions.BooleanSubscription; +import rx.subscriptions.Subscriptions; +import rx.util.functions.Action1; +import rx.util.functions.Func1; + +import java.util.Iterator; + +import static org.junit.Assert.*; -@Ignore("WIP") public class BlockingObservableTest { + + @Mock + Observer w; + + @Before + public void before() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testLast() { + BlockingObservable obs = BlockingObservable.from(Observable.from("one", "two", "three")); + + assertEquals("three", obs.last()); + } + + @Test + public void testLastEmptyObservable() { + BlockingObservable obs = BlockingObservable.from(Observable.empty()); + + assertNull(obs.last()); + } + + @Test + public void testLastOrDefault() { + BlockingObservable observable = BlockingObservable.from(Observable.from(1, 0, -1)); + int last = observable.lastOrDefault(-100, new Func1() { + @Override + public Boolean call(Integer args) { + return args >= 0; + } + }); + assertEquals(0, last); + } + + @Test + public void testLastOrDefault1() { + BlockingObservable observable = BlockingObservable.from(Observable.from("one", "two", "three")); + assertEquals("three", observable.lastOrDefault("default")); + } + + @Test + public void testLastOrDefault2() { + BlockingObservable observable = BlockingObservable.from(Observable.empty()); + assertEquals("default", observable.lastOrDefault("default")); + } + + @Test + public void testLastOrDefaultWithPredicate() { + BlockingObservable observable = BlockingObservable.from(Observable.from(1, 0, -1)); + int last = observable.lastOrDefault(0, new Func1() { + @Override + public Boolean call(Integer args) { + return args < 0; + } + }); + + assertEquals(-1, last); + } + + @Test + public void testLastOrDefaultWrongPredicate() { + BlockingObservable observable = BlockingObservable.from(Observable.from(-1, -2, -3)); + int last = observable.lastOrDefault(0, new Func1() { + @Override + public Boolean call(Integer args) { + return args >= 0; + } + }); + assertEquals(0, last); + } + + @Test + public void testLastWithPredicate() { + BlockingObservable obs = BlockingObservable.from(Observable.from("one", "two", "three")); + + assertEquals("two", obs.last(new Func1() { + @Override + public Boolean call(String s) { + return s.length() == 3; + } + })); + } + + public void testSingle() { + BlockingObservable observable = BlockingObservable.from(Observable.from("one")); + assertEquals("one", observable.single()); + } + + @Test + public void testSingleDefault() { + BlockingObservable observable = BlockingObservable.from(Observable.empty()); + assertEquals("default", observable.singleOrDefault("default")); + } + + @Test(expected = IllegalStateException.class) + public void testSingleDefaultPredicateMatchesMoreThanOne() { + BlockingObservable.from(Observable.from("one", "two")).singleOrDefault("default", new Func1() { + @Override + public Boolean call(String args) { + return args.length() == 3; + } + }); + } + + @Test + public void testSingleDefaultPredicateMatchesNothing() { + BlockingObservable observable = BlockingObservable.from(Observable.from("one", "two")); + String result = observable.singleOrDefault("default", new Func1() { + @Override + public Boolean call(String args) { + return args.length() == 4; + } + }); + assertEquals("default", result); + } + + @Test(expected = IllegalStateException.class) + public void testSingleDefaultWithMoreThanOne() { + BlockingObservable observable = BlockingObservable.from(Observable.from("one", "two", "three")); + observable.singleOrDefault("default"); + } + + @Test + public void testSingleWithPredicateDefault() { + BlockingObservable observable = BlockingObservable.from(Observable.from("one", "two", "four")); + assertEquals("four", observable.single(new Func1() { + @Override + public Boolean call(String s) { + return s.length() == 4; + } + })); + } + + @Test(expected = IllegalStateException.class) + public void testSingleWrong() { + BlockingObservable observable = BlockingObservable.from(Observable.from(1, 2)); + observable.single(); + } + + @Test(expected = IllegalStateException.class) + public void testSingleWrongPredicate() { + BlockingObservable observable = BlockingObservable.from(Observable.from(-1)); + observable.single(new Func1() { + @Override + public Boolean call(Integer args) { + return args > 0; + } + }); + } + + @Test + public void testToIterable() { + BlockingObservable obs = BlockingObservable.from(Observable.from("one", "two", "three")); + + Iterator it = obs.toIterable().iterator(); + + assertEquals(true, it.hasNext()); + assertEquals("one", it.next()); + + assertEquals(true, it.hasNext()); + assertEquals("two", it.next()); + + assertEquals(true, it.hasNext()); + assertEquals("three", it.next()); + + assertEquals(false, it.hasNext()); + + } + + @Test(expected = TestException.class) + public void testToIterableWithException() { + BlockingObservable obs = BlockingObservable.from(Observable.create(new Observable.OnSubscribeFunc() { + + @Override + public Subscription onSubscribe(Observer observer) { + observer.onNext("one"); + observer.onError(new TestException()); + return Subscriptions.empty(); + } + })); + + Iterator it = obs.toIterable().iterator(); + + assertEquals(true, it.hasNext()); + assertEquals("one", it.next()); + + assertEquals(true, it.hasNext()); + it.next(); + + } + + @Test + public void testForEachWithError() { + try { + BlockingObservable.from(Observable.create(new Observable.OnSubscribeFunc() { + + @Override + public Subscription onSubscribe(final Observer observer) { + final BooleanSubscription subscription = new BooleanSubscription(); + new Thread(new Runnable() { + + @Override + public void run() { + observer.onNext("one"); + observer.onNext("two"); + observer.onNext("three"); + observer.onCompleted(); + } + }).start(); + return subscription; + } + })).forEach(new Action1() { + + @Override + public void call(String t1) { + throw new RuntimeException("fail"); + } + }); + fail("we expect an exception to be thrown"); + } catch (Throwable e) { + // do nothing as we expect this + } + } + + private static class TestException extends RuntimeException { + private static final long serialVersionUID = 1L; + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationAllTest.java b/rxjava-core/src/test/java/rx/operators/OperationAllTest.java index ffb0b56798..23bde39e59 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationAllTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationAllTest.java @@ -1,7 +1,84 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Observable; +import rx.Observer; +import rx.util.functions.Func1; + +import static org.mockito.Mockito.*; +import static rx.operators.OperationAll.all; -@Ignore("WIP") public class OperationAllTest { + + @Test + @SuppressWarnings("unchecked") + public void testAll() { + Observable obs = Observable.from("one", "two", "six"); + + Observer observer = mock(Observer.class); + Observable.create(all(obs, new Func1() { + @Override + public Boolean call(String s) { + return s.length() == 3; + } + })).subscribe(observer); + + verify(observer).onNext(true); + verify(observer).onCompleted(); + verifyNoMoreInteractions(observer); + } + + @Test + @SuppressWarnings("unchecked") + public void testNotAll() { + Observable obs = Observable.from("one", "two", "three", "six"); + + Observer observer = mock(Observer.class); + Observable.create(all(obs, new Func1() { + @Override + public Boolean call(String s) { + return s.length() == 3; + } + })).subscribe(observer); + + verify(observer).onNext(false); + verify(observer).onCompleted(); + verifyNoMoreInteractions(observer); + } + + @Test + @SuppressWarnings("unchecked") + public void testEmpty() { + Observable obs = Observable.empty(); + + Observer observer = mock(Observer.class); + Observable.create(all(obs, new Func1() { + @Override + public Boolean call(String s) { + return s.length() == 3; + } + })).subscribe(observer); + + verify(observer).onNext(true); + verify(observer).onCompleted(); + verifyNoMoreInteractions(observer); + } + + @Test + @SuppressWarnings("unchecked") + public void testError() { + Throwable error = new Throwable(); + Observable obs = Observable.error(error); + + Observer observer = mock(Observer.class); + Observable.create(all(obs, new Func1() { + @Override + public Boolean call(String s) { + return s.length() == 3; + } + })).subscribe(observer); + + verify(observer).onError(error); + verifyNoMoreInteractions(observer); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationAnyTest.java b/rxjava-core/src/test/java/rx/operators/OperationAnyTest.java index 98d6e72fa5..801a35d0c3 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationAnyTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationAnyTest.java @@ -1,7 +1,182 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Observable; +import rx.Observer; +import rx.util.functions.Func1; + +import static org.mockito.Mockito.*; +import static rx.operators.OperationAny.any; +import static rx.operators.OperationAny.*; -@Ignore("WIP") public class OperationAnyTest { + + @Test + public void testAnyWithTwoItems() { + Observable w = Observable.from(1, 2); + Observable observable = Observable.create(any(w)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, never()).onNext(false); + verify(aObserver, times(1)).onNext(true); + verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testIsEmptyWithTwoItems() { + Observable w = Observable.from(1, 2); + Observable observable = Observable.create(isEmpty(w)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, never()).onNext(true); + verify(aObserver, times(1)).onNext(false); + verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testAnyWithOneItem() { + Observable w = Observable.from(1); + Observable observable = Observable.create(any(w)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, never()).onNext(false); + verify(aObserver, times(1)).onNext(true); + verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testIsEmptyWithOneItem() { + Observable w = Observable.from(1); + Observable observable = Observable.create(isEmpty(w)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, never()).onNext(true); + verify(aObserver, times(1)).onNext(false); + verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testAnyWithEmpty() { + Observable w = Observable.empty(); + Observable observable = Observable.create(any(w)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, times(1)).onNext(false); + verify(aObserver, never()).onNext(true); + verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testIsEmptyWithEmpty() { + Observable w = Observable.empty(); + Observable observable = Observable.create(isEmpty(w)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, times(1)).onNext(true); + verify(aObserver, never()).onNext(false); + verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testAnyWithPredicate1() { + Observable w = Observable.from(1, 2, 3); + Observable observable = Observable.create(any(w, + new Func1() { + + @Override + public Boolean call(Integer t1) { + return t1 < 2; + } + })); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, never()).onNext(false); + verify(aObserver, times(1)).onNext(true); + verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testExists1() { + Observable w = Observable.from(1, 2, 3); + Observable observable = Observable.create(exists(w, + new Func1() { + + @Override + public Boolean call(Integer t1) { + return t1 < 2; + } + })); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, never()).onNext(false); + verify(aObserver, times(1)).onNext(true); + verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testAnyWithPredicate2() { + Observable w = Observable.from(1, 2, 3); + Observable observable = Observable.create(any(w, + new Func1() { + + @Override + public Boolean call(Integer t1) { + return t1 < 1; + } + })); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, times(1)).onNext(false); + verify(aObserver, never()).onNext(true); + verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testAnyWithEmptyAndPredicate() { + // If the source is empty, always output false. + Observable w = Observable.empty(); + Observable observable = Observable.create(any(w, + new Func1() { + + @Override + public Boolean call(Integer t1) { + return true; + } + })); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, times(1)).onNext(false); + verify(aObserver, never()).onNext(true); + verify(aObserver, never()).onError(org.mockito.Matchers.any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationAverageTest.java b/rxjava-core/src/test/java/rx/operators/OperationAverageTest.java index 6fa01dfc92..45e23bf2b9 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationAverageTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationAverageTest.java @@ -1,7 +1,111 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Observable; +import rx.Observer; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyDouble; +import static org.mockito.Matchers.anyFloat; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Mockito.*; +import static rx.operators.OperationAverage.*; + -@Ignore("WIP") public class OperationAverageTest { + + @SuppressWarnings("unchecked") + Observer w = mock(Observer.class); + @SuppressWarnings("unchecked") + Observer wl = mock(Observer.class); + @SuppressWarnings("unchecked") + Observer wf = mock(Observer.class); + @SuppressWarnings("unchecked") + Observer wd = mock(Observer.class); + + @Test + public void testAverageOfAFewInts() throws Throwable { + Observable src = Observable.from(1, 2, 3, 4, 6); + average(src).subscribe(w); + + verify(w, times(1)).onNext(anyInt()); + verify(w).onNext(3); + verify(w, never()).onError(any(Throwable.class)); + verify(w, times(1)).onCompleted(); + } + + @Test + public void testEmptyAverage() throws Throwable { + Observable src = Observable.empty(); + average(src).subscribe(w); + + verify(w, never()).onNext(anyInt()); + verify(w, times(1)).onError(any(ArithmeticException.class)); + verify(w, never()).onCompleted(); + } + + @Test + public void testAverageOfAFewLongs() throws Throwable { + Observable src = Observable.from(1L, 2L, 3L, 4L, 6L); + averageLongs(src).subscribe(wl); + + verify(wl, times(1)).onNext(anyLong()); + verify(wl).onNext(3L); + verify(wl, never()).onError(any(Throwable.class)); + verify(wl, times(1)).onCompleted(); + } + + @Test + public void testEmptyAverageLongs() throws Throwable { + Observable src = Observable.empty(); + averageLongs(src).subscribe(wl); + + verify(wl, never()).onNext(anyLong()); + verify(wl, times(1)).onError(any(ArithmeticException.class)); + verify(wl, never()).onCompleted(); + } + + @Test + public void testAverageOfAFewFloats() throws Throwable { + Observable src = Observable.from(1.0f, 2.0f); + averageFloats(src).subscribe(wf); + + verify(wf, times(1)).onNext(anyFloat()); + verify(wf).onNext(1.5f); + verify(wf, never()).onError(any(Throwable.class)); + verify(wf, times(1)).onCompleted(); + } + + + @Test + public void testEmptyAverageFloats() throws Throwable { + Observable src = Observable.empty(); + averageFloats(src).subscribe(wf); + + verify(wf, never()).onNext(anyFloat()); + verify(wf, times(1)).onError(any(ArithmeticException.class)); + verify(wf, never()).onCompleted(); + } + + @Test + public void testAverageOfAFewDoubles() throws Throwable { + Observable src = Observable.from(1.0d, 2.0d); + averageDoubles(src).subscribe(wd); + + verify(wd, times(1)).onNext(anyDouble()); + verify(wd).onNext(1.5d); + verify(wd, never()).onError(any(Throwable.class)); + verify(wd, times(1)).onCompleted(); + } + + @Test + public void testEmptyAverageDoubles() throws Throwable { + Observable src = Observable.empty(); + averageDoubles(src).subscribe(wd); + + verify(wd, never()).onNext(anyDouble()); + verify(wd, times(1)).onError(any(ArithmeticException.class)); + verify(wd, never()).onCompleted(); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationBufferTest.java b/rxjava-core/src/test/java/rx/operators/OperationBufferTest.java index d096cd666a..fdc44e4014 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationBufferTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationBufferTest.java @@ -1,7 +1,350 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mockito; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.concurrency.TestScheduler; +import rx.subscriptions.Subscriptions; +import rx.util.Closing; +import rx.util.Closings; +import rx.util.Opening; +import rx.util.Openings; +import rx.util.functions.Action0; +import rx.util.functions.Action1; +import rx.util.functions.Func0; +import rx.util.functions.Func1; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertFalse; +import static rx.operators.OperationBuffer.buffer; -@Ignore("WIP") public class OperationBufferTest { + + private Observer> observer; + private TestScheduler scheduler; + + @Before + @SuppressWarnings("unchecked") + public void before() { + observer = Mockito.mock(Observer.class); + scheduler = new TestScheduler(); + } + + @Test + public void testComplete() { + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + observer.onCompleted(); + return Subscriptions.empty(); + } + }); + + Observable> buffered = Observable.create(buffer(source, 3, 3)); + buffered.subscribe(observer); + + Mockito.verify(observer, Mockito.never()).onNext(Mockito.anyListOf(String.class)); + Mockito.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); + Mockito.verify(observer, Mockito.times(1)).onCompleted(); + } + + @Test + public void testSkipAndCountOverlappingBuffers() { + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + observer.onNext("one"); + observer.onNext("two"); + observer.onNext("three"); + observer.onNext("four"); + observer.onNext("five"); + return Subscriptions.empty(); + } + }); + + Observable> buffered = Observable.create(buffer(source, 3, 1)); + buffered.subscribe(observer); + + InOrder inOrder = Mockito.inOrder(observer); + inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two", "three")); + inOrder.verify(observer, Mockito.times(1)).onNext(list("two", "three", "four")); + inOrder.verify(observer, Mockito.times(1)).onNext(list("three", "four", "five")); + inOrder.verify(observer, Mockito.never()).onNext(Mockito.anyListOf(String.class)); + inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); + inOrder.verify(observer, Mockito.never()).onCompleted(); + } + + @Test + public void testSkipAndCountGaplessBuffers() { + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + observer.onNext("one"); + observer.onNext("two"); + observer.onNext("three"); + observer.onNext("four"); + observer.onNext("five"); + observer.onCompleted(); + return Subscriptions.empty(); + } + }); + + Observable> buffered = Observable.create(buffer(source, 3, 3)); + buffered.subscribe(observer); + + InOrder inOrder = Mockito.inOrder(observer); + inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two", "three")); + inOrder.verify(observer, Mockito.times(1)).onNext(list("four", "five")); + inOrder.verify(observer, Mockito.never()).onNext(Mockito.anyListOf(String.class)); + inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); + inOrder.verify(observer, Mockito.times(1)).onCompleted(); + } + + @Test + public void testSkipAndCountBuffersWithGaps() { + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + observer.onNext("one"); + observer.onNext("two"); + observer.onNext("three"); + observer.onNext("four"); + observer.onNext("five"); + observer.onCompleted(); + return Subscriptions.empty(); + } + }); + + Observable> buffered = Observable.create(buffer(source, 2, 3)); + buffered.subscribe(observer); + + InOrder inOrder = Mockito.inOrder(observer); + inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two")); + inOrder.verify(observer, Mockito.times(1)).onNext(list("four", "five")); + inOrder.verify(observer, Mockito.never()).onNext(Mockito.anyListOf(String.class)); + inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); + inOrder.verify(observer, Mockito.times(1)).onCompleted(); + } + + @Test + public void testTimedAndCount() { + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + push(observer, "one", 10); + push(observer, "two", 90); + push(observer, "three", 110); + push(observer, "four", 190); + push(observer, "five", 210); + complete(observer, 250); + return Subscriptions.empty(); + } + }); + + Observable> buffered = Observable.create(buffer(source, 100, TimeUnit.MILLISECONDS, 2, scheduler)); + buffered.subscribe(observer); + + InOrder inOrder = Mockito.inOrder(observer); + scheduler.advanceTimeTo(100, TimeUnit.MILLISECONDS); + inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two")); + + scheduler.advanceTimeTo(200, TimeUnit.MILLISECONDS); + inOrder.verify(observer, Mockito.times(1)).onNext(list("three", "four")); + + scheduler.advanceTimeTo(300, TimeUnit.MILLISECONDS); + inOrder.verify(observer, Mockito.times(1)).onNext(list("five")); + inOrder.verify(observer, Mockito.never()).onNext(Mockito.anyListOf(String.class)); + inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); + inOrder.verify(observer, Mockito.times(1)).onCompleted(); + } + + @Test + public void testTimed() { + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + push(observer, "one", 98); + push(observer, "two", 99); + push(observer, "three", 100); + push(observer, "four", 101); + push(observer, "five", 102); + complete(observer, 150); + return Subscriptions.empty(); + } + }); + + Observable> buffered = Observable.create(buffer(source, 100, TimeUnit.MILLISECONDS, scheduler)); + buffered.subscribe(observer); + + InOrder inOrder = Mockito.inOrder(observer); + scheduler.advanceTimeTo(101, TimeUnit.MILLISECONDS); + inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two", "three")); + + scheduler.advanceTimeTo(201, TimeUnit.MILLISECONDS); + inOrder.verify(observer, Mockito.times(1)).onNext(list("four", "five")); + inOrder.verify(observer, Mockito.never()).onNext(Mockito.anyListOf(String.class)); + inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); + inOrder.verify(observer, Mockito.times(1)).onCompleted(); + } + + @Test + public void testObservableBasedOpenerAndCloser() { + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + push(observer, "one", 10); + push(observer, "two", 60); + push(observer, "three", 110); + push(observer, "four", 160); + push(observer, "five", 210); + complete(observer, 500); + return Subscriptions.empty(); + } + }); + + Observable openings = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + push(observer, Openings.create(), 50); + push(observer, Openings.create(), 200); + complete(observer, 250); + return Subscriptions.empty(); + } + }); + + Func1> closer = new Func1>() { + @Override + public Observable call(Opening opening) { + return Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + push(observer, Closings.create(), 100); + complete(observer, 101); + return Subscriptions.empty(); + } + }); + } + }; + + Observable> buffered = Observable.create(buffer(source, openings, closer)); + buffered.subscribe(observer); + + InOrder inOrder = Mockito.inOrder(observer); + scheduler.advanceTimeTo(500, TimeUnit.MILLISECONDS); + inOrder.verify(observer, Mockito.times(1)).onNext(list("two", "three")); + inOrder.verify(observer, Mockito.times(1)).onNext(list("five")); + inOrder.verify(observer, Mockito.never()).onNext(Mockito.anyListOf(String.class)); + inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); + inOrder.verify(observer, Mockito.times(1)).onCompleted(); + } + + @Test + public void testObservableBasedCloser() { + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + push(observer, "one", 10); + push(observer, "two", 60); + push(observer, "three", 110); + push(observer, "four", 160); + push(observer, "five", 210); + complete(observer, 250); + return Subscriptions.empty(); + } + }); + + Func0> closer = new Func0>() { + @Override + public Observable call() { + return Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + push(observer, Closings.create(), 100); + complete(observer, 101); + return Subscriptions.empty(); + } + }); + } + }; + + Observable> buffered = Observable.create(buffer(source, closer)); + buffered.subscribe(observer); + + InOrder inOrder = Mockito.inOrder(observer); + scheduler.advanceTimeTo(500, TimeUnit.MILLISECONDS); + inOrder.verify(observer, Mockito.times(1)).onNext(list("one", "two")); + inOrder.verify(observer, Mockito.times(1)).onNext(list("three", "four")); + inOrder.verify(observer, Mockito.times(1)).onNext(list("five")); + inOrder.verify(observer, Mockito.never()).onNext(Mockito.anyListOf(String.class)); + inOrder.verify(observer, Mockito.never()).onError(Mockito.any(Throwable.class)); + inOrder.verify(observer, Mockito.times(1)).onCompleted(); + } + + @Test + public void testLongTimeAction() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + LongTimeAction action = new LongTimeAction(latch); + Observable.from(1).buffer(10, TimeUnit.MILLISECONDS, 10) + .subscribe(action); + latch.await(); + assertFalse(action.fail); + } + + private static class LongTimeAction implements Action1> { + + CountDownLatch latch; + boolean fail = false; + + public LongTimeAction(CountDownLatch latch) { + this.latch = latch; + } + + @Override + public void call(List t1) { + try { + if (fail) { + return; + } + Thread.sleep(200); + } catch (InterruptedException e) { + fail = true; + } finally { + latch.countDown(); + } + } + } + + private List list(String... args) { + List list = new ArrayList(); + for (String arg : args) { + list.add(arg); + } + return list; + } + + private void push(final Observer observer, final T value, int delay) { + scheduler.schedule(new Action0() { + @Override + public void call() { + observer.onNext(value); + } + }, delay, TimeUnit.MILLISECONDS); + } + + private void complete(final Observer observer, int delay) { + scheduler.schedule(new Action0() { + @Override + public void call() { + observer.onCompleted(); + } + }, delay, TimeUnit.MILLISECONDS); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationCacheTest.java b/rxjava-core/src/test/java/rx/operators/OperationCacheTest.java index 4a754528e5..9f9ab051a1 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationCacheTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationCacheTest.java @@ -1,7 +1,72 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.subscriptions.BooleanSubscription; +import rx.util.functions.Action1; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static rx.operators.OperationCache.cache; -@Ignore("WIP") public class OperationCacheTest { + + @Test + public void testCache() throws InterruptedException { + final AtomicInteger counter = new AtomicInteger(); + Observable o = Observable.create(cache(Observable.create(new Observable.OnSubscribeFunc() { + + @Override + public Subscription onSubscribe(final Observer observer) { + final BooleanSubscription subscription = new BooleanSubscription(); + new Thread(new Runnable() { + + @Override + public void run() { + counter.incrementAndGet(); + System.out.println("published observable being executed"); + observer.onNext("one"); + observer.onCompleted(); + } + }).start(); + return subscription; + } + }))); + + // we then expect the following 2 subscriptions to get that same value + final CountDownLatch latch = new CountDownLatch(2); + + // subscribe once + o.subscribe(new Action1() { + + @Override + public void call(String v) { + assertEquals("one", v); + System.out.println("v: " + v); + latch.countDown(); + } + }); + + // subscribe again + o.subscribe(new Action1() { + + @Override + public void call(String v) { + assertEquals("one", v); + System.out.println("v: " + v); + latch.countDown(); + } + }); + + if (!latch.await(1000, TimeUnit.MILLISECONDS)) { + fail("subscriptions did not receive values"); + } + assertEquals(1, counter.get()); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationCastTest.java b/rxjava-core/src/test/java/rx/operators/OperationCastTest.java index 36bab268ff..1a87c915fc 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationCastTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationCastTest.java @@ -1,7 +1,40 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Observable; +import rx.Observer; + +import static org.mockito.Mockito.*; +import static rx.operators.OperationCast.cast; -@Ignore("WIP") public class OperationCastTest { + + @Test + public void testCast() { + Observable source = Observable.from(1, 2); + Observable observable = Observable.create(cast(source, + Integer.class)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, times(1)).onNext(1); + verify(aObserver, times(1)).onNext(1); + verify(aObserver, never()).onError( + org.mockito.Matchers.any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testCastWithWrongType() { + Observable source = Observable.from(1, 2); + Observable observable = Observable.create(cast(source, + Boolean.class)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, times(1)).onError( + org.mockito.Matchers.any(ClassCastException.class)); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationCombineLatestTest.java b/rxjava-core/src/test/java/rx/operators/OperationCombineLatestTest.java index b154ce1223..b7ea62a8fd 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationCombineLatestTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationCombineLatestTest.java @@ -1,7 +1,619 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Matchers; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.subscriptions.Subscriptions; +import rx.util.functions.Func2; +import rx.util.functions.Func3; +import rx.util.functions.FuncN; + +import java.util.Arrays; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; +import static rx.operators.OperationCombineLatest.Aggregator; +import static rx.operators.OperationCombineLatest.CombineObserver; +import static rx.operators.OperationCombineLatest.combineLatest; -@Ignore("WIP") public class OperationCombineLatestTest { + + @Test + public void testCombineLatestWithFunctionThatThrowsAnException() { + @SuppressWarnings("unchecked") // mock calls don't do generics + Observer w = mock(Observer.class); + + TestObservable w1 = new TestObservable(); + TestObservable w2 = new TestObservable(); + + Observable combined = Observable.create(combineLatest(Observable.create(w1), Observable.create(w2), new Func2() { + @Override + public String call(String v1, String v2) { + throw new RuntimeException("I don't work."); + } + })); + combined.subscribe(w); + + w1.observer.onNext("first value of w1"); + w2.observer.onNext("first value of w2"); + + verify(w, never()).onNext(anyString()); + verify(w, never()).onCompleted(); + verify(w, times(1)).onError(Matchers.any()); + } + + @Test + public void testCombineLatestDifferentLengthObservableSequences1() { + @SuppressWarnings("unchecked") // mock calls don't do generics + Observer w = mock(Observer.class); + + TestObservable w1 = new TestObservable(); + TestObservable w2 = new TestObservable(); + TestObservable w3 = new TestObservable(); + + Observable combineLatestW = Observable.create(combineLatest(Observable.create(w1), Observable.create(w2), Observable.create(w3), getConcat3StringsCombineLatestFunction())); + combineLatestW.subscribe(w); + + /* simulate sending data */ + // once for w1 + w1.observer.onNext("1a"); + w2.observer.onNext("2a"); + w3.observer.onNext("3a"); + w1.observer.onCompleted(); + // twice for w2 + w2.observer.onNext("2b"); + w2.observer.onCompleted(); + // 4 times for w3 + w3.observer.onNext("3b"); + w3.observer.onNext("3c"); + w3.observer.onNext("3d"); + w3.observer.onCompleted(); + + /* we should have been called 4 times on the Observer */ + InOrder inOrder = inOrder(w); + inOrder.verify(w).onNext("1a2a3a"); + inOrder.verify(w).onNext("1a2b3a"); + inOrder.verify(w).onNext("1a2b3b"); + inOrder.verify(w).onNext("1a2b3c"); + inOrder.verify(w).onNext("1a2b3d"); + inOrder.verify(w, never()).onNext(anyString()); + inOrder.verify(w, times(1)).onCompleted(); + } + + @Test + public void testCombineLatestDifferentLengthObservableSequences2() { + @SuppressWarnings("unchecked") + Observer w = mock(Observer.class); + + TestObservable w1 = new TestObservable(); + TestObservable w2 = new TestObservable(); + TestObservable w3 = new TestObservable(); + + Observable combineLatestW = Observable.create(combineLatest(Observable.create(w1), Observable.create(w2), Observable.create(w3), getConcat3StringsCombineLatestFunction())); + combineLatestW.subscribe(w); + + /* simulate sending data */ + // 4 times for w1 + w1.observer.onNext("1a"); + w1.observer.onNext("1b"); + w1.observer.onNext("1c"); + w1.observer.onNext("1d"); + w1.observer.onCompleted(); + // twice for w2 + w2.observer.onNext("2a"); + w2.observer.onNext("2b"); + w2.observer.onCompleted(); + // 1 times for w3 + w3.observer.onNext("3a"); + w3.observer.onCompleted(); + + /* we should have been called 1 time only on the Observer since we only combine the "latest" we don't go back and loop through others once completed */ + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext("1d2b3a"); + inOrder.verify(w, never()).onNext(anyString()); + + inOrder.verify(w, times(1)).onCompleted(); + + } + + @Test + public void testCombineLatestWithInterleavingSequences() { + @SuppressWarnings("unchecked") + Observer w = mock(Observer.class); + + TestObservable w1 = new TestObservable(); + TestObservable w2 = new TestObservable(); + TestObservable w3 = new TestObservable(); + + Observable combineLatestW = Observable.create(combineLatest(Observable.create(w1), Observable.create(w2), Observable.create(w3), getConcat3StringsCombineLatestFunction())); + combineLatestW.subscribe(w); + + /* simulate sending data */ + w1.observer.onNext("1a"); + w2.observer.onNext("2a"); + w2.observer.onNext("2b"); + w3.observer.onNext("3a"); + + w1.observer.onNext("1b"); + w2.observer.onNext("2c"); + w2.observer.onNext("2d"); + w3.observer.onNext("3b"); + + w1.observer.onCompleted(); + w2.observer.onCompleted(); + w3.observer.onCompleted(); + + /* we should have been called 5 times on the Observer */ + InOrder inOrder = inOrder(w); + inOrder.verify(w).onNext("1a2b3a"); + inOrder.verify(w).onNext("1b2b3a"); + inOrder.verify(w).onNext("1b2c3a"); + inOrder.verify(w).onNext("1b2d3a"); + inOrder.verify(w).onNext("1b2d3b"); + + inOrder.verify(w, never()).onNext(anyString()); + inOrder.verify(w, times(1)).onCompleted(); + } + + /** + * Testing internal private logic due to the complexity so I want to use TDD to test as a I build it rather than relying purely on the overall functionality expected by the public methods. + */ + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testAggregatorSimple() { + FuncN combineLatestFunction = getConcatCombineLatestFunction(); + /* create the aggregator which will execute the combineLatest function when all Observables provide values */ + Aggregator a = new Aggregator(combineLatestFunction); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + Observable.create(a).subscribe(aObserver); + + /* mock the Observable Observers that are 'pushing' data for us */ + CombineObserver r1 = mock(CombineObserver.class); + CombineObserver r2 = mock(CombineObserver.class); + + /* pretend we're starting up */ + a.addObserver(r1); + a.addObserver(r2); + + /* simulate the Observables pushing data into the aggregator */ + a.next(r1, "hello"); + a.next(r2, "world"); + + InOrder inOrder = inOrder(aObserver); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + inOrder.verify(aObserver, times(1)).onNext("helloworld"); + + a.next(r1, "hello "); + a.next(r2, "again"); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + inOrder.verify(aObserver, times(1)).onNext("hello again"); + + a.complete(r1); + a.complete(r2); + + inOrder.verify(aObserver, never()).onNext(anyString()); + verify(aObserver, times(1)).onCompleted(); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testAggregatorDifferentSizedResultsWithOnComplete() { + FuncN combineLatestFunction = getConcatCombineLatestFunction(); + /* create the aggregator which will execute the combineLatest function when all Observables provide values */ + Aggregator a = new Aggregator(combineLatestFunction); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + Observable.create(a).subscribe(aObserver); + + /* mock the Observable Observers that are 'pushing' data for us */ + CombineObserver r1 = mock(CombineObserver.class); + CombineObserver r2 = mock(CombineObserver.class); + + /* pretend we're starting up */ + a.addObserver(r1); + a.addObserver(r2); + + /* simulate the Observables pushing data into the aggregator */ + a.next(r1, "hello"); + a.next(r2, "world"); + a.complete(r2); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + verify(aObserver, times(1)).onNext("helloworld"); + + a.next(r1, "hi"); + a.complete(r1); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + verify(aObserver, times(1)).onNext("hiworld"); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testAggregateMultipleTypes() { + FuncN combineLatestFunction = getConcatCombineLatestFunction(); + /* create the aggregator which will execute the combineLatest function when all Observables provide values */ + Aggregator a = new Aggregator(combineLatestFunction); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + Observable.create(a).subscribe(aObserver); + + /* mock the Observable Observers that are 'pushing' data for us */ + CombineObserver r1 = mock(CombineObserver.class); + CombineObserver r2 = mock(CombineObserver.class); + + /* pretend we're starting up */ + a.addObserver(r1); + a.addObserver(r2); + + /* simulate the Observables pushing data into the aggregator */ + a.next(r1, "hello"); + a.next(r2, "world"); + a.complete(r2); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + verify(aObserver, times(1)).onNext("helloworld"); + + a.next(r1, "hi"); + a.complete(r1); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + verify(aObserver, times(1)).onNext("hiworld"); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testAggregate3Types() { + FuncN combineLatestFunction = getConcatCombineLatestFunction(); + /* create the aggregator which will execute the combineLatest function when all Observables provide values */ + Aggregator a = new Aggregator(combineLatestFunction); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + Observable.create(a).subscribe(aObserver); + + /* mock the Observable Observers that are 'pushing' data for us */ + CombineObserver r1 = mock(CombineObserver.class); + CombineObserver r2 = mock(CombineObserver.class); + CombineObserver r3 = mock(CombineObserver.class); + + /* pretend we're starting up */ + a.addObserver(r1); + a.addObserver(r2); + a.addObserver(r3); + + /* simulate the Observables pushing data into the aggregator */ + a.next(r1, "hello"); + a.next(r2, 2); + a.next(r3, new int[]{5, 6, 7}); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + verify(aObserver, times(1)).onNext("hello2[5, 6, 7]"); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testAggregatorsWithDifferentSizesAndTiming() { + FuncN combineLatestFunction = getConcatCombineLatestFunction(); + /* create the aggregator which will execute the combineLatest function when all Observables provide values */ + Aggregator a = new Aggregator(combineLatestFunction); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + Observable.create(a).subscribe(aObserver); + + /* mock the Observable Observers that are 'pushing' data for us */ + CombineObserver r1 = mock(CombineObserver.class); + CombineObserver r2 = mock(CombineObserver.class); + + /* pretend we're starting up */ + a.addObserver(r1); + a.addObserver(r2); + + /* simulate the Observables pushing data into the aggregator */ + a.next(r1, "one"); + a.next(r1, "two"); + a.next(r1, "three"); + a.next(r2, "A"); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + verify(aObserver, times(1)).onNext("threeA"); + + a.next(r1, "four"); + a.complete(r1); + a.next(r2, "B"); + verify(aObserver, times(1)).onNext("fourB"); + a.next(r2, "C"); + verify(aObserver, times(1)).onNext("fourC"); + a.next(r2, "D"); + verify(aObserver, times(1)).onNext("fourD"); + a.next(r2, "E"); + verify(aObserver, times(1)).onNext("fourE"); + a.complete(r2); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testAggregatorError() { + FuncN combineLatestFunction = getConcatCombineLatestFunction(); + /* create the aggregator which will execute the combineLatest function when all Observables provide values */ + Aggregator a = new Aggregator(combineLatestFunction); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + Observable.create(a).subscribe(aObserver); + + /* mock the Observable Observers that are 'pushing' data for us */ + CombineObserver r1 = mock(CombineObserver.class); + CombineObserver r2 = mock(CombineObserver.class); + + /* pretend we're starting up */ + a.addObserver(r1); + a.addObserver(r2); + + /* simulate the Observables pushing data into the aggregator */ + a.next(r1, "hello"); + a.next(r2, "world"); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + verify(aObserver, times(1)).onNext("helloworld"); + + a.error(new RuntimeException("")); + a.next(r1, "hello"); + a.next(r2, "again"); + + verify(aObserver, times(1)).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + // we don't want to be called again after an error + verify(aObserver, times(0)).onNext("helloagain"); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testAggregatorUnsubscribe() { + FuncN combineLatestFunction = getConcatCombineLatestFunction(); + /* create the aggregator which will execute the combineLatest function when all Observables provide values */ + Aggregator a = new Aggregator(combineLatestFunction); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + Subscription subscription = Observable.create(a).subscribe(aObserver); + + /* mock the Observable Observers that are 'pushing' data for us */ + CombineObserver r1 = mock(CombineObserver.class); + CombineObserver r2 = mock(CombineObserver.class); + + /* pretend we're starting up */ + a.addObserver(r1); + a.addObserver(r2); + + /* simulate the Observables pushing data into the aggregator */ + a.next(r1, "hello"); + a.next(r2, "world"); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + verify(aObserver, times(1)).onNext("helloworld"); + + subscription.unsubscribe(); + a.next(r1, "hello"); + a.next(r2, "again"); + + verify(aObserver, times(0)).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + // we don't want to be called again after an error + verify(aObserver, times(0)).onNext("helloagain"); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testAggregatorEarlyCompletion() { + FuncN combineLatestFunction = getConcatCombineLatestFunction(); + /* create the aggregator which will execute the combineLatest function when all Observables provide values */ + Aggregator a = new Aggregator(combineLatestFunction); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + Observable.create(a).subscribe(aObserver); + + /* mock the Observable Observers that are 'pushing' data for us */ + CombineObserver r1 = mock(CombineObserver.class); + CombineObserver r2 = mock(CombineObserver.class); + + /* pretend we're starting up */ + a.addObserver(r1); + a.addObserver(r2); + + /* simulate the Observables pushing data into the aggregator */ + a.next(r1, "one"); + a.next(r1, "two"); + a.complete(r1); + a.next(r2, "A"); + + InOrder inOrder = inOrder(aObserver); + + inOrder.verify(aObserver, never()).onError(any(Throwable.class)); + inOrder.verify(aObserver, never()).onCompleted(); + inOrder.verify(aObserver, times(1)).onNext("twoA"); + + a.complete(r2); + + inOrder.verify(aObserver, never()).onError(any(Throwable.class)); + inOrder.verify(aObserver, times(1)).onCompleted(); + // we shouldn't get this since completed is called before any other onNext calls could trigger this + inOrder.verify(aObserver, never()).onNext(anyString()); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testCombineLatest2Types() { + Func2 combineLatestFunction = getConcatStringIntegerCombineLatestFunction(); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + + Observable w = Observable.create(combineLatest(Observable.from("one", "two"), Observable.from(2, 3, 4), combineLatestFunction)); + w.subscribe(aObserver); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + verify(aObserver, times(1)).onNext("two2"); + verify(aObserver, times(1)).onNext("two3"); + verify(aObserver, times(1)).onNext("two4"); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testCombineLatest3TypesA() { + Func3 combineLatestFunction = getConcatStringIntegerIntArrayCombineLatestFunction(); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + + Observable w = Observable.create(combineLatest(Observable.from("one", "two"), Observable.from(2), Observable.from(new int[]{4, 5, 6}), combineLatestFunction)); + w.subscribe(aObserver); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + verify(aObserver, times(1)).onNext("two2[4, 5, 6]"); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testCombineLatest3TypesB() { + Func3 combineLatestFunction = getConcatStringIntegerIntArrayCombineLatestFunction(); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + + Observable w = Observable.create(combineLatest(Observable.from("one"), Observable.from(2), Observable.from(new int[]{4, 5, 6}, new int[]{7, 8}), combineLatestFunction)); + w.subscribe(aObserver); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + verify(aObserver, times(1)).onNext("one2[4, 5, 6]"); + verify(aObserver, times(1)).onNext("one2[7, 8]"); + } + + private Func3 getConcat3StringsCombineLatestFunction() { + Func3 combineLatestFunction = new Func3() { + + @Override + public String call(String a1, String a2, String a3) { + if (a1 == null) { + a1 = ""; + } + if (a2 == null) { + a2 = ""; + } + if (a3 == null) { + a3 = ""; + } + return a1 + a2 + a3; + } + + }; + return combineLatestFunction; + } + + private FuncN getConcatCombineLatestFunction() { + FuncN combineLatestFunction = new FuncN() { + + @Override + public String call(Object... args) { + String returnValue = ""; + for (Object o : args) { + if (o != null) { + returnValue += getStringValue(o); + } + } + System.out.println("returning: " + returnValue); + return returnValue; + } + + }; + return combineLatestFunction; + } + + private Func2 getConcatStringIntegerCombineLatestFunction() { + Func2 combineLatestFunction = new Func2() { + + @Override + public String call(String s, Integer i) { + return getStringValue(s) + getStringValue(i); + } + + }; + return combineLatestFunction; + } + + private Func3 getConcatStringIntegerIntArrayCombineLatestFunction() { + Func3 combineLatestFunction = new Func3() { + + @Override + public String call(String s, Integer i, int[] iArray) { + return getStringValue(s) + getStringValue(i) + getStringValue(iArray); + } + + }; + return combineLatestFunction; + } + + private static String getStringValue(Object o) { + if (o == null) { + return ""; + } else { + if (o instanceof int[]) { + return Arrays.toString((int[]) o); + } else { + return String.valueOf(o); + } + } + } + + private static class TestObservable implements Observable.OnSubscribeFunc { + + Observer observer; + + @Override + public Subscription onSubscribe(Observer observer) { + // just store the variable where it can be accessed so we can manually trigger it + this.observer = observer; + return Subscriptions.empty(); + } + + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationConcatTest.java b/rxjava-core/src/test/java/rx/operators/OperationConcatTest.java index 1380ffcaef..35fc22bcc2 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationConcatTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationConcatTest.java @@ -1,7 +1,544 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.InOrder; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.subscriptions.BooleanSubscription; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; +import static rx.operators.OperationConcat.concat; -@Ignore("WIP") public class OperationConcatTest { + + @Test + public void testConcat() { + @SuppressWarnings("unchecked") + Observer observer = mock(Observer.class); + + final String[] o = {"1", "3", "5", "7"}; + final String[] e = {"2", "4", "6"}; + + final Observable odds = Observable.from(o); + final Observable even = Observable.from(e); + + @SuppressWarnings("unchecked") + Observable concat = Observable.create(concat(odds, even)); + concat.subscribe(observer); + + verify(observer, times(7)).onNext(anyString()); + } + + @Test + public void testConcatWithList() { + @SuppressWarnings("unchecked") + Observer observer = mock(Observer.class); + + final String[] o = {"1", "3", "5", "7"}; + final String[] e = {"2", "4", "6"}; + + final Observable odds = Observable.from(o); + final Observable even = Observable.from(e); + final List> list = new ArrayList>(); + list.add(odds); + list.add(even); + Observable concat = Observable.create(concat(list)); + concat.subscribe(observer); + + verify(observer, times(7)).onNext(anyString()); + } + + @Test + public void testConcatObservableOfObservables() { + @SuppressWarnings("unchecked") + Observer observer = mock(Observer.class); + + final String[] o = {"1", "3", "5", "7"}; + final String[] e = {"2", "4", "6"}; + + final Observable odds = Observable.from(o); + final Observable even = Observable.from(e); + + Observable> observableOfObservables = Observable.create(new Observable.OnSubscribeFunc>() { + + @Override + public Subscription onSubscribe(Observer> observer) { + // simulate what would happen in an observable + observer.onNext(odds); + observer.onNext(even); + observer.onCompleted(); + + return new Subscription() { + + @Override + public void unsubscribe() { + // unregister ... will never be called here since we are executing synchronously + } + + }; + } + + }); + Observable concat = Observable.create(concat(observableOfObservables)); + + concat.subscribe(observer); + + verify(observer, times(7)).onNext(anyString()); + } + + /** + * Simple concat of 2 asynchronous observables ensuring it emits in correct order. + */ + @SuppressWarnings("unchecked") + @Test + public void testSimpleAsyncConcat() { + Observer observer = mock(Observer.class); + + TestObservable o1 = new TestObservable("one", "two", "three"); + TestObservable o2 = new TestObservable("four", "five", "six"); + + Observable.concat(Observable.create(o1), Observable.create(o2)).subscribe(observer); + + try { + // wait for async observables to complete + o1.t.join(); + o2.t.join(); + } catch (Throwable e) { + throw new RuntimeException("failed waiting on threads"); + } + + InOrder inOrder = inOrder(observer); + inOrder.verify(observer, times(1)).onNext("one"); + inOrder.verify(observer, times(1)).onNext("two"); + inOrder.verify(observer, times(1)).onNext("three"); + inOrder.verify(observer, times(1)).onNext("four"); + inOrder.verify(observer, times(1)).onNext("five"); + inOrder.verify(observer, times(1)).onNext("six"); + } + + /** + * Test an async Observable that emits more async Observables + */ + @SuppressWarnings("unchecked") + @Test + public void testNestedAsyncConcat() throws Throwable { + Observer observer = mock(Observer.class); + + final TestObservable o1 = new TestObservable("one", "two", "three"); + final TestObservable o2 = new TestObservable("four", "five", "six"); + final TestObservable o3 = new TestObservable("seven", "eight", "nine"); + final CountDownLatch allowThird = new CountDownLatch(1); + + final AtomicReference parent = new AtomicReference(); + Observable> observableOfObservables = Observable.create(new Observable.OnSubscribeFunc>() { + + @Override + public Subscription onSubscribe(final Observer> observer) { + final BooleanSubscription s = new BooleanSubscription(); + parent.set(new Thread(new Runnable() { + + @Override + public void run() { + try { + // emit first + if (!s.isUnsubscribed()) { + System.out.println("Emit o1"); + observer.onNext(Observable.create(o1)); + } + // emit second + if (!s.isUnsubscribed()) { + System.out.println("Emit o2"); + observer.onNext(Observable.create(o2)); + } + + // wait until sometime later and emit third + try { + allowThird.await(); + } catch (InterruptedException e) { + observer.onError(e); + } + if (!s.isUnsubscribed()) { + System.out.println("Emit o3"); + observer.onNext(Observable.create(o3)); + } + + } catch (Throwable e) { + observer.onError(e); + } finally { + System.out.println("Done parent Observable"); + observer.onCompleted(); + } + } + })); + parent.get().start(); + return s; + } + }); + + Observable.create(concat(observableOfObservables)).subscribe(observer); + + // wait for parent to start + while (parent.get() == null) { + Thread.sleep(1); + } + + try { + // wait for first 2 async observables to complete + while (o1.t == null) { + Thread.sleep(1); + } + System.out.println("Thread1 started ... waiting for it to complete ..."); + o1.t.join(); + while (o2.t == null) { + Thread.sleep(1); + } + System.out.println("Thread2 started ... waiting for it to complete ..."); + o2.t.join(); + } catch (Throwable e) { + throw new RuntimeException("failed waiting on threads", e); + } + + InOrder inOrder = inOrder(observer); + inOrder.verify(observer, times(1)).onNext("one"); + inOrder.verify(observer, times(1)).onNext("two"); + inOrder.verify(observer, times(1)).onNext("three"); + inOrder.verify(observer, times(1)).onNext("four"); + inOrder.verify(observer, times(1)).onNext("five"); + inOrder.verify(observer, times(1)).onNext("six"); + // we shouldn't have the following 3 yet + inOrder.verify(observer, never()).onNext("seven"); + inOrder.verify(observer, never()).onNext("eight"); + inOrder.verify(observer, never()).onNext("nine"); + // we should not be completed yet + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + // now allow the third + allowThird.countDown(); + + try { + while (o3.t == null) { + Thread.sleep(1); + } + // wait for 3rd to complete + o3.t.join(); + } catch (Throwable e) { + throw new RuntimeException("failed waiting on threads", e); + } + + inOrder.verify(observer, times(1)).onNext("seven"); + inOrder.verify(observer, times(1)).onNext("eight"); + inOrder.verify(observer, times(1)).onNext("nine"); + + inOrder.verify(observer, times(1)).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + } + + @SuppressWarnings("unchecked") + @Test + public void testBlockedObservableOfObservables() { + Observer observer = mock(Observer.class); + + final String[] o = {"1", "3", "5", "7"}; + final String[] e = {"2", "4", "6"}; + final Observable odds = Observable.from(o); + final Observable even = Observable.from(e); + final CountDownLatch callOnce = new CountDownLatch(1); + final CountDownLatch okToContinue = new CountDownLatch(1); + TestObservable> observableOfObservables = new TestObservable>(callOnce, okToContinue, odds, even); + Observable.OnSubscribeFunc concatF = concat(Observable.create(observableOfObservables)); + Observable concat = Observable.create(concatF); + concat.subscribe(observer); + try { + //Block main thread to allow observables to serve up o1. + callOnce.await(); + } catch (Throwable ex) { + ex.printStackTrace(); + fail(ex.getMessage()); + } + // The concated observable should have served up all of the odds. + verify(observer, times(1)).onNext("1"); + verify(observer, times(1)).onNext("3"); + verify(observer, times(1)).onNext("5"); + verify(observer, times(1)).onNext("7"); + + try { + // unblock observables so it can serve up o2 and complete + okToContinue.countDown(); + observableOfObservables.t.join(); + } catch (Throwable ex) { + ex.printStackTrace(); + fail(ex.getMessage()); + } + // The concatenated observable should now have served up all the evens. + verify(observer, times(1)).onNext("2"); + verify(observer, times(1)).onNext("4"); + verify(observer, times(1)).onNext("6"); + } + + @Test + public void testConcatConcurrentWithInfinity() { + final TestObservable w1 = new TestObservable("one", "two", "three"); + //This observable will send "hello" MAX_VALUE time. + final TestObservable w2 = new TestObservable("hello", Integer.MAX_VALUE); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + @SuppressWarnings("unchecked") + TestObservable> observableOfObservables = new TestObservable>(Observable.create(w1), Observable.create(w2)); + Observable.OnSubscribeFunc concatF = concat(Observable.create(observableOfObservables)); + + Observable concat = Observable.create(concatF); + + concat.take(50).subscribe(aObserver); + + //Wait for the thread to start up. + try { + Thread.sleep(25); + w1.t.join(); + w2.t.join(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + InOrder inOrder = inOrder(aObserver); + inOrder.verify(aObserver, times(1)).onNext("one"); + inOrder.verify(aObserver, times(1)).onNext("two"); + inOrder.verify(aObserver, times(1)).onNext("three"); + inOrder.verify(aObserver, times(47)).onNext("hello"); + verify(aObserver, times(1)).onCompleted(); + verify(aObserver, never()).onError(any(Throwable.class)); + } + + @Test + public void testConcatNonBlockingObservables() { + + final CountDownLatch okToContinueW1 = new CountDownLatch(1); + final CountDownLatch okToContinueW2 = new CountDownLatch(1); + + final TestObservable w1 = new TestObservable(null, okToContinueW1, "one", "two", "three"); + final TestObservable w2 = new TestObservable(null, okToContinueW2, "four", "five", "six"); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + Observable> observableOfObservables = Observable.create(new Observable.OnSubscribeFunc>() { + + @Override + public Subscription onSubscribe(Observer> observer) { + // simulate what would happen in an observable + observer.onNext(Observable.create(w1)); + observer.onNext(Observable.create(w2)); + observer.onCompleted(); + + return new Subscription() { + + @Override + public void unsubscribe() { + } + + }; + } + + }); + Observable concat = Observable.create(concat(observableOfObservables)); + concat.subscribe(aObserver); + + verify(aObserver, times(0)).onCompleted(); + + try { + // release both threads + okToContinueW1.countDown(); + okToContinueW2.countDown(); + // wait for both to finish + w1.t.join(); + w2.t.join(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + InOrder inOrder = inOrder(aObserver); + inOrder.verify(aObserver, times(1)).onNext("one"); + inOrder.verify(aObserver, times(1)).onNext("two"); + inOrder.verify(aObserver, times(1)).onNext("three"); + inOrder.verify(aObserver, times(1)).onNext("four"); + inOrder.verify(aObserver, times(1)).onNext("five"); + inOrder.verify(aObserver, times(1)).onNext("six"); + verify(aObserver, times(1)).onCompleted(); + + } + + /** + * Test unsubscribing the concatenated Observable in a single thread. + */ + @Test + public void testConcatUnsubscribe() { + final CountDownLatch callOnce = new CountDownLatch(1); + final CountDownLatch okToContinue = new CountDownLatch(1); + final TestObservable w1 = new TestObservable("one", "two", "three"); + final TestObservable w2 = new TestObservable(callOnce, okToContinue, "four", "five", "six"); + + @SuppressWarnings("unchecked") + final Observer aObserver = mock(Observer.class); + @SuppressWarnings("unchecked") + final Observable concat = Observable.create(concat(Observable.create(w1), Observable.create(w2))); + final SafeObservableSubscription s1 = new SafeObservableSubscription(); + + try { + // Subscribe + s1.wrap(concat.subscribe(aObserver)); + //Block main thread to allow observable "w1" to complete and observable "w2" to call onNext once. + callOnce.await(); + // Unsubcribe + s1.unsubscribe(); + //Unblock the observable to continue. + okToContinue.countDown(); + w1.t.join(); + w2.t.join(); + } catch (Throwable e) { + e.printStackTrace(); + fail(e.getMessage()); + } + + InOrder inOrder = inOrder(aObserver); + inOrder.verify(aObserver, times(1)).onNext("one"); + inOrder.verify(aObserver, times(1)).onNext("two"); + inOrder.verify(aObserver, times(1)).onNext("three"); + inOrder.verify(aObserver, times(1)).onNext("four"); + inOrder.verify(aObserver, never()).onNext("five"); + inOrder.verify(aObserver, never()).onNext("six"); + inOrder.verify(aObserver, never()).onCompleted(); + + } + + /** + * All observables will be running in different threads so subscribe() is unblocked. CountDownLatch is only used in order to call unsubscribe() in a predictable manner. + */ + @Test + public void testConcatUnsubscribeConcurrent() { + final CountDownLatch callOnce = new CountDownLatch(1); + final CountDownLatch okToContinue = new CountDownLatch(1); + final TestObservable w1 = new TestObservable("one", "two", "three"); + final TestObservable w2 = new TestObservable(callOnce, okToContinue, "four", "five", "six"); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + @SuppressWarnings("unchecked") + TestObservable> observableOfObservables = new TestObservable>(Observable.create(w1), Observable.create(w2)); + Observable.OnSubscribeFunc concatF = concat(Observable.create(observableOfObservables)); + + Observable concat = Observable.create(concatF); + + Subscription s1 = concat.subscribe(aObserver); + + try { + //Block main thread to allow observable "w1" to complete and observable "w2" to call onNext exactly once. + callOnce.await(); + //"four" from w2 has been processed by onNext() + s1.unsubscribe(); + //"five" and "six" will NOT be processed by onNext() + //Unblock the observable to continue. + okToContinue.countDown(); + w1.t.join(); + w2.t.join(); + } catch (Throwable e) { + e.printStackTrace(); + fail(e.getMessage()); + } + + InOrder inOrder = inOrder(aObserver); + inOrder.verify(aObserver, times(1)).onNext("one"); + inOrder.verify(aObserver, times(1)).onNext("two"); + inOrder.verify(aObserver, times(1)).onNext("three"); + inOrder.verify(aObserver, times(1)).onNext("four"); + inOrder.verify(aObserver, never()).onNext("five"); + inOrder.verify(aObserver, never()).onNext("six"); + verify(aObserver, never()).onCompleted(); + verify(aObserver, never()).onError(any(Throwable.class)); + } + + private static class TestObservable implements Observable.OnSubscribeFunc { + + private final Subscription s = new Subscription() { + + @Override + public void unsubscribe() { + subscribed = false; + } + + }; + private final List values; + private Thread t = null; + private int count = 0; + private boolean subscribed = true; + private final CountDownLatch once; + private final CountDownLatch okToContinue; + private final T seed; + private final int size; + + public TestObservable(T... values) { + this(null, null, values); + } + + public TestObservable(CountDownLatch once, CountDownLatch okToContinue, T... values) { + this.values = Arrays.asList(values); + this.size = this.values.size(); + this.once = once; + this.okToContinue = okToContinue; + this.seed = null; + } + + public TestObservable(T seed, int size) { + values = null; + once = null; + okToContinue = null; + this.seed = seed; + this.size = size; + } + + @Override + public Subscription onSubscribe(final Observer observer) { + t = new Thread(new Runnable() { + + @Override + public void run() { + try { + while (count < size && subscribed) { + if (null != values) + observer.onNext(values.get(count)); + else + observer.onNext(seed); + count++; + //Unblock the main thread to call unsubscribe. + if (null != once) + once.countDown(); + //Block until the main thread has called unsubscribe. + if (null != okToContinue) + okToContinue.await(5, TimeUnit.SECONDS); + } + if (subscribed) + observer.onCompleted(); + } catch (InterruptedException e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + }); + t.start(); + return s; + } + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationDebounceTest.java b/rxjava-core/src/test/java/rx/operators/OperationDebounceTest.java index a1f6d4c237..2e907d8f6b 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationDebounceTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationDebounceTest.java @@ -1,7 +1,146 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.concurrency.TestScheduler; +import rx.subscriptions.Subscriptions; +import rx.util.functions.Action0; + +import java.util.concurrent.TimeUnit; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; -@Ignore("WIP") public class OperationDebounceTest { + + private TestScheduler scheduler; + private Observer observer; + + @Before + @SuppressWarnings("unchecked") + public void before() { + scheduler = new TestScheduler(); + observer = mock(Observer.class); + } + + @Test + public void testDebounceWithCompleted() { + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + publishNext(observer, 100, "one"); // Should be skipped since "two" will arrive before the timeout expires. + publishNext(observer, 400, "two"); // Should be published since "three" will arrive after the timeout expires. + publishNext(observer, 900, "three"); // Should be skipped since onCompleted will arrive before the timeout expires. + publishCompleted(observer, 1000); // Should be published as soon as the timeout expires. + + return Subscriptions.empty(); + } + }); + + Observable sampled = Observable.create(OperationDebounce.debounce(source, 400, TimeUnit.MILLISECONDS, scheduler)); + sampled.subscribe(observer); + + scheduler.advanceTimeTo(0, TimeUnit.MILLISECONDS); + InOrder inOrder = inOrder(observer); + // must go to 800 since it must be 400 after when two is sent, which is at 400 + scheduler.advanceTimeTo(800, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onNext("two"); + scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onCompleted(); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testDebounceNeverEmits() { + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + // all should be skipped since they are happening faster than the 200ms timeout + publishNext(observer, 100, "a"); // Should be skipped + publishNext(observer, 200, "b"); // Should be skipped + publishNext(observer, 300, "c"); // Should be skipped + publishNext(observer, 400, "d"); // Should be skipped + publishNext(observer, 500, "e"); // Should be skipped + publishNext(observer, 600, "f"); // Should be skipped + publishNext(observer, 700, "g"); // Should be skipped + publishNext(observer, 800, "h"); // Should be skipped + publishCompleted(observer, 900); // Should be published as soon as the timeout expires. + + return Subscriptions.empty(); + } + }); + + Observable sampled = Observable.create(OperationDebounce.debounce(source, 200, TimeUnit.MILLISECONDS, scheduler)); + sampled.subscribe(observer); + + scheduler.advanceTimeTo(0, TimeUnit.MILLISECONDS); + InOrder inOrder = inOrder(observer); + inOrder.verify(observer, times(0)).onNext(anyString()); + scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onCompleted(); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testDebounceWithError() { + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + Exception error = new TestException(); + publishNext(observer, 100, "one"); // Should be published since "two" will arrive after the timeout expires. + publishNext(observer, 600, "two"); // Should be skipped since onError will arrive before the timeout expires. + publishError(observer, 700, error); // Should be published as soon as the timeout expires. + + return Subscriptions.empty(); + } + }); + + Observable sampled = Observable.create(OperationDebounce.debounce(source, 400, TimeUnit.MILLISECONDS, scheduler)); + sampled.subscribe(observer); + + scheduler.advanceTimeTo(0, TimeUnit.MILLISECONDS); + InOrder inOrder = inOrder(observer); + // 100 + 400 means it triggers at 500 + scheduler.advanceTimeTo(500, TimeUnit.MILLISECONDS); + inOrder.verify(observer).onNext("one"); + scheduler.advanceTimeTo(701, TimeUnit.MILLISECONDS); + inOrder.verify(observer).onError(any(TestException.class)); + inOrder.verifyNoMoreInteractions(); + } + + private void publishCompleted(final Observer observer, long delay) { + scheduler.schedule(new Action0() { + @Override + public void call() { + observer.onCompleted(); + } + }, delay, TimeUnit.MILLISECONDS); + } + + private void publishError(final Observer observer, long delay, final Exception error) { + scheduler.schedule(new Action0() { + @Override + public void call() { + observer.onError(error); + } + }, delay, TimeUnit.MILLISECONDS); + } + + private void publishNext(final Observer observer, final long delay, final T value) { + scheduler.schedule(new Action0() { + @Override + public void call() { + observer.onNext(value); + } + }, delay, TimeUnit.MILLISECONDS); + } + + @SuppressWarnings("serial") + private class TestException extends Exception { + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationDefaultIfEmptyTest.java b/rxjava-core/src/test/java/rx/operators/OperationDefaultIfEmptyTest.java index 241c8790c3..fb2166dfc1 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationDefaultIfEmptyTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationDefaultIfEmptyTest.java @@ -1,7 +1,44 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Observable; +import rx.Observer; + +import static org.mockito.Mockito.*; +import static rx.operators.OperationDefaultIfEmpty.defaultIfEmpty; -@Ignore("WIP") public class OperationDefaultIfEmptyTest { + + @Test + public void testDefaultIfEmpty() { + Observable source = Observable.from(1, 2, 3); + Observable observable = Observable.create(defaultIfEmpty( + source, 10)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, never()).onNext(10); + verify(aObserver, times(1)).onNext(1); + verify(aObserver, times(1)).onNext(2); + verify(aObserver, times(1)).onNext(3); + verify(aObserver, never()).onError( + org.mockito.Matchers.any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testDefaultIfEmptyWithEmpty() { + Observable source = Observable.empty(); + Observable observable = Observable.create(defaultIfEmpty( + source, 10)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, times(1)).onNext(10); + verify(aObserver, never()).onError( + org.mockito.Matchers.any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationDeferTest.java b/rxjava-core/src/test/java/rx/operators/OperationDeferTest.java index 344cbee450..8e02b17647 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationDeferTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationDeferTest.java @@ -1,7 +1,47 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Observable; +import rx.Observer; +import rx.util.functions.Func0; + +import static org.mockito.Mockito.*; -@Ignore("WIP") public class OperationDeferTest { + + @Test + @SuppressWarnings("unchecked") + public void testDefer() throws Throwable { + + Func0> factory = mock(Func0.class); + + Observable firstObservable = Observable.from("one", "two"); + Observable secondObservable = Observable.from("three", "four"); + when(factory.call()).thenReturn(firstObservable, secondObservable); + + Observable deferred = Observable.defer(factory); + + verifyZeroInteractions(factory); + + Observer firstObserver = mock(Observer.class); + deferred.subscribe(firstObserver); + + verify(factory, times(1)).call(); + verify(firstObserver, times(1)).onNext("one"); + verify(firstObserver, times(1)).onNext("two"); + verify(firstObserver, times(0)).onNext("three"); + verify(firstObserver, times(0)).onNext("four"); + verify(firstObserver, times(1)).onCompleted(); + + Observer secondObserver = mock(Observer.class); + deferred.subscribe(secondObserver); + + verify(factory, times(2)).call(); + verify(secondObserver, times(0)).onNext("one"); + verify(secondObserver, times(0)).onNext("two"); + verify(secondObserver, times(1)).onNext("three"); + verify(secondObserver, times(1)).onNext("four"); + verify(secondObserver, times(1)).onCompleted(); + + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationDematerializeTest.java b/rxjava-core/src/test/java/rx/operators/OperationDematerializeTest.java index f0433032fb..fcc1898d4a 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationDematerializeTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationDematerializeTest.java @@ -1,7 +1,58 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Notification; +import rx.Observable; +import rx.Observer; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationDematerialize.dematerialize; -@Ignore("WIP") public class OperationDematerializeTest { + + @Test + @SuppressWarnings("unchecked") + public void testDematerialize1() { + Observable> notifications = Observable.from(1, 2).materialize(); + Observable dematerialize = notifications.dematerialize(); + + Observer aObserver = mock(Observer.class); + dematerialize.subscribe(aObserver); + + verify(aObserver, times(1)).onNext(1); + verify(aObserver, times(1)).onNext(2); + verify(aObserver, times(1)).onCompleted(); + verify(aObserver, never()).onError(any(Throwable.class)); + } + + @Test + @SuppressWarnings("unchecked") + public void testDematerialize2() { + Throwable exception = new Throwable("test"); + Observable observable = Observable.error(exception); + Observable dematerialize = Observable.create(dematerialize(observable.materialize())); + + Observer aObserver = mock(Observer.class); + dematerialize.subscribe(aObserver); + + verify(aObserver, times(1)).onError(exception); + verify(aObserver, times(0)).onCompleted(); + verify(aObserver, times(0)).onNext(any(Integer.class)); + } + + @Test + @SuppressWarnings("unchecked") + public void testDematerialize3() { + Exception exception = new Exception("test"); + Observable observable = Observable.error(exception); + Observable dematerialize = Observable.create(dematerialize(observable.materialize())); + + Observer aObserver = mock(Observer.class); + dematerialize.subscribe(aObserver); + + verify(aObserver, times(1)).onError(exception); + verify(aObserver, times(0)).onCompleted(); + verify(aObserver, times(0)).onNext(any(Integer.class)); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationDistinctTest.java b/rxjava-core/src/test/java/rx/operators/OperationDistinctTest.java index 1704b644fc..740ba9429a 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationDistinctTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationDistinctTest.java @@ -1,7 +1,182 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mock; +import rx.Observable; +import rx.Observer; +import rx.util.functions.Func1; + +import java.util.Comparator; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.never; +import static org.mockito.MockitoAnnotations.initMocks; +import static rx.Observable.*; +import static rx.operators.OperationDistinct.distinct; -@Ignore("WIP") public class OperationDistinctTest { + + @Mock + Observer w; + @Mock + Observer w2; + + // nulls lead to exceptions + final Func1 TO_UPPER_WITH_EXCEPTION = new Func1() { + @Override + public String call(String s) { + if (s.equals("x")) { + return "XX"; + } + return s.toUpperCase(); + } + }; + + final Comparator COMPARE_LENGTH = new Comparator() { + @Override + public int compare(String s1, String s2) { + return s1.length() - s2.length(); + } + }; + + @Before + public void before() { + initMocks(this); + } + + @Test + public void testDistinctOfNone() { + Observable src = empty(); + create(distinct(src)).subscribe(w); + + verify(w, never()).onNext(anyString()); + verify(w, never()).onError(any(Throwable.class)); + verify(w, times(1)).onCompleted(); + } + + @Test + public void testDistinctOfNoneWithKeySelector() { + Observable src = empty(); + create(distinct(src, TO_UPPER_WITH_EXCEPTION)).subscribe(w); + + verify(w, never()).onNext(anyString()); + verify(w, never()).onError(any(Throwable.class)); + verify(w, times(1)).onCompleted(); + } + + @Test + public void testDistinctOfNormalSource() { + Observable src = from("a", "b", "c", "c", "c", "b", "b", "a", "e"); + create(distinct(src)).subscribe(w); + + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext("a"); + inOrder.verify(w, times(1)).onNext("b"); + inOrder.verify(w, times(1)).onNext("c"); + inOrder.verify(w, times(1)).onNext("e"); + inOrder.verify(w, times(1)).onCompleted(); + inOrder.verify(w, never()).onNext(anyString()); + verify(w, never()).onError(any(Throwable.class)); + } + + @Test + public void testDistinctOfNormalSourceWithKeySelector() { + Observable src = from("a", "B", "c", "C", "c", "B", "b", "a", "E"); + create(distinct(src, TO_UPPER_WITH_EXCEPTION)).subscribe(w); + + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext("a"); + inOrder.verify(w, times(1)).onNext("B"); + inOrder.verify(w, times(1)).onNext("c"); + inOrder.verify(w, times(1)).onNext("E"); + inOrder.verify(w, times(1)).onCompleted(); + inOrder.verify(w, never()).onNext(anyString()); + verify(w, never()).onError(any(Throwable.class)); + } + + @Test + public void testDistinctOfNormalSourceWithComparator() { + Observable src = from("1", "12", "123", "aaa", "321", "12", "21", "1", "12345"); + create(distinct(src, COMPARE_LENGTH)).subscribe(w); + + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext("1"); + inOrder.verify(w, times(1)).onNext("12"); + inOrder.verify(w, times(1)).onNext("123"); + inOrder.verify(w, times(1)).onNext("12345"); + inOrder.verify(w, times(1)).onCompleted(); + inOrder.verify(w, never()).onNext(anyString()); + verify(w, never()).onError(any(Throwable.class)); + } + + @Test + public void testDistinctOfNormalSourceWithKeySelectorAndComparator() { + Observable src = from("a", "x", "ab", "abc", "cba", "de", "x", "a", "abcd"); + create(distinct(src, TO_UPPER_WITH_EXCEPTION, COMPARE_LENGTH)).subscribe(w); + + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext("a"); + inOrder.verify(w, times(1)).onNext("x"); + inOrder.verify(w, times(1)).onNext("abc"); + inOrder.verify(w, times(1)).onNext("abcd"); + inOrder.verify(w, times(1)).onCompleted(); + inOrder.verify(w, never()).onNext(anyString()); + verify(w, never()).onError(any(Throwable.class)); + } + + @Test + public void testDistinctOfNormalSourceWithKeySelectorAndComparatorAndTwoSubscriptions() { + Observable src = from("a", "x", "ab", "abc", "cba", "de", "x", "a", "abcd"); + create(distinct(src, TO_UPPER_WITH_EXCEPTION, COMPARE_LENGTH)).subscribe(w); + + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext("a"); + inOrder.verify(w, times(1)).onNext("x"); + create(distinct(src, TO_UPPER_WITH_EXCEPTION, COMPARE_LENGTH)).subscribe(w2); + inOrder.verify(w, times(1)).onNext("abc"); + inOrder.verify(w, times(1)).onNext("abcd"); + inOrder.verify(w, times(1)).onCompleted(); + inOrder.verify(w, never()).onNext(anyString()); + verify(w, never()).onError(any(Throwable.class)); + + InOrder inOrder2 = inOrder(w2); + inOrder2.verify(w2, times(1)).onNext("a"); + inOrder2.verify(w2, times(1)).onNext("x"); + inOrder2.verify(w2, times(1)).onNext("abc"); + inOrder2.verify(w2, times(1)).onNext("abcd"); + inOrder2.verify(w2, times(1)).onCompleted(); + inOrder2.verify(w2, never()).onNext(anyString()); + verify(w2, never()).onError(any(Throwable.class)); + } + + @Test + public void testDistinctOfSourceWithNulls() { + Observable src = from(null, "a", "a", null, null, "b", null); + create(distinct(src)).subscribe(w); + + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext(null); + inOrder.verify(w, times(1)).onNext("a"); + inOrder.verify(w, times(1)).onNext("b"); + inOrder.verify(w, times(1)).onCompleted(); + inOrder.verify(w, never()).onNext(anyString()); + verify(w, never()).onError(any(Throwable.class)); + } + + @Test + public void testDistinctOfSourceWithExceptionsFromKeySelector() { + Observable src = from("a", "b", null, "c"); + create(distinct(src, TO_UPPER_WITH_EXCEPTION)).subscribe(w); + + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext("a"); + inOrder.verify(w, times(1)).onNext("b"); + inOrder.verify(w, times(1)).onError(any(NullPointerException.class)); + inOrder.verify(w, never()).onNext(anyString()); + inOrder.verify(w, never()).onCompleted(); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationDistinctUntilChangedTest.java b/rxjava-core/src/test/java/rx/operators/OperationDistinctUntilChangedTest.java index cdb4eb7203..e39a123f3d 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationDistinctUntilChangedTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationDistinctUntilChangedTest.java @@ -1,7 +1,185 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mock; +import rx.Observable; +import rx.Observer; +import rx.util.functions.Func1; + +import java.util.Comparator; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.never; +import static org.mockito.MockitoAnnotations.initMocks; +import static rx.Observable.*; +import static rx.operators.OperationDistinctUntilChanged.distinctUntilChanged; -@Ignore("WIP") public class OperationDistinctUntilChangedTest { + + @Mock + Observer w; + @Mock + Observer w2; + + // nulls lead to exceptions + final Func1 TO_UPPER_WITH_EXCEPTION = new Func1() { + @Override + public String call(String s) { + if (s.equals("x")) { + return "xx"; + } + return s.toUpperCase(); + } + }; + + final Comparator COMPARE_LENGTH = new Comparator() { + @Override + public int compare(String s1, String s2) { + return s1.length() - s2.length(); + } + }; + + @Before + public void before() { + initMocks(this); + } + + @Test + public void testDistinctUntilChangedOfNone() { + Observable src = empty(); + create(distinctUntilChanged(src)).subscribe(w); + + verify(w, never()).onNext(anyString()); + verify(w, never()).onError(any(Throwable.class)); + verify(w, times(1)).onCompleted(); + } + + @Test + public void testDistinctUntilChangedOfNoneWithKeySelector() { + Observable src = empty(); + create(distinctUntilChanged(src, TO_UPPER_WITH_EXCEPTION)).subscribe(w); + + verify(w, never()).onNext(anyString()); + verify(w, never()).onError(any(Throwable.class)); + verify(w, times(1)).onCompleted(); + } + + @Test + public void testDistinctUntilChangedOfNormalSource() { + Observable src = from("a", "b", "c", "c", "c", "b", "b", "a", "e"); + create(distinctUntilChanged(src)).subscribe(w); + + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext("a"); + inOrder.verify(w, times(1)).onNext("b"); + inOrder.verify(w, times(1)).onNext("c"); + inOrder.verify(w, times(1)).onNext("b"); + inOrder.verify(w, times(1)).onNext("a"); + inOrder.verify(w, times(1)).onNext("e"); + inOrder.verify(w, times(1)).onCompleted(); + inOrder.verify(w, never()).onNext(anyString()); + verify(w, never()).onError(any(Throwable.class)); + } + + @Test + public void testDistinctUntilChangedOfNormalSourceWithKeySelector() { + Observable src = from("a", "b", "c", "C", "c", "B", "b", "a", "e"); + create(distinctUntilChanged(src, TO_UPPER_WITH_EXCEPTION)).subscribe(w); + + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext("a"); + inOrder.verify(w, times(1)).onNext("b"); + inOrder.verify(w, times(1)).onNext("c"); + inOrder.verify(w, times(1)).onNext("B"); + inOrder.verify(w, times(1)).onNext("a"); + inOrder.verify(w, times(1)).onNext("e"); + inOrder.verify(w, times(1)).onCompleted(); + inOrder.verify(w, never()).onNext(anyString()); + verify(w, never()).onError(any(Throwable.class)); + } + + @Test + public void testDistinctUntilChangedOfSourceWithNulls() { + Observable src = from(null, "a", "a", null, null, "b", null, null); + create(distinctUntilChanged(src)).subscribe(w); + + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext(null); + inOrder.verify(w, times(1)).onNext("a"); + inOrder.verify(w, times(1)).onNext(null); + inOrder.verify(w, times(1)).onNext("b"); + inOrder.verify(w, times(1)).onNext(null); + inOrder.verify(w, times(1)).onCompleted(); + inOrder.verify(w, never()).onNext(anyString()); + verify(w, never()).onError(any(Throwable.class)); + } + + @Test + public void testDistinctUntilChangedOfSourceWithExceptionsFromKeySelector() { + Observable src = from("a", "b", null, "c"); + create(distinctUntilChanged(src, TO_UPPER_WITH_EXCEPTION)).subscribe(w); + + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext("a"); + inOrder.verify(w, times(1)).onNext("b"); + verify(w, times(1)).onError(any(NullPointerException.class)); + inOrder.verify(w, never()).onNext(anyString()); + inOrder.verify(w, never()).onCompleted(); + } + + @Test + public void testDistinctUntilChangedWithComparator() { + Observable src = from("a", "b", "c", "aa", "bb", "c", "ddd"); + create(distinctUntilChanged(src, COMPARE_LENGTH)).subscribe(w); + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext("a"); + inOrder.verify(w, times(1)).onNext("aa"); + inOrder.verify(w, times(1)).onNext("c"); + inOrder.verify(w, times(1)).onNext("ddd"); + inOrder.verify(w, times(1)).onCompleted(); + inOrder.verify(w, never()).onNext(anyString()); + verify(w, never()).onError(any(Throwable.class)); + } + + @Test + public void testDistinctUntilChangedWithComparatorAndKeySelector() { + Observable src = from("a", "b", "x", "aa", "bb", "c", "ddd"); + create(distinctUntilChanged(src, TO_UPPER_WITH_EXCEPTION, COMPARE_LENGTH)).subscribe(w); + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext("a"); + inOrder.verify(w, times(1)).onNext("x"); + inOrder.verify(w, times(1)).onNext("c"); + inOrder.verify(w, times(1)).onNext("ddd"); + inOrder.verify(w, times(1)).onCompleted(); + inOrder.verify(w, never()).onNext(anyString()); + verify(w, never()).onError(any(Throwable.class)); + } + + @Test + public void testDistinctUntilChangedWithComparatorAndKeySelectorandTwoSubscriptions() { + Observable src = from("a", "b", "x", "aa", "bb", "c", "ddd"); + create(distinctUntilChanged(src, TO_UPPER_WITH_EXCEPTION, COMPARE_LENGTH)).subscribe(w); + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext("a"); + inOrder.verify(w, times(1)).onNext("x"); + create(distinctUntilChanged(src, TO_UPPER_WITH_EXCEPTION, COMPARE_LENGTH)).subscribe(w2); + inOrder.verify(w, times(1)).onNext("c"); + inOrder.verify(w, times(1)).onNext("ddd"); + inOrder.verify(w, times(1)).onCompleted(); + inOrder.verify(w, never()).onNext(anyString()); + verify(w, never()).onError(any(Throwable.class)); + + InOrder inOrder2 = inOrder(w2); + inOrder2.verify(w2, times(1)).onNext("a"); + inOrder2.verify(w2, times(1)).onNext("x"); + inOrder2.verify(w2, times(1)).onNext("c"); + inOrder2.verify(w2, times(1)).onNext("ddd"); + inOrder2.verify(w2, times(1)).onCompleted(); + inOrder2.verify(w2, never()).onNext(anyString()); + verify(w2, never()).onError(any(Throwable.class)); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationElementAtTest.java b/rxjava-core/src/test/java/rx/operators/OperationElementAtTest.java index b17efa3cd3..4f1326df06 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationElementAtTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationElementAtTest.java @@ -1,7 +1,113 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Observable; +import rx.Observer; + +import java.util.Iterator; +import java.util.concurrent.ExecutionException; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationElementAt.elementAt; +import static rx.operators.OperationElementAt.elementAtOrDefault; -@Ignore("WIP") public class OperationElementAtTest { + + @Test + public void testElementAt() { + Observable w = Observable.from(1, 2); + Observable observable = Observable.create(elementAt(w, 1)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, never()).onNext(1); + verify(aObserver, times(1)).onNext(2); + verify(aObserver, never()).onError( + any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testElementAtWithMinusIndex() { + Observable w = Observable.from(1, 2); + Observable observable = Observable + .create(elementAt(w, -1)); + + try { + Iterator iter = OperationToIterator + .toIterator(observable); + assertTrue(iter.hasNext()); + iter.next(); + fail("expect an IndexOutOfBoundsException when index is out of bounds"); + } catch (IndexOutOfBoundsException e) { + } + } + + @Test + public void testElementAtWithIndexOutOfBounds() + throws InterruptedException, ExecutionException { + Observable w = Observable.from(1, 2); + Observable observable = Observable.create(elementAt(w, 2)); + try { + Iterator iter = OperationToIterator + .toIterator(observable); + assertTrue(iter.hasNext()); + iter.next(); + fail("expect an IndexOutOfBoundsException when index is out of bounds"); + } catch (IndexOutOfBoundsException e) { + } + } + + @Test + public void testElementAtOrDefault() throws InterruptedException, + ExecutionException { + Observable w = Observable.from(1, 2); + Observable observable = Observable + .create(elementAtOrDefault(w, 1, 0)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, never()).onNext(1); + verify(aObserver, times(1)).onNext(2); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testElementAtOrDefaultWithIndexOutOfBounds() + throws InterruptedException, ExecutionException { + Observable w = Observable.from(1, 2); + Observable observable = Observable + .create(elementAtOrDefault(w, 2, 0)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, never()).onNext(1); + verify(aObserver, never()).onNext(2); + verify(aObserver, times(1)).onNext(0); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testElementAtOrDefaultWithMinusIndex() { + Observable w = Observable.from(1, 2); + Observable observable = Observable + .create(elementAtOrDefault(w, -1, 0)); + + try { + Iterator iter = OperationToIterator + .toIterator(observable); + assertTrue(iter.hasNext()); + iter.next(); + fail("expect an IndexOutOfBoundsException when index is out of bounds"); + } catch (IndexOutOfBoundsException e) { + } + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationFilterTest.java b/rxjava-core/src/test/java/rx/operators/OperationFilterTest.java index 19e15ea81a..a6da7261e1 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationFilterTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationFilterTest.java @@ -1,7 +1,35 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.Mockito; +import rx.Observable; +import rx.Observer; +import rx.util.functions.Func1; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationFilter.filter; -@Ignore("WIP") public class OperationFilterTest { + + @Test + public void testFilter() { + Observable w = Observable.from("one", "two", "three"); + Observable observable = Observable.create(filter(w, new Func1() { + + @Override + public Boolean call(String t1) { + return t1.equals("two"); + } + })); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, Mockito.never()).onNext("one"); + verify(aObserver, times(1)).onNext("two"); + verify(aObserver, Mockito.never()).onNext("three"); + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationFinallyTest.java b/rxjava-core/src/test/java/rx/operators/OperationFinallyTest.java index 0e46ce1cb2..b856c86fa6 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationFinallyTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationFinallyTest.java @@ -1,7 +1,38 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Before; +import org.junit.Test; +import rx.Observable; +import rx.Observer; +import rx.util.functions.Action0; + +import static org.mockito.Mockito.*; +import static rx.operators.OperationFinally.finallyDo; -@Ignore("WIP") public class OperationFinallyTest { + + private Action0 aAction0; + private Observer aObserver; + + @SuppressWarnings("unchecked") // mocking has to be unchecked, unfortunately + @Before + public void before() { + aAction0 = mock(Action0.class); + aObserver = mock(Observer.class); + } + + private void checkActionCalled(Observable input) { + Observable.create(finallyDo(input, aAction0)).subscribe(aObserver); + verify(aAction0, times(1)).call(); + } + + @Test + public void testFinallyCalledOnComplete() { + checkActionCalled(Observable.from(new String[]{"1", "2", "3"})); + } + + @Test + public void testFinallyCalledOnError() { + checkActionCalled(Observable.error(new RuntimeException("expected"))); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationFirstOrDefaultTest.java b/rxjava-core/src/test/java/rx/operators/OperationFirstOrDefaultTest.java index 39a60a03c5..344ab98578 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationFirstOrDefaultTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationFirstOrDefaultTest.java @@ -1,7 +1,78 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import rx.Observable; +import rx.Observer; +import rx.util.functions.Func1; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.*; +import static org.mockito.MockitoAnnotations.initMocks; +import static rx.Observable.*; +import static rx.operators.OperationFirstOrDefault.firstOrDefault; -@Ignore("WIP") public class OperationFirstOrDefaultTest { + + @Mock + Observer w; + + private static final Func1 IS_D = new Func1() { + @Override + public Boolean call(String value) { + return "d".equals(value); + } + }; + + @Before + public void before() { + initMocks(this); + } + + @Test + public void testFirstOrElseOfNone() { + Observable src = empty(); + create(firstOrDefault(src, "default")).subscribe(w); + + verify(w, times(1)).onNext(anyString()); + verify(w, times(1)).onNext("default"); + verify(w, never()).onError(any(Throwable.class)); + verify(w, times(1)).onCompleted(); + } + + @Test + public void testFirstOrElseOfSome() { + Observable src = from("a", "b", "c"); + create(firstOrDefault(src, "default")).subscribe(w); + + verify(w, times(1)).onNext(anyString()); + verify(w, times(1)).onNext("a"); + verify(w, never()).onError(any(Throwable.class)); + verify(w, times(1)).onCompleted(); + } + + @Test + public void testFirstOrElseWithPredicateOfNoneMatchingThePredicate() { + Observable src = from("a", "b", "c"); + create(firstOrDefault(src, IS_D, "default")).subscribe(w); + + verify(w, times(1)).onNext(anyString()); + verify(w, times(1)).onNext("default"); + verify(w, never()).onError(any(Throwable.class)); + verify(w, times(1)).onCompleted(); + } + + @Test + public void testFirstOrElseWithPredicateOfSome() { + Observable src = from("a", "b", "c", "d", "e", "f"); + create(firstOrDefault(src, IS_D, "default")).subscribe(w); + + verify(w, times(1)).onNext(anyString()); + verify(w, times(1)).onNext("d"); + verify(w, never()).onError(any(Throwable.class)); + verify(w, times(1)).onCompleted(); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationGroupByTest.java b/rxjava-core/src/test/java/rx/operators/OperationGroupByTest.java index 222085a96f..e62be97d11 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationGroupByTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationGroupByTest.java @@ -1,7 +1,331 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.observables.GroupedObservable; +import rx.subscriptions.BooleanSubscription; +import rx.subscriptions.Subscriptions; +import rx.util.functions.Action1; +import rx.util.functions.Func1; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.Assert.*; +import static rx.operators.OperationGroupBy.groupBy; -@Ignore("WIP") public class OperationGroupByTest { + + final Func1 length = new Func1() { + @Override + public Integer call(String s) { + return s.length(); + } + }; + + @Test + public void testGroupBy() { + Observable source = Observable.from("one", "two", "three", "four", "five", "six"); + Observable> grouped = Observable.create(groupBy(source, length)); + + Map> map = toMap(grouped); + + assertEquals(3, map.size()); + assertArrayEquals(Arrays.asList("one", "two", "six").toArray(), map.get(3).toArray()); + assertArrayEquals(Arrays.asList("four", "five").toArray(), map.get(4).toArray()); + assertArrayEquals(Arrays.asList("three").toArray(), map.get(5).toArray()); + } + + @Test + public void testEmpty() { + Observable source = Observable.empty(); + Observable> grouped = Observable.create(groupBy(source, length)); + + Map> map = toMap(grouped); + + assertTrue(map.isEmpty()); + } + + @Test + public void testError() { + Observable sourceStrings = Observable.from("one", "two", "three", "four", "five", "six"); + Observable errorSource = Observable.error(new RuntimeException("forced failure")); + Observable source = Observable.concat(sourceStrings, errorSource); + + Observable> grouped = Observable.create(groupBy(source, length)); + + final AtomicInteger groupCounter = new AtomicInteger(); + final AtomicInteger eventCounter = new AtomicInteger(); + final AtomicReference error = new AtomicReference(); + + grouped.mapMany(new Func1, Observable>() { + + @Override + public Observable call(final GroupedObservable o) { + groupCounter.incrementAndGet(); + return o.map(new Func1() { + + @Override + public String call(String v) { + return "Event => key: " + o.getKey() + " value: " + v; + } + }); + } + }).subscribe(new Observer() { + + @Override + public void onCompleted() { + + } + + @Override + public void onError(Throwable e) { + e.printStackTrace(); + error.set(e); + } + + @Override + public void onNext(String v) { + eventCounter.incrementAndGet(); + System.out.println(v); + + } + }); + + assertEquals(3, groupCounter.get()); + assertEquals(6, eventCounter.get()); + assertNotNull(error.get()); + } + + private static Map> toMap(Observable> observable) { + + final ConcurrentHashMap> result = new ConcurrentHashMap>(); + + observable.toBlockingObservable().forEach(new Action1>() { + + @Override + public void call(final GroupedObservable o) { + result.put(o.getKey(), new ConcurrentLinkedQueue()); + o.subscribe(new Action1() { + + @Override + public void call(V v) { + result.get(o.getKey()).add(v); + } + + }); + } + }); + + return result; + } + + /** + * Assert that only a single subscription to a stream occurs and that all events are received. + * + * @throws Throwable + */ + @Test + public void testGroupedEventStream() throws Throwable { + + final AtomicInteger eventCounter = new AtomicInteger(); + final AtomicInteger subscribeCounter = new AtomicInteger(); + final AtomicInteger groupCounter = new AtomicInteger(); + final CountDownLatch latch = new CountDownLatch(1); + final int count = 100; + final int groupCount = 2; + + Observable es = Observable.create(new Observable.OnSubscribeFunc() { + + @Override + public Subscription onSubscribe(final Observer observer) { + System.out.println("*** Subscribing to EventStream ***"); + subscribeCounter.incrementAndGet(); + new Thread(new Runnable() { + + @Override + public void run() { + for (int i = 0; i < count; i++) { + Event e = new Event(); + e.source = i % groupCount; + e.message = "Event-" + i; + observer.onNext(e); + } + observer.onCompleted(); + } + + }).start(); + return Subscriptions.empty(); + } + + }); + + es.groupBy(new Func1() { + + @Override + public Integer call(Event e) { + return e.source; + } + }).mapMany(new Func1, Observable>() { + + @Override + public Observable call(GroupedObservable eventGroupedObservable) { + System.out.println("GroupedObservable Key: " + eventGroupedObservable.getKey()); + groupCounter.incrementAndGet(); + + return eventGroupedObservable.map(new Func1() { + + @Override + public String call(Event event) { + return "Source: " + event.source + " Message: " + event.message; + } + }); + + } + }).subscribe(new Observer() { + + @Override + public void onCompleted() { + latch.countDown(); + } + + @Override + public void onError(Throwable e) { + e.printStackTrace(); + latch.countDown(); + } + + @Override + public void onNext(String outputMessage) { + System.out.println(outputMessage); + eventCounter.incrementAndGet(); + } + }); + + latch.await(5000, TimeUnit.MILLISECONDS); + assertEquals(1, subscribeCounter.get()); + assertEquals(groupCount, groupCounter.get()); + assertEquals(count, eventCounter.get()); + + } + + /* + * We will only take 1 group with 20 events from it and then unsubscribe. + */ + @Test + public void testUnsubscribe() throws InterruptedException { + + final AtomicInteger eventCounter = new AtomicInteger(); + final AtomicInteger subscribeCounter = new AtomicInteger(); + final AtomicInteger groupCounter = new AtomicInteger(); + final AtomicInteger sentEventCounter = new AtomicInteger(); + final CountDownLatch latch = new CountDownLatch(1); + final int count = 100; + final int groupCount = 2; + + Observable es = Observable.create(new Observable.OnSubscribeFunc() { + + @Override + public Subscription onSubscribe(final Observer observer) { + final BooleanSubscription s = new BooleanSubscription(); + System.out.println("testUnsubscribe => *** Subscribing to EventStream ***"); + subscribeCounter.incrementAndGet(); + new Thread(new Runnable() { + + @Override + public void run() { + for (int i = 0; i < count; i++) { + if (s.isUnsubscribed()) { + break; + } + Event e = new Event(); + e.source = i % groupCount; + e.message = "Event-" + i; + observer.onNext(e); + sentEventCounter.incrementAndGet(); + } + observer.onCompleted(); + } + + }).start(); + return s; + } + + }); + + es.groupBy(new Func1() { + + @Override + public Integer call(Event e) { + return e.source; + } + }) + .take(1) // we want only the first group + .mapMany(new Func1, Observable>() { + + @Override + public Observable call(GroupedObservable eventGroupedObservable) { + System.out.println("testUnsubscribe => GroupedObservable Key: " + eventGroupedObservable.getKey()); + groupCounter.incrementAndGet(); + + return eventGroupedObservable + .take(20) // limit to only 20 events on this group + .map(new Func1() { + + @Override + public String call(Event event) { + return "testUnsubscribe => Source: " + event.source + " Message: " + event.message; + } + }); + + } + }).subscribe(new Observer() { + + @Override + public void onCompleted() { + latch.countDown(); + } + + @Override + public void onError(Throwable e) { + e.printStackTrace(); + latch.countDown(); + } + + @Override + public void onNext(String outputMessage) { + System.out.println(outputMessage); + eventCounter.incrementAndGet(); + } + }); + + latch.await(5000, TimeUnit.MILLISECONDS); + assertEquals(1, subscribeCounter.get()); + assertEquals(1, groupCounter.get()); + assertEquals(20, eventCounter.get()); + // sentEvents will go until 'eventCounter' hits 20 and then unsubscribes + // which means it will also send (but ignore) the 19/20 events for the other group + // It will not however send all 100 events. + assertEquals(39, sentEventCounter.get(), 10); + // gave it a delta of 10 to account for the threading/unsubscription race condition which can vary depending on a machines performance, thread-scheduler, etc + } + + private static class Event { + int source; + String message; + + @Override + public String toString() { + return "Event => source: " + source + " message: " + message; + } + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationIntervalTest.java b/rxjava-core/src/test/java/rx/operators/OperationIntervalTest.java index 60b2ad7789..0ffd27c85b 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationIntervalTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationIntervalTest.java @@ -1,7 +1,176 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.concurrency.TestScheduler; +import rx.observables.ConnectableObservable; + +import java.util.concurrent.TimeUnit; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Mockito.*; -@Ignore("WIP") public class OperationIntervalTest { + + private TestScheduler scheduler; + private Observer observer; + private Observer observer2; + + @Before + @SuppressWarnings("unchecked") // due to mocking + public void before() { + scheduler = new TestScheduler(); + observer = mock(Observer.class); + observer2 = mock(Observer.class); + } + + @Test + public void testInterval() { + Observable w = Observable.create(OperationInterval.interval(1, TimeUnit.SECONDS, scheduler)); + Subscription sub = w.subscribe(observer); + + verify(observer, never()).onNext(0L); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + scheduler.advanceTimeTo(2, TimeUnit.SECONDS); + + InOrder inOrder = inOrder(observer); + inOrder.verify(observer, times(1)).onNext(0L); + inOrder.verify(observer, times(1)).onNext(1L); + inOrder.verify(observer, never()).onNext(2L); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + sub.unsubscribe(); + scheduler.advanceTimeTo(4, TimeUnit.SECONDS); + verify(observer, never()).onNext(2L); + verify(observer, times(1)).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + } + + @Test + public void testWithMultipleSubscribersStartingAtSameTime() { + Observable w = Observable.create(OperationInterval.interval(1, TimeUnit.SECONDS, scheduler)); + Subscription sub1 = w.subscribe(observer); + Subscription sub2 = w.subscribe(observer2); + + verify(observer, never()).onNext(anyLong()); + verify(observer2, never()).onNext(anyLong()); + + scheduler.advanceTimeTo(2, TimeUnit.SECONDS); + + InOrder inOrder1 = inOrder(observer); + InOrder inOrder2 = inOrder(observer2); + + inOrder1.verify(observer, times(1)).onNext(0L); + inOrder1.verify(observer, times(1)).onNext(1L); + inOrder1.verify(observer, never()).onNext(2L); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + inOrder2.verify(observer2, times(1)).onNext(0L); + inOrder2.verify(observer2, times(1)).onNext(1L); + inOrder2.verify(observer2, never()).onNext(2L); + verify(observer2, never()).onCompleted(); + verify(observer2, never()).onError(any(Throwable.class)); + + sub1.unsubscribe(); + sub2.unsubscribe(); + scheduler.advanceTimeTo(4, TimeUnit.SECONDS); + + verify(observer, never()).onNext(2L); + verify(observer, times(1)).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + verify(observer2, never()).onNext(2L); + verify(observer2, times(1)).onCompleted(); + verify(observer2, never()).onError(any(Throwable.class)); + } + + @Test + public void testWithMultipleStaggeredSubscribers() { + Observable w = Observable.create(OperationInterval.interval(1, TimeUnit.SECONDS, scheduler)); + Subscription sub1 = w.subscribe(observer); + + verify(observer, never()).onNext(anyLong()); + + scheduler.advanceTimeTo(2, TimeUnit.SECONDS); + Subscription sub2 = w.subscribe(observer2); + + InOrder inOrder1 = inOrder(observer); + inOrder1.verify(observer, times(1)).onNext(0L); + inOrder1.verify(observer, times(1)).onNext(1L); + inOrder1.verify(observer, never()).onNext(2L); + + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + verify(observer2, never()).onNext(anyLong()); + + scheduler.advanceTimeTo(4, TimeUnit.SECONDS); + + inOrder1.verify(observer, times(1)).onNext(2L); + inOrder1.verify(observer, times(1)).onNext(3L); + + InOrder inOrder2 = inOrder(observer2); + inOrder2.verify(observer2, times(1)).onNext(0L); + inOrder2.verify(observer2, times(1)).onNext(1L); + + sub1.unsubscribe(); + sub2.unsubscribe(); + + inOrder1.verify(observer, never()).onNext(anyLong()); + inOrder1.verify(observer, times(1)).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + inOrder2.verify(observer2, never()).onNext(anyLong()); + inOrder2.verify(observer2, times(1)).onCompleted(); + verify(observer2, never()).onError(any(Throwable.class)); + } + + @Test + public void testWithMultipleStaggeredSubscribersAndPublish() { + ConnectableObservable w = Observable.create(OperationInterval.interval(1, TimeUnit.SECONDS, scheduler)).publish(); + Subscription sub1 = w.subscribe(observer); + w.connect(); + + verify(observer, never()).onNext(anyLong()); + + scheduler.advanceTimeTo(2, TimeUnit.SECONDS); + Subscription sub2 = w.subscribe(observer2); + + InOrder inOrder1 = inOrder(observer); + inOrder1.verify(observer, times(1)).onNext(0L); + inOrder1.verify(observer, times(1)).onNext(1L); + inOrder1.verify(observer, never()).onNext(2L); + + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + verify(observer2, never()).onNext(anyLong()); + + scheduler.advanceTimeTo(4, TimeUnit.SECONDS); + + inOrder1.verify(observer, times(1)).onNext(2L); + inOrder1.verify(observer, times(1)).onNext(3L); + + InOrder inOrder2 = inOrder(observer2); + inOrder2.verify(observer2, times(1)).onNext(2L); + inOrder2.verify(observer2, times(1)).onNext(3L); + + sub1.unsubscribe(); + sub2.unsubscribe(); + + inOrder1.verify(observer, never()).onNext(anyLong()); + inOrder1.verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + inOrder2.verify(observer2, never()).onNext(anyLong()); + inOrder2.verify(observer2, never()).onCompleted(); + verify(observer2, never()).onError(any(Throwable.class)); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationMapTest.java b/rxjava-core/src/test/java/rx/operators/OperationMapTest.java index 3c3ee5813c..cfd081112e 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationMapTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationMapTest.java @@ -1,7 +1,276 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import rx.Observable; +import rx.Observer; +import rx.concurrency.Schedulers; +import rx.util.functions.Func1; +import rx.util.functions.Func2; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationMap.*; -@Ignore("WIP") public class OperationMapTest { + + @Mock + Observer stringObserver; + @Mock + Observer stringObserver2; + + final static Func2 APPEND_INDEX = new Func2() { + @Override + public String call(String value, Integer index) { + return value + index; + } + }; + + @Before + public void before() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testMap() { + Map m1 = getMap("One"); + Map m2 = getMap("Two"); + Observable> observable = Observable.from(m1, m2); + + Observable m = Observable.create(map(observable, new Func1, String>() { + + @Override + public String call(Map map) { + return map.get("firstName"); + } + + })); + m.subscribe(stringObserver); + + verify(stringObserver, never()).onError(any(Throwable.class)); + verify(stringObserver, times(1)).onNext("OneFirst"); + verify(stringObserver, times(1)).onNext("TwoFirst"); + verify(stringObserver, times(1)).onCompleted(); + } + + @Test + public void testMapWithIndex() { + Observable w = Observable.from("a", "b", "c"); + Observable m = Observable.create(mapWithIndex(w, APPEND_INDEX)); + m.subscribe(stringObserver); + InOrder inOrder = inOrder(stringObserver); + inOrder.verify(stringObserver, times(1)).onNext("a0"); + inOrder.verify(stringObserver, times(1)).onNext("b1"); + inOrder.verify(stringObserver, times(1)).onNext("c2"); + inOrder.verify(stringObserver, times(1)).onCompleted(); + verify(stringObserver, never()).onError(any(Throwable.class)); + } + + @Test + public void testMapWithIndexAndMultipleSubscribers() { + Observable w = Observable.from("a", "b", "c"); + Observable m = Observable.create(mapWithIndex(w, APPEND_INDEX)); + m.subscribe(stringObserver); + m.subscribe(stringObserver2); + InOrder inOrder = inOrder(stringObserver); + inOrder.verify(stringObserver, times(1)).onNext("a0"); + inOrder.verify(stringObserver, times(1)).onNext("b1"); + inOrder.verify(stringObserver, times(1)).onNext("c2"); + inOrder.verify(stringObserver, times(1)).onCompleted(); + verify(stringObserver, never()).onError(any(Throwable.class)); + + InOrder inOrder2 = inOrder(stringObserver2); + inOrder2.verify(stringObserver2, times(1)).onNext("a0"); + inOrder2.verify(stringObserver2, times(1)).onNext("b1"); + inOrder2.verify(stringObserver2, times(1)).onNext("c2"); + inOrder2.verify(stringObserver2, times(1)).onCompleted(); + verify(stringObserver2, never()).onError(any(Throwable.class)); + } + + @Test + public void testMapMany() { + /* simulate a top-level async call which returns IDs */ + Observable ids = Observable.from(1, 2); + + /* now simulate the behavior to take those IDs and perform nested async calls based on them */ + Observable m = Observable.create(mapMany(ids, new Func1>() { + + @Override + public Observable call(Integer id) { + /* simulate making a nested async call which creates another Observable */ + Observable> subObservable = null; + if (id == 1) { + Map m1 = getMap("One"); + Map m2 = getMap("Two"); + subObservable = Observable.from(m1, m2); + } else { + Map m3 = getMap("Three"); + Map m4 = getMap("Four"); + subObservable = Observable.from(m3, m4); + } + + /* simulate kicking off the async call and performing a select on it to transform the data */ + return Observable.create(map(subObservable, new Func1, String>() { + @Override + public String call(Map map) { + return map.get("firstName"); + } + })); + } + + })); + m.subscribe(stringObserver); + + verify(stringObserver, never()).onError(any(Throwable.class)); + verify(stringObserver, times(1)).onNext("OneFirst"); + verify(stringObserver, times(1)).onNext("TwoFirst"); + verify(stringObserver, times(1)).onNext("ThreeFirst"); + verify(stringObserver, times(1)).onNext("FourFirst"); + verify(stringObserver, times(1)).onCompleted(); + } + + @Test + public void testMapMany2() { + Map m1 = getMap("One"); + Map m2 = getMap("Two"); + Observable> observable1 = Observable.from(m1, m2); + + Map m3 = getMap("Three"); + Map m4 = getMap("Four"); + Observable> observable2 = Observable.from(m3, m4); + + Observable>> observable = Observable.from(observable1, observable2); + + Observable m = Observable.create(mapMany(observable, new Func1>, Observable>() { + + @Override + public Observable call(Observable> o) { + return Observable.create(map(o, new Func1, String>() { + + @Override + public String call(Map map) { + return map.get("firstName"); + } + })); + } + + })); + m.subscribe(stringObserver); + + verify(stringObserver, never()).onError(any(Throwable.class)); + verify(stringObserver, times(1)).onNext("OneFirst"); + verify(stringObserver, times(1)).onNext("TwoFirst"); + verify(stringObserver, times(1)).onNext("ThreeFirst"); + verify(stringObserver, times(1)).onNext("FourFirst"); + verify(stringObserver, times(1)).onCompleted(); + + } + + @Test + public void testMapWithError() { + Observable w = Observable.from("one", "fail", "two", "three", "fail"); + Observable m = Observable.create(map(w, new Func1() { + @Override + public String call(String s) { + if ("fail".equals(s)) { + throw new RuntimeException("Forced Failure"); + } + return s; + } + })); + + m.subscribe(stringObserver); + verify(stringObserver, times(1)).onNext("one"); + verify(stringObserver, never()).onNext("two"); + verify(stringObserver, never()).onNext("three"); + verify(stringObserver, never()).onCompleted(); + verify(stringObserver, times(1)).onError(any(Throwable.class)); + } + + @Test + public void testMapWithSynchronousObservableContainingError() { + Observable w = Observable.from("one", "fail", "two", "three", "fail"); + final AtomicInteger c1 = new AtomicInteger(); + final AtomicInteger c2 = new AtomicInteger(); + Observable m = Observable.create(map(w, new Func1() { + @Override + public String call(String s) { + if ("fail".equals(s)) + throw new RuntimeException("Forced Failure"); + System.out.println("BadMapper:" + s); + c1.incrementAndGet(); + return s; + } + })).map(new Func1() { + @Override + public String call(String s) { + System.out.println("SecondMapper:" + s); + c2.incrementAndGet(); + return s; + } + }); + + m.subscribe(stringObserver); + + verify(stringObserver, times(1)).onNext("one"); + verify(stringObserver, never()).onNext("two"); + verify(stringObserver, never()).onNext("three"); + verify(stringObserver, never()).onCompleted(); + verify(stringObserver, times(1)).onError(any(Throwable.class)); + + // we should have only returned 1 value: "one" + assertEquals(1, c1.get()); + assertEquals(1, c2.get()); + } + + @Test(expected = IllegalArgumentException.class) + public void testMapWithIssue417() { + Observable.from(1).observeOn(Schedulers.threadPoolForComputation()) + .map(new Func1() { + public Integer call(Integer arg0) { + throw new IllegalArgumentException("any error"); + } + }).toBlockingObservable().single(); + } + + @Test + public void testMapWithErrorInFuncAndThreadPoolScheduler() throws InterruptedException { + // The error will throw in one of threads in the thread pool. + // If map does not handle it, the error will disappear. + // so map needs to handle the error by itself. + final CountDownLatch latch = new CountDownLatch(1); + Observable m = Observable.from("one") + .observeOn(Schedulers.threadPoolForComputation()) + .map(new Func1() { + public String call(String arg0) { + try { + throw new IllegalArgumentException("any error"); + } finally { + latch.countDown(); + } + } + }); + + m.subscribe(stringObserver); + latch.await(); + InOrder inorder = inOrder(stringObserver); + inorder.verify(stringObserver, times(1)).onError(any(IllegalArgumentException.class)); + inorder.verifyNoMoreInteractions(); + } + + private static Map getMap(String prefix) { + Map m = new HashMap(); + m.put("firstName", prefix + "First"); + m.put("lastName", prefix + "Last"); + return m; + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationMaterializeTest.java b/rxjava-core/src/test/java/rx/operators/OperationMaterializeTest.java index 24f67b432c..f7f4142672 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationMaterializeTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationMaterializeTest.java @@ -1,7 +1,150 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Notification; +import rx.Observable; +import rx.Observer; +import rx.Subscription; + +import java.util.List; +import java.util.Vector; +import java.util.concurrent.ExecutionException; + +import static org.junit.Assert.*; +import static rx.operators.OperationMaterialize.materialize; -@Ignore("WIP") public class OperationMaterializeTest { + + @Test + public void testMaterialize1() { + // null will cause onError to be triggered before "three" can be returned + final TestAsyncErrorObservable o1 = new TestAsyncErrorObservable("one", "two", null, "three"); + + TestObserver Observer = new TestObserver(); + Observable> m = Observable.create(materialize(Observable.create(o1))); + m.subscribe(Observer); + + try { + o1.t.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + assertFalse(Observer.onError); + assertTrue(Observer.onCompleted); + assertEquals(3, Observer.notifications.size()); + assertEquals("one", Observer.notifications.get(0).getValue()); + assertTrue(Observer.notifications.get(0).isOnNext()); + assertEquals("two", Observer.notifications.get(1).getValue()); + assertTrue(Observer.notifications.get(1).isOnNext()); + assertEquals(NullPointerException.class, Observer.notifications.get(2).getThrowable().getClass()); + assertTrue(Observer.notifications.get(2).isOnError()); + } + + @Test + public void testMaterialize2() { + final TestAsyncErrorObservable o1 = new TestAsyncErrorObservable("one", "two", "three"); + + TestObserver Observer = new TestObserver(); + Observable> m = Observable.create(materialize(Observable.create(o1))); + m.subscribe(Observer); + + try { + o1.t.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + assertFalse(Observer.onError); + assertTrue(Observer.onCompleted); + assertEquals(4, Observer.notifications.size()); + assertEquals("one", Observer.notifications.get(0).getValue()); + assertTrue(Observer.notifications.get(0).isOnNext()); + assertEquals("two", Observer.notifications.get(1).getValue()); + assertTrue(Observer.notifications.get(1).isOnNext()); + assertEquals("three", Observer.notifications.get(2).getValue()); + assertTrue(Observer.notifications.get(2).isOnNext()); + assertTrue(Observer.notifications.get(3).isOnCompleted()); + } + + @Test + public void testMultipleSubscribes() throws InterruptedException, ExecutionException { + final TestAsyncErrorObservable o = new TestAsyncErrorObservable("one", "two", null, "three"); + + Observable> m = Observable.create(materialize(Observable.create(o))); + + assertEquals(3, m.toList().toBlockingObservable().toFuture().get().size()); + assertEquals(3, m.toList().toBlockingObservable().toFuture().get().size()); + } + + private static class TestObserver implements Observer> { + + boolean onCompleted = false; + boolean onError = false; + List> notifications = new Vector>(); + + @Override + public void onCompleted() { + this.onCompleted = true; + } + + @Override + public void onError(Throwable e) { + this.onError = true; + } + + @Override + public void onNext(Notification value) { + this.notifications.add(value); + } + + } + + private static class TestAsyncErrorObservable implements Observable.OnSubscribeFunc { + + String[] valuesToReturn; + + TestAsyncErrorObservable(String... values) { + valuesToReturn = values; + } + + volatile Thread t; + + @Override + public Subscription onSubscribe(final Observer observer) { + t = new Thread(new Runnable() { + + @Override + public void run() { + for (String s : valuesToReturn) { + if (s == null) { + System.out.println("throwing exception"); + try { + Thread.sleep(100); + } catch (Throwable e) { + + } + observer.onError(new NullPointerException()); + return; + } else { + observer.onNext(s); + } + } + System.out.println("subscription complete"); + observer.onCompleted(); + } + + }); + t.start(); + + return new Subscription() { + + @Override + public void unsubscribe() { + + } + + }; + } + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationMergeDelayErrorTest.java b/rxjava-core/src/test/java/rx/operators/OperationMergeDelayErrorTest.java index 1e3c763573..03dbcd7044 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationMergeDelayErrorTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationMergeDelayErrorTest.java @@ -1,7 +1,500 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.util.CompositeException; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationMergeDelayError.mergeDelayError; -@Ignore("WIP") public class OperationMergeDelayErrorTest { + + + @Mock + Observer stringObserver; + + @Before + public void before() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testErrorDelayed1() { + final Observable o1 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" from the source (and it should never be sent by the source since onError was called + final Observable o2 = Observable.create(new TestErrorObservable("one", "two", "three")); + + @SuppressWarnings("unchecked") + Observable m = Observable.create(mergeDelayError(o1, o2)); + m.subscribe(stringObserver); + + verify(stringObserver, times(1)).onError(any(NullPointerException.class)); + verify(stringObserver, never()).onCompleted(); + verify(stringObserver, times(1)).onNext("one"); + verify(stringObserver, times(1)).onNext("two"); + verify(stringObserver, times(1)).onNext("three"); + verify(stringObserver, times(1)).onNext("four"); + verify(stringObserver, times(0)).onNext("five"); + verify(stringObserver, times(0)).onNext("six"); + } + + @Test + public void testErrorDelayed2() { + final Observable o1 = Observable.create(new TestErrorObservable("one", "two", "three")); + final Observable o2 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" from the source (and it should never be sent by the source since onError was called + final Observable o3 = Observable.create(new TestErrorObservable("seven", "eight", null)); + final Observable o4 = Observable.create(new TestErrorObservable("nine")); + + @SuppressWarnings("unchecked") + Observable m = Observable.create(mergeDelayError(o1, o2, o3, o4)); + m.subscribe(stringObserver); + + verify(stringObserver, times(1)).onError(any(NullPointerException.class)); + verify(stringObserver, never()).onCompleted(); + verify(stringObserver, times(1)).onNext("one"); + verify(stringObserver, times(1)).onNext("two"); + verify(stringObserver, times(1)).onNext("three"); + verify(stringObserver, times(1)).onNext("four"); + verify(stringObserver, times(0)).onNext("five"); + verify(stringObserver, times(0)).onNext("six"); + verify(stringObserver, times(1)).onNext("seven"); + verify(stringObserver, times(1)).onNext("eight"); + verify(stringObserver, times(1)).onNext("nine"); + } + + @Test + public void testErrorDelayed3() { + final Observable o1 = Observable.create(new TestErrorObservable("one", "two", "three")); + final Observable o2 = Observable.create(new TestErrorObservable("four", "five", "six")); + final Observable o3 = Observable.create(new TestErrorObservable("seven", "eight", null)); + final Observable o4 = Observable.create(new TestErrorObservable("nine")); + + @SuppressWarnings("unchecked") + Observable m = Observable.create(mergeDelayError(o1, o2, o3, o4)); + m.subscribe(stringObserver); + + verify(stringObserver, times(1)).onError(any(NullPointerException.class)); + verify(stringObserver, never()).onCompleted(); + verify(stringObserver, times(1)).onNext("one"); + verify(stringObserver, times(1)).onNext("two"); + verify(stringObserver, times(1)).onNext("three"); + verify(stringObserver, times(1)).onNext("four"); + verify(stringObserver, times(1)).onNext("five"); + verify(stringObserver, times(1)).onNext("six"); + verify(stringObserver, times(1)).onNext("seven"); + verify(stringObserver, times(1)).onNext("eight"); + verify(stringObserver, times(1)).onNext("nine"); + } + + @Test + public void testErrorDelayed4() { + final Observable o1 = Observable.create(new TestErrorObservable("one", "two", "three")); + final Observable o2 = Observable.create(new TestErrorObservable("four", "five", "six")); + final Observable o3 = Observable.create(new TestErrorObservable("seven", "eight")); + final Observable o4 = Observable.create(new TestErrorObservable("nine", null)); + + @SuppressWarnings("unchecked") + Observable m = Observable.create(mergeDelayError(o1, o2, o3, o4)); + m.subscribe(stringObserver); + + verify(stringObserver, times(1)).onError(any(NullPointerException.class)); + verify(stringObserver, never()).onCompleted(); + verify(stringObserver, times(1)).onNext("one"); + verify(stringObserver, times(1)).onNext("two"); + verify(stringObserver, times(1)).onNext("three"); + verify(stringObserver, times(1)).onNext("four"); + verify(stringObserver, times(1)).onNext("five"); + verify(stringObserver, times(1)).onNext("six"); + verify(stringObserver, times(1)).onNext("seven"); + verify(stringObserver, times(1)).onNext("eight"); + verify(stringObserver, times(1)).onNext("nine"); + } + + @Test + public void testErrorDelayed4WithThreading() { + final TestAsyncErrorObservable o1 = new TestAsyncErrorObservable("one", "two", "three"); + final TestAsyncErrorObservable o2 = new TestAsyncErrorObservable("four", "five", "six"); + final TestAsyncErrorObservable o3 = new TestAsyncErrorObservable("seven", "eight"); + // throw the error at the very end so no onComplete will be called after it + final TestAsyncErrorObservable o4 = new TestAsyncErrorObservable("nine", null); + + @SuppressWarnings("unchecked") + Observable m = Observable.create(mergeDelayError(Observable.create(o1), Observable.create(o2), Observable.create(o3), Observable.create(o4))); + m.subscribe(stringObserver); + + try { + o1.t.join(); + o2.t.join(); + o3.t.join(); + o4.t.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + verify(stringObserver, times(1)).onError(any(NullPointerException.class)); + verify(stringObserver, never()).onCompleted(); + verify(stringObserver, times(1)).onNext("one"); + verify(stringObserver, times(1)).onNext("two"); + verify(stringObserver, times(1)).onNext("three"); + verify(stringObserver, times(1)).onNext("four"); + verify(stringObserver, times(1)).onNext("five"); + verify(stringObserver, times(1)).onNext("six"); + verify(stringObserver, times(1)).onNext("seven"); + verify(stringObserver, times(1)).onNext("eight"); + verify(stringObserver, times(1)).onNext("nine"); + } + + @Test + public void testCompositeErrorDelayed1() { + final Observable o1 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" from the source (and it should never be sent by the source since onError was called + final Observable o2 = Observable.create(new TestErrorObservable("one", "two", null)); + + @SuppressWarnings("unchecked") + Observable m = Observable.create(mergeDelayError(o1, o2)); + m.subscribe(stringObserver); + + verify(stringObserver, times(1)).onError(any(CompositeException.class)); + verify(stringObserver, never()).onCompleted(); + verify(stringObserver, times(1)).onNext("one"); + verify(stringObserver, times(1)).onNext("two"); + verify(stringObserver, times(0)).onNext("three"); + verify(stringObserver, times(1)).onNext("four"); + verify(stringObserver, times(0)).onNext("five"); + verify(stringObserver, times(0)).onNext("six"); + } + + @Test + public void testCompositeErrorDelayed2() { + final Observable o1 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" from the source (and it should never be sent by the source since onError was called + final Observable o2 = Observable.create(new TestErrorObservable("one", "two", null)); + + @SuppressWarnings("unchecked") + Observable m = Observable.create(mergeDelayError(o1, o2)); + CaptureObserver w = new CaptureObserver(); + m.subscribe(w); + + assertNotNull(w.e); + if (w.e instanceof CompositeException) { + assertEquals(2, ((CompositeException) w.e).getExceptions().size()); + w.e.printStackTrace(); + } else { + fail("Expecting CompositeException"); + } + + } + + /** + * The unit tests below are from OperationMerge and should ensure the normal merge functionality is correct. + */ + + @Test + public void testMergeObservableOfObservables() { + final Observable o1 = Observable.create(new TestSynchronousObservable()); + final Observable o2 = Observable.create(new TestSynchronousObservable()); + + Observable> observableOfObservables = Observable.create(new Observable.OnSubscribeFunc>() { + + @Override + public Subscription onSubscribe(Observer> observer) { + // simulate what would happen in an observable + observer.onNext(o1); + observer.onNext(o2); + observer.onCompleted(); + + return new Subscription() { + + @Override + public void unsubscribe() { + // unregister ... will never be called here since we are executing synchronously + } + + }; + } + + }); + Observable m = Observable.create(mergeDelayError(observableOfObservables)); + m.subscribe(stringObserver); + + verify(stringObserver, never()).onError(any(Throwable.class)); + verify(stringObserver, times(1)).onCompleted(); + verify(stringObserver, times(2)).onNext("hello"); + } + + @Test + public void testMergeArray() { + final Observable o1 = Observable.create(new TestSynchronousObservable()); + final Observable o2 = Observable.create(new TestSynchronousObservable()); + + @SuppressWarnings("unchecked") + Observable m = Observable.create(mergeDelayError(o1, o2)); + m.subscribe(stringObserver); + + verify(stringObserver, never()).onError(any(Throwable.class)); + verify(stringObserver, times(2)).onNext("hello"); + verify(stringObserver, times(1)).onCompleted(); + } + + @Test + public void testMergeList() { + final Observable o1 = Observable.create(new TestSynchronousObservable()); + final Observable o2 = Observable.create(new TestSynchronousObservable()); + List> listOfObservables = new ArrayList>(); + listOfObservables.add(o1); + listOfObservables.add(o2); + + Observable m = Observable.create(mergeDelayError(listOfObservables)); + m.subscribe(stringObserver); + + verify(stringObserver, never()).onError(any(Throwable.class)); + verify(stringObserver, times(1)).onCompleted(); + verify(stringObserver, times(2)).onNext("hello"); + } + + @Test + public void testUnSubscribe() { + TestObservable tA = new TestObservable(); + TestObservable tB = new TestObservable(); + + @SuppressWarnings("unchecked") + Observable m = Observable.create(mergeDelayError(Observable.create(tA), Observable.create(tB))); + Subscription s = m.subscribe(stringObserver); + + tA.sendOnNext("Aone"); + tB.sendOnNext("Bone"); + s.unsubscribe(); + tA.sendOnNext("Atwo"); + tB.sendOnNext("Btwo"); + tA.sendOnCompleted(); + tB.sendOnCompleted(); + + verify(stringObserver, never()).onError(any(Throwable.class)); + verify(stringObserver, times(1)).onNext("Aone"); + verify(stringObserver, times(1)).onNext("Bone"); + assertTrue(tA.unsubscribed); + assertTrue(tB.unsubscribed); + verify(stringObserver, never()).onNext("Atwo"); + verify(stringObserver, never()).onNext("Btwo"); + verify(stringObserver, never()).onCompleted(); + } + + @Test + public void testMergeArrayWithThreading() { + final TestASynchronousObservable o1 = new TestASynchronousObservable(); + final TestASynchronousObservable o2 = new TestASynchronousObservable(); + + @SuppressWarnings("unchecked") + Observable m = Observable.create(mergeDelayError(Observable.create(o1), Observable.create(o2))); + m.subscribe(stringObserver); + + try { + o1.t.join(); + o2.t.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + verify(stringObserver, never()).onError(any(Throwable.class)); + verify(stringObserver, times(2)).onNext("hello"); + verify(stringObserver, times(1)).onCompleted(); + } + + private static class TestSynchronousObservable implements Observable.OnSubscribeFunc { + + @Override + public Subscription onSubscribe(Observer observer) { + + observer.onNext("hello"); + observer.onCompleted(); + + return new Subscription() { + + @Override + public void unsubscribe() { + // unregister ... will never be called here since we are executing synchronously + } + + }; + } + } + + private static class TestASynchronousObservable implements Observable.OnSubscribeFunc { + Thread t; + + @Override + public Subscription onSubscribe(final Observer observer) { + t = new Thread(new Runnable() { + + @Override + public void run() { + observer.onNext("hello"); + observer.onCompleted(); + } + + }); + t.start(); + + return new Subscription() { + + @Override + public void unsubscribe() { + + } + + }; + } + } + + /** + * A Observable that doesn't do the right thing on UnSubscribe/Error/etc in that it will keep sending events down the pipe regardless of what happens. + */ + private static class TestObservable implements Observable.OnSubscribeFunc { + + Observer observer = null; + volatile boolean unsubscribed = false; + Subscription s = new Subscription() { + + @Override + public void unsubscribe() { + unsubscribed = true; + + } + + }; + + /* used to simulate subscription */ + public void sendOnCompleted() { + observer.onCompleted(); + } + + /* used to simulate subscription */ + public void sendOnNext(String value) { + observer.onNext(value); + } + + /* used to simulate subscription */ + @SuppressWarnings("unused") + public void sendOnError(Throwable e) { + observer.onError(e); + } + + @Override + public Subscription onSubscribe(final Observer observer) { + this.observer = observer; + return s; + } + } + + private static class TestErrorObservable implements Observable.OnSubscribeFunc { + + String[] valuesToReturn; + + TestErrorObservable(String... values) { + valuesToReturn = values; + } + + @Override + public Subscription onSubscribe(Observer observer) { + boolean errorThrown = false; + for (String s : valuesToReturn) { + if (s == null) { + System.out.println("throwing exception"); + observer.onError(new NullPointerException()); + errorThrown = true; + // purposefully not returning here so it will continue calling onNext + // so that we also test that we handle bad sequences like this + } else { + observer.onNext(s); + } + } + if (!errorThrown) { + observer.onCompleted(); + } + + return new Subscription() { + + @Override + public void unsubscribe() { + // unregister ... will never be called here since we are executing synchronously + } + + }; + } + } + + private static class TestAsyncErrorObservable implements Observable.OnSubscribeFunc { + + String[] valuesToReturn; + + TestAsyncErrorObservable(String... values) { + valuesToReturn = values; + } + + Thread t; + + @Override + public Subscription onSubscribe(final Observer observer) { + t = new Thread(new Runnable() { + + @Override + public void run() { + for (String s : valuesToReturn) { + if (s == null) { + System.out.println("throwing exception"); + try { + Thread.sleep(100); + } catch (Throwable e) { + + } + observer.onError(new NullPointerException()); + return; + } else { + observer.onNext(s); + } + } + System.out.println("subscription complete"); + observer.onCompleted(); + } + + }); + t.start(); + + return new Subscription() { + + @Override + public void unsubscribe() { + + } + + }; + } + } + + private static class CaptureObserver implements Observer { + volatile Throwable e; + + @Override + public void onCompleted() { + + } + + @Override + public void onError(Throwable e) { + this.e = e; + } + + @Override + public void onNext(String args) { + + } + + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationMergeTest.java b/rxjava-core/src/test/java/rx/operators/OperationMergeTest.java index ef50b179e6..b3bdf1423c 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationMergeTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationMergeTest.java @@ -1,7 +1,458 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.subscriptions.Subscriptions; +import rx.util.functions.Action0; +import rx.util.functions.Action1; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationMerge.merge; -@Ignore("WIP") public class OperationMergeTest { + + @Mock + Observer stringObserver; + + @Before + public void before() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testMergeObservableOfObservables() { + final Observable o1 = Observable.create(new TestSynchronousObservable()); + final Observable o2 = Observable.create(new TestSynchronousObservable()); + + Observable> observableOfObservables = Observable.create(new Observable.OnSubscribeFunc>() { + + @Override + public Subscription onSubscribe(Observer> observer) { + // simulate what would happen in an observable + observer.onNext(o1); + observer.onNext(o2); + observer.onCompleted(); + + return new Subscription() { + + @Override + public void unsubscribe() { + // unregister ... will never be called here since we are executing synchronously + } + + }; + } + + }); + Observable m = Observable.create(merge(observableOfObservables)); + m.subscribe(stringObserver); + + verify(stringObserver, never()).onError(any(Throwable.class)); + verify(stringObserver, times(1)).onCompleted(); + verify(stringObserver, times(2)).onNext("hello"); + } + + @Test + public void testMergeArray() { + final Observable o1 = Observable.create(new TestSynchronousObservable()); + final Observable o2 = Observable.create(new TestSynchronousObservable()); + + @SuppressWarnings("unchecked") + Observable m = Observable.create(merge(o1, o2)); + m.subscribe(stringObserver); + + verify(stringObserver, never()).onError(any(Throwable.class)); + verify(stringObserver, times(2)).onNext("hello"); + verify(stringObserver, times(1)).onCompleted(); + } + + @Test + public void testMergeList() { + final Observable o1 = Observable.create(new TestSynchronousObservable()); + final Observable o2 = Observable.create(new TestSynchronousObservable()); + List> listOfObservables = new ArrayList>(); + listOfObservables.add(o1); + listOfObservables.add(o2); + + Observable m = Observable.create(merge(listOfObservables)); + m.subscribe(stringObserver); + + verify(stringObserver, never()).onError(any(Throwable.class)); + verify(stringObserver, times(1)).onCompleted(); + verify(stringObserver, times(2)).onNext("hello"); + } + + @Test + public void testUnSubscribe() { + TestObservable tA = new TestObservable(); + TestObservable tB = new TestObservable(); + + @SuppressWarnings("unchecked") + Observable m = Observable.create(merge(Observable.create(tA), Observable.create(tB))); + Subscription s = m.subscribe(stringObserver); + + tA.sendOnNext("Aone"); + tB.sendOnNext("Bone"); + s.unsubscribe(); + tA.sendOnNext("Atwo"); + tB.sendOnNext("Btwo"); + tA.sendOnCompleted(); + tB.sendOnCompleted(); + + verify(stringObserver, never()).onError(any(Throwable.class)); + verify(stringObserver, times(1)).onNext("Aone"); + verify(stringObserver, times(1)).onNext("Bone"); + assertTrue(tA.unsubscribed); + assertTrue(tB.unsubscribed); + verify(stringObserver, never()).onNext("Atwo"); + verify(stringObserver, never()).onNext("Btwo"); + verify(stringObserver, never()).onCompleted(); + } + + @Test + public void testUnSubscribeObservableOfObservables() throws InterruptedException { + + final AtomicBoolean unsubscribed = new AtomicBoolean(); + final CountDownLatch latch = new CountDownLatch(1); + + Observable> source = Observable.create(new Observable.OnSubscribeFunc>() { + + @Override + public Subscription onSubscribe(final Observer> observer) { + // verbose on purpose so I can track the inside of it + final Subscription s = Subscriptions.create(new Action0() { + + @Override + public void call() { + System.out.println("*** unsubscribed"); + unsubscribed.set(true); + } + + }); + + new Thread(new Runnable() { + + @Override + public void run() { + + while (!unsubscribed.get()) { + observer.onNext(Observable.from(1L, 2L)); + } + System.out.println("Done looping after unsubscribe: " + unsubscribed.get()); + observer.onCompleted(); + + // mark that the thread is finished + latch.countDown(); + } + }).start(); + + return s; + } + + ; + + }); + + final AtomicInteger count = new AtomicInteger(); + Observable.create(merge(source)).take(6).toBlockingObservable().forEach(new Action1() { + + @Override + public void call(Long v) { + System.out.println("Value: " + v); + int c = count.incrementAndGet(); + if (c > 6) { + fail("Should be only 6"); + } + + } + }); + + latch.await(1000, TimeUnit.MILLISECONDS); + + System.out.println("unsubscribed: " + unsubscribed.get()); + + assertTrue(unsubscribed.get()); + + } + + @Test + public void testMergeArrayWithThreading() { + final TestASynchronousObservable o1 = new TestASynchronousObservable(); + final TestASynchronousObservable o2 = new TestASynchronousObservable(); + + @SuppressWarnings("unchecked") + Observable m = Observable.create(merge(Observable.create(o1), Observable.create(o2))); + m.subscribe(stringObserver); + + try { + o1.t.join(); + o2.t.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + verify(stringObserver, never()).onError(any(Throwable.class)); + verify(stringObserver, times(2)).onNext("hello"); + verify(stringObserver, times(1)).onCompleted(); + } + + @Test + public void testSynchronizationOfMultipleSequences() throws Throwable { + final TestASynchronousObservable o1 = new TestASynchronousObservable(); + final TestASynchronousObservable o2 = new TestASynchronousObservable(); + + // use this latch to cause onNext to wait until we're ready to let it go + final CountDownLatch endLatch = new CountDownLatch(1); + + final AtomicInteger concurrentCounter = new AtomicInteger(); + final AtomicInteger totalCounter = new AtomicInteger(); + + @SuppressWarnings("unchecked") + Observable m = Observable.create(merge(Observable.create(o1), Observable.create(o2))); + m.subscribe(new Observer() { + + @Override + public void onCompleted() { + + } + + @Override + public void onError(Throwable e) { + throw new RuntimeException("failed", e); + } + + @Override + public void onNext(String v) { + totalCounter.incrementAndGet(); + concurrentCounter.incrementAndGet(); + try { + // wait here until we're done asserting + endLatch.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + throw new RuntimeException("failed", e); + } finally { + concurrentCounter.decrementAndGet(); + } + } + + }); + + // wait for both observables to send (one should be blocked) + o1.onNextBeingSent.await(); + o2.onNextBeingSent.await(); + + // I can't think of a way to know for sure that both threads have or are trying to send onNext + // since I can't use a CountDownLatch for "after" onNext since I want to catch during it + // but I can't know for sure onNext is invoked + // so I'm unfortunately reverting to using a Thread.sleep to allow the process scheduler time + // to make sure after o1.onNextBeingSent and o2.onNextBeingSent are hit that the following + // onNext is invoked. + + Thread.sleep(300); + + try { // in try/finally so threads are released via latch countDown even if assertion fails + assertEquals(1, concurrentCounter.get()); + } finally { + // release so it can finish + endLatch.countDown(); + } + + try { + o1.t.join(); + o2.t.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + assertEquals(2, totalCounter.get()); + assertEquals(0, concurrentCounter.get()); + } + + /** + * unit test from OperationMergeDelayError backported here to show how these use cases work with normal merge + */ + @Test + public void testError1() { + // we are using synchronous execution to test this exactly rather than non-deterministic concurrent behavior + final Observable o1 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" + final Observable o2 = Observable.create(new TestErrorObservable("one", "two", "three")); // we expect to lose all of these since o1 is done first and fails + + @SuppressWarnings("unchecked") + Observable m = Observable.create(merge(o1, o2)); + m.subscribe(stringObserver); + + verify(stringObserver, times(1)).onError(any(NullPointerException.class)); + verify(stringObserver, never()).onCompleted(); + verify(stringObserver, times(0)).onNext("one"); + verify(stringObserver, times(0)).onNext("two"); + verify(stringObserver, times(0)).onNext("three"); + verify(stringObserver, times(1)).onNext("four"); + verify(stringObserver, times(0)).onNext("five"); + verify(stringObserver, times(0)).onNext("six"); + } + + /** + * unit test from OperationMergeDelayError backported here to show how these use cases work with normal merge + */ + @Test + public void testError2() { + // we are using synchronous execution to test this exactly rather than non-deterministic concurrent behavior + final Observable o1 = Observable.create(new TestErrorObservable("one", "two", "three")); + final Observable o2 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" + final Observable o3 = Observable.create(new TestErrorObservable("seven", "eight", null));// we expect to lose all of these since o2 is done first and fails + final Observable o4 = Observable.create(new TestErrorObservable("nine"));// we expect to lose all of these since o2 is done first and fails + + @SuppressWarnings("unchecked") + Observable m = Observable.create(merge(o1, o2, o3, o4)); + m.subscribe(stringObserver); + + verify(stringObserver, times(1)).onError(any(NullPointerException.class)); + verify(stringObserver, never()).onCompleted(); + verify(stringObserver, times(1)).onNext("one"); + verify(stringObserver, times(1)).onNext("two"); + verify(stringObserver, times(1)).onNext("three"); + verify(stringObserver, times(1)).onNext("four"); + verify(stringObserver, times(0)).onNext("five"); + verify(stringObserver, times(0)).onNext("six"); + verify(stringObserver, times(0)).onNext("seven"); + verify(stringObserver, times(0)).onNext("eight"); + verify(stringObserver, times(0)).onNext("nine"); + } + + private static class TestSynchronousObservable implements Observable.OnSubscribeFunc { + + @Override + public Subscription onSubscribe(Observer observer) { + + observer.onNext("hello"); + observer.onCompleted(); + + return new Subscription() { + + @Override + public void unsubscribe() { + // unregister ... will never be called here since we are executing synchronously + } + + }; + } + } + + private static class TestASynchronousObservable implements Observable.OnSubscribeFunc { + Thread t; + final CountDownLatch onNextBeingSent = new CountDownLatch(1); + + @Override + public Subscription onSubscribe(final Observer observer) { + t = new Thread(new Runnable() { + + @Override + public void run() { + onNextBeingSent.countDown(); + observer.onNext("hello"); + // I can't use a countDownLatch to prove we are actually sending 'onNext' + // since it will block if synchronized and I'll deadlock + observer.onCompleted(); + } + + }); + t.start(); + + return new Subscription() { + + @Override + public void unsubscribe() { + + } + + }; + } + } + + /** + * A Observable that doesn't do the right thing on UnSubscribe/Error/etc in that it will keep sending events down the pipe regardless of what happens. + */ + private static class TestObservable implements Observable.OnSubscribeFunc { + + Observer observer = null; + volatile boolean unsubscribed = false; + Subscription s = new Subscription() { + + @Override + public void unsubscribe() { + unsubscribed = true; + + } + + }; + + /* used to simulate subscription */ + public void sendOnCompleted() { + observer.onCompleted(); + } + + /* used to simulate subscription */ + public void sendOnNext(String value) { + observer.onNext(value); + } + + /* used to simulate subscription */ + @SuppressWarnings("unused") + public void sendOnError(Throwable e) { + observer.onError(e); + } + + @Override + public Subscription onSubscribe(final Observer observer) { + this.observer = observer; + return s; + } + } + + private static class TestErrorObservable implements Observable.OnSubscribeFunc { + + String[] valuesToReturn; + + TestErrorObservable(String... values) { + valuesToReturn = values; + } + + @Override + public Subscription onSubscribe(Observer observer) { + + for (String s : valuesToReturn) { + if (s == null) { + System.out.println("throwing exception"); + observer.onError(new NullPointerException()); + } else { + observer.onNext(s); + } + } + observer.onCompleted(); + + return new Subscription() { + + @Override + public void unsubscribe() { + // unregister ... will never be called here since we are executing synchronously + } + + }; + } + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationMostRecentTest.java b/rxjava-core/src/test/java/rx/operators/OperationMostRecentTest.java index 1f5806b310..35c6c9fadf 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationMostRecentTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationMostRecentTest.java @@ -1,7 +1,59 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.subjects.PublishSubject; +import rx.subjects.Subject; + +import java.util.Iterator; + +import static org.junit.Assert.*; +import static rx.operators.OperationMostRecent.mostRecent; -@Ignore("WIP") public class OperationMostRecentTest { + + + @Test + public void testMostRecent() { + Subject observable = PublishSubject.create(); + + Iterator it = mostRecent(observable, "default").iterator(); + + assertTrue(it.hasNext()); + assertEquals("default", it.next()); + assertEquals("default", it.next()); + + observable.onNext("one"); + assertTrue(it.hasNext()); + assertEquals("one", it.next()); + assertEquals("one", it.next()); + + observable.onNext("two"); + assertTrue(it.hasNext()); + assertEquals("two", it.next()); + assertEquals("two", it.next()); + + observable.onCompleted(); + assertFalse(it.hasNext()); + + } + + @Test(expected = TestException.class) + public void testMostRecentWithException() { + Subject observable = PublishSubject.create(); + + Iterator it = mostRecent(observable, "default").iterator(); + + assertTrue(it.hasNext()); + assertEquals("default", it.next()); + assertEquals("default", it.next()); + + observable.onError(new TestException()); + assertTrue(it.hasNext()); + + it.next(); + } + + private static class TestException extends RuntimeException { + private static final long serialVersionUID = 1L; + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationMulticastTest.java b/rxjava-core/src/test/java/rx/operators/OperationMulticastTest.java index dd2ba06360..e33ee00de3 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationMulticastTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationMulticastTest.java @@ -1,7 +1,97 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Observer; +import rx.Subscription; +import rx.observables.ConnectableObservable; +import rx.subjects.PublishSubject; +import rx.subjects.Subject; + +import static org.mockito.Mockito.*; -@Ignore("WIP") public class OperationMulticastTest { + + @Test + public void testMulticast() { + Subject source = PublishSubject.create(); + + ConnectableObservable multicasted = OperationMulticast.multicast(source, + PublishSubject.create()); + + @SuppressWarnings("unchecked") + Observer observer = mock(Observer.class); + multicasted.subscribe(observer); + + source.onNext("one"); + source.onNext("two"); + + multicasted.connect(); + + source.onNext("three"); + source.onNext("four"); + source.onCompleted(); + + verify(observer, never()).onNext("one"); + verify(observer, never()).onNext("two"); + verify(observer, times(1)).onNext("three"); + verify(observer, times(1)).onNext("four"); + verify(observer, times(1)).onCompleted(); + + } + + @Test + public void testMulticastConnectTwice() { + Subject source = PublishSubject.create(); + + ConnectableObservable multicasted = OperationMulticast.multicast(source, + PublishSubject.create()); + + @SuppressWarnings("unchecked") + Observer observer = mock(Observer.class); + multicasted.subscribe(observer); + + source.onNext("one"); + + multicasted.connect(); + multicasted.connect(); + + source.onNext("two"); + source.onCompleted(); + + verify(observer, never()).onNext("one"); + verify(observer, times(1)).onNext("two"); + verify(observer, times(1)).onCompleted(); + + } + + @Test + public void testMulticastDisconnect() { + Subject source = PublishSubject.create(); + + ConnectableObservable multicasted = OperationMulticast.multicast(source, + PublishSubject.create()); + + @SuppressWarnings("unchecked") + Observer observer = mock(Observer.class); + multicasted.subscribe(observer); + + source.onNext("one"); + + Subscription connection = multicasted.connect(); + source.onNext("two"); + + connection.unsubscribe(); + source.onNext("three"); + + multicasted.connect(); + source.onNext("four"); + source.onCompleted(); + + verify(observer, never()).onNext("one"); + verify(observer, times(1)).onNext("two"); + verify(observer, never()).onNext("three"); + verify(observer, times(1)).onNext("four"); + verify(observer, times(1)).onCompleted(); + + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationNextTest.java b/rxjava-core/src/test/java/rx/operators/OperationNextTest.java index bad26bbcb1..c696a64c27 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationNextTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationNextTest.java @@ -1,7 +1,281 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.concurrency.Schedulers; +import rx.subjects.PublishSubject; +import rx.subjects.Subject; +import rx.subscriptions.Subscriptions; + +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.Assert.*; +import static rx.operators.OperationNext.next; -@Ignore("WIP") public class OperationNextTest { + + private void fireOnNextInNewThread(final Subject o, final String value) { + new Thread() { + @Override + public void run() { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + // ignore + } + o.onNext(value); + } + }.start(); + } + + private void fireOnErrorInNewThread(final Subject o) { + new Thread() { + @Override + public void run() { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + // ignore + } + o.onError(new TestException()); + } + }.start(); + } + + + @Test + public void testNext() { + Subject obs = PublishSubject.create(); + Iterator it = next(obs).iterator(); + fireOnNextInNewThread(obs, "one"); + assertTrue(it.hasNext()); + assertEquals("one", it.next()); + + fireOnNextInNewThread(obs, "two"); + assertTrue(it.hasNext()); + assertEquals("two", it.next()); + + obs.onCompleted(); + assertFalse(it.hasNext()); + try { + it.next(); + fail("At the end of an iterator should throw a NoSuchElementException"); + } catch (NoSuchElementException e) { + } + + // If the observable is completed, hasNext always returns false and next always throw a NoSuchElementException. + assertFalse(it.hasNext()); + try { + it.next(); + fail("At the end of an iterator should throw a NoSuchElementException"); + } catch (NoSuchElementException e) { + } + } + + @Test + public void testNextWithError() { + Subject obs = PublishSubject.create(); + Iterator it = next(obs).iterator(); + fireOnNextInNewThread(obs, "one"); + assertTrue(it.hasNext()); + assertEquals("one", it.next()); + + fireOnErrorInNewThread(obs); + try { + it.hasNext(); + fail("Expected an TestException"); + } catch (TestException e) { + } + + assertErrorAfterObservableFail(it); + } + + @Test + public void testNextWithEmpty() { + Observable obs = Observable.empty().observeOn(Schedulers.newThread()); + Iterator it = next(obs).iterator(); + + assertFalse(it.hasNext()); + try { + it.next(); + fail("At the end of an iterator should throw a NoSuchElementException"); + } catch (NoSuchElementException e) { + } + + // If the observable is completed, hasNext always returns false and next always throw a NoSuchElementException. + assertFalse(it.hasNext()); + try { + it.next(); + fail("At the end of an iterator should throw a NoSuchElementException"); + } catch (NoSuchElementException e) { + } + } + + @Test + public void testOnError() throws Throwable { + Subject obs = PublishSubject.create(); + Iterator it = next(obs).iterator(); + + obs.onError(new TestException()); + try { + it.hasNext(); + fail("Expected an TestException"); + } catch (TestException e) { + // successful + } + + assertErrorAfterObservableFail(it); + } + + @Test + public void testOnErrorInNewThread() { + Subject obs = PublishSubject.create(); + Iterator it = next(obs).iterator(); + + fireOnErrorInNewThread(obs); + + try { + it.hasNext(); + fail("Expected an TestException"); + } catch (TestException e) { + // successful + } + + assertErrorAfterObservableFail(it); + } + + private void assertErrorAfterObservableFail(Iterator it) { + // After the observable fails, hasNext and next always throw the exception. + try { + it.hasNext(); + fail("hasNext should throw a TestException"); + } catch (TestException e) { + } + try { + it.next(); + fail("next should throw a TestException"); + } catch (TestException e) { + } + } + + @Test + public void testNextWithOnlyUsingNextMethod() { + Subject obs = PublishSubject.create(); + Iterator it = next(obs).iterator(); + fireOnNextInNewThread(obs, "one"); + assertEquals("one", it.next()); + + fireOnNextInNewThread(obs, "two"); + assertEquals("two", it.next()); + + obs.onCompleted(); + try { + it.next(); + fail("At the end of an iterator should throw a NoSuchElementException"); + } catch (NoSuchElementException e) { + } + } + + @Test + public void testNextWithCallingHasNextMultipleTimes() { + Subject obs = PublishSubject.create(); + Iterator it = next(obs).iterator(); + fireOnNextInNewThread(obs, "one"); + assertTrue(it.hasNext()); + assertTrue(it.hasNext()); + assertTrue(it.hasNext()); + assertTrue(it.hasNext()); + assertEquals("one", it.next()); + + obs.onCompleted(); + try { + it.next(); + fail("At the end of an iterator should throw a NoSuchElementException"); + } catch (NoSuchElementException e) { + } + } + + @SuppressWarnings("serial") + private static class TestException extends RuntimeException { + + } + + /** + * Confirm that no buffering or blocking of the Observable onNext calls occurs and it just grabs the next emitted value. + *

    + * This results in output such as => a: 1 b: 2 c: 89 + * + * @throws Throwable + */ + @Test + public void testNoBufferingOrBlockingOfSequence() throws Throwable { + final CountDownLatch finished = new CountDownLatch(1); + final int COUNT = 30; + final CountDownLatch timeHasPassed = new CountDownLatch(COUNT); + final AtomicBoolean running = new AtomicBoolean(true); + final AtomicInteger count = new AtomicInteger(0); + final Observable obs = Observable.create(new Observable.OnSubscribeFunc() { + + @Override + public Subscription onSubscribe(final Observer o) { + new Thread(new Runnable() { + + @Override + public void run() { + try { + while (running.get()) { + o.onNext(count.incrementAndGet()); + timeHasPassed.countDown(); + } + o.onCompleted(); + } catch (Throwable e) { + o.onError(e); + } finally { + finished.countDown(); + } + } + }).start(); + return Subscriptions.empty(); + } + + }); + + Iterator it = next(obs).iterator(); + + assertTrue(it.hasNext()); + int a = it.next(); + assertTrue(it.hasNext()); + int b = it.next(); + // we should have a different value + assertTrue("a and b should be different", a != b); + + // wait for some time (if times out we are blocked somewhere so fail ... set very high for very slow, constrained machines) + timeHasPassed.await(8000, TimeUnit.MILLISECONDS); + + assertTrue(it.hasNext()); + int c = it.next(); + + assertTrue("c should not just be the next in sequence", c != (b + 1)); + assertTrue("expected that c [" + c + "] is higher than or equal to " + COUNT, c >= COUNT); + + assertTrue(it.hasNext()); + int d = it.next(); + assertTrue(d > c); + + // shut down the thread + running.set(false); + + finished.await(); + + assertFalse(it.hasNext()); + + System.out.println("a: " + a + " b: " + b + " c: " + c); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationObserveOnTest.java b/rxjava-core/src/test/java/rx/operators/OperationObserveOnTest.java index 9f439949a8..17b5292130 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationObserveOnTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationObserveOnTest.java @@ -1,7 +1,68 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import rx.Observable; +import rx.Observer; +import rx.concurrency.Schedulers; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.fail; +import static org.mockito.Mockito.*; +import static rx.operators.OperationObserveOn.observeOn; -@Ignore("WIP") public class OperationObserveOnTest { + + /** + * This is testing a no-op path since it uses Schedulers.immediate() which will not do scheduling. + */ + @Test + @SuppressWarnings("unchecked") + public void testObserveOn() { + Observer observer = mock(Observer.class); + Observable.create(observeOn(Observable.from(1, 2, 3), Schedulers.immediate())).subscribe(observer); + + verify(observer, times(1)).onNext(1); + verify(observer, times(1)).onNext(2); + verify(observer, times(1)).onNext(3); + verify(observer, times(1)).onCompleted(); + } + + @Test + @SuppressWarnings("unchecked") + public void testOrdering() throws InterruptedException { + Observable obs = Observable.from("one", null, "two", "three", "four"); + + Observer observer = mock(Observer.class); + + InOrder inOrder = inOrder(observer); + + final CountDownLatch completedLatch = new CountDownLatch(1); + doAnswer(new Answer() { + + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + completedLatch.countDown(); + return null; + } + }).when(observer).onCompleted(); + + obs.observeOn(Schedulers.threadPoolForComputation()).subscribe(observer); + + if (!completedLatch.await(1000, TimeUnit.MILLISECONDS)) { + fail("timed out waiting"); + } + + inOrder.verify(observer, times(1)).onNext("one"); + inOrder.verify(observer, times(1)).onNext(null); + inOrder.verify(observer, times(1)).onNext("two"); + inOrder.verify(observer, times(1)).onNext("three"); + inOrder.verify(observer, times(1)).onNext("four"); + inOrder.verify(observer, times(1)).onCompleted(); + inOrder.verifyNoMoreInteractions(); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationOnErrorResumeNextViaFunctionTest.java b/rxjava-core/src/test/java/rx/operators/OperationOnErrorResumeNextViaFunctionTest.java index 8a98b35dd2..3de89d6a49 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationOnErrorResumeNextViaFunctionTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationOnErrorResumeNextViaFunctionTest.java @@ -1,7 +1,168 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.Mockito; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.subscriptions.Subscriptions; +import rx.util.functions.Func1; + +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationOnErrorResumeNextViaFunction.onErrorResumeNextViaFunction; -@Ignore("WIP") public class OperationOnErrorResumeNextViaFunctionTest { + + @Test + public void testResumeNextWithSynchronousExecution() { + final AtomicReference receivedException = new AtomicReference(); + Observable w = Observable.create(new Observable.OnSubscribeFunc() { + + @Override + public Subscription onSubscribe(Observer observer) { + observer.onNext("one"); + observer.onError(new Throwable("injected failure")); + return Subscriptions.empty(); + } + }); + + Func1> resume = new Func1>() { + + @Override + public Observable call(Throwable t1) { + receivedException.set(t1); + return Observable.from("twoResume", "threeResume"); + } + + }; + Observable observable = Observable.create(onErrorResumeNextViaFunction(w, resume)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, Mockito.never()).onNext("two"); + verify(aObserver, Mockito.never()).onNext("three"); + verify(aObserver, times(1)).onNext("twoResume"); + verify(aObserver, times(1)).onNext("threeResume"); + assertNotNull(receivedException.get()); + } + + @Test + public void testResumeNextWithAsyncExecution() { + final AtomicReference receivedException = new AtomicReference(); + Subscription s = mock(Subscription.class); + TestObservable w = new TestObservable(s, "one"); + Func1> resume = new Func1>() { + + @Override + public Observable call(Throwable t1) { + receivedException.set(t1); + return Observable.from("twoResume", "threeResume"); + } + + }; + Observable observable = Observable.create(onErrorResumeNextViaFunction(Observable.create(w), resume)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + + try { + w.t.join(); + } catch (InterruptedException e) { + fail(e.getMessage()); + } + + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, Mockito.never()).onNext("two"); + verify(aObserver, Mockito.never()).onNext("three"); + verify(aObserver, times(1)).onNext("twoResume"); + verify(aObserver, times(1)).onNext("threeResume"); + assertNotNull(receivedException.get()); + } + + /** + * Test that when a function throws an exception this is propagated through onError + */ + @Test + public void testFunctionThrowsError() { + Subscription s = mock(Subscription.class); + TestObservable w = new TestObservable(s, "one"); + Func1> resume = new Func1>() { + + @Override + public Observable call(Throwable t1) { + throw new RuntimeException("exception from function"); + } + + }; + Observable observable = Observable.create(onErrorResumeNextViaFunction(Observable.create(w), resume)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + + try { + w.t.join(); + } catch (InterruptedException e) { + fail(e.getMessage()); + } + + // we should get the "one" value before the error + verify(aObserver, times(1)).onNext("one"); + + // we should have received an onError call on the Observer since the resume function threw an exception + verify(aObserver, times(1)).onError(any(Throwable.class)); + verify(aObserver, times(0)).onCompleted(); + } + + private static class TestObservable implements Observable.OnSubscribeFunc { + + final Subscription s; + final String[] values; + Thread t = null; + + public TestObservable(Subscription s, String... values) { + this.s = s; + this.values = values; + } + + @Override + public Subscription onSubscribe(final Observer observer) { + System.out.println("TestObservable subscribed to ..."); + t = new Thread(new Runnable() { + + @Override + public void run() { + try { + System.out.println("running TestObservable thread"); + for (String s : values) { + System.out.println("TestObservable onNext: " + s); + observer.onNext(s); + } + throw new RuntimeException("Forced Failure"); + } catch (Throwable e) { + observer.onError(e); + } + } + + }); + System.out.println("starting TestObservable thread"); + t.start(); + System.out.println("done starting TestObservable thread"); + return s; + } + + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationOnErrorResumeNextViaObservableTest.java b/rxjava-core/src/test/java/rx/operators/OperationOnErrorResumeNextViaObservableTest.java index b0ec9f3211..69b62ec495 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationOnErrorResumeNextViaObservableTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationOnErrorResumeNextViaObservableTest.java @@ -1,7 +1,127 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.Mockito; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.util.functions.Func1; + +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationOnErrorResumeNextViaObservable.onErrorResumeNextViaObservable; -@Ignore("WIP") public class OperationOnErrorResumeNextViaObservableTest { + + @Test + public void testResumeNext() { + Subscription s = mock(Subscription.class); + // Trigger failure on second element + TestObservable f = new TestObservable(s, "one", "fail", "two", "three"); + Observable w = Observable.create(f); + Observable resume = Observable.from("twoResume", "threeResume"); + Observable observable = Observable.create(onErrorResumeNextViaObservable(w, resume)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + + try { + f.t.join(); + } catch (InterruptedException e) { + fail(e.getMessage()); + } + + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, Mockito.never()).onNext("two"); + verify(aObserver, Mockito.never()).onNext("three"); + verify(aObserver, times(1)).onNext("twoResume"); + verify(aObserver, times(1)).onNext("threeResume"); + } + + @Test + public void testMapResumeAsyncNext() { + Subscription sr = mock(Subscription.class); + // Trigger multiple failures + Observable w = Observable.from("one", "fail", "two", "three", "fail"); + // Resume Observable is async + TestObservable f = new TestObservable(sr, "twoResume", "threeResume"); + Observable resume = Observable.create(f); + + // Introduce map function that fails intermittently (Map does not prevent this when the observer is a + // rx.operator incl onErrorResumeNextViaObservable) + w = w.map(new Func1() { + public String call(String s) { + if ("fail".equals(s)) + throw new RuntimeException("Forced Failure"); + System.out.println("BadMapper:" + s); + return s; + } + }); + + Observable observable = Observable.create(onErrorResumeNextViaObservable(w, resume)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + + try { + f.t.join(); + } catch (InterruptedException e) { + fail(e.getMessage()); + } + + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, Mockito.never()).onNext("two"); + verify(aObserver, Mockito.never()).onNext("three"); + verify(aObserver, times(1)).onNext("twoResume"); + verify(aObserver, times(1)).onNext("threeResume"); + } + + private static class TestObservable implements Observable.OnSubscribeFunc { + + final Subscription s; + final String[] values; + Thread t = null; + + public TestObservable(Subscription s, String... values) { + this.s = s; + this.values = values; + } + + @Override + public Subscription onSubscribe(final Observer observer) { + System.out.println("TestObservable subscribed to ..."); + t = new Thread(new Runnable() { + + @Override + public void run() { + try { + System.out.println("running TestObservable thread"); + for (String s : values) { + if ("fail".equals(s)) + throw new RuntimeException("Forced Failure"); + System.out.println("TestObservable onNext: " + s); + observer.onNext(s); + } + System.out.println("TestObservable onCompleted"); + observer.onCompleted(); + } catch (Throwable e) { + System.out.println("TestObservable onError: " + e); + observer.onError(e); + } + } + + }); + System.out.println("starting TestObservable thread"); + t.start(); + System.out.println("done starting TestObservable thread"); + return s; + } + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationOnErrorReturnTest.java b/rxjava-core/src/test/java/rx/operators/OperationOnErrorReturnTest.java index 0fe50a7f04..b19e60598f 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationOnErrorReturnTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationOnErrorReturnTest.java @@ -1,7 +1,130 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.Mockito; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.util.functions.Func1; + +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationOnErrorReturn.onErrorReturn; -@Ignore("WIP") public class OperationOnErrorReturnTest { + + @Test + public void testResumeNext() { + Subscription s = mock(Subscription.class); + TestObservable f = new TestObservable(s, "one"); + Observable w = Observable.create(f); + final AtomicReference capturedException = new AtomicReference(); + + Observable observable = Observable.create(onErrorReturn(w, new Func1() { + + @Override + public String call(Throwable e) { + capturedException.set(e); + return "failure"; + } + + })); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + + try { + f.t.join(); + } catch (InterruptedException e) { + fail(e.getMessage()); + } + + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, times(1)).onNext("failure"); + assertNotNull(capturedException.get()); + } + + /** + * Test that when a function throws an exception this is propagated through onError + */ + @Test + public void testFunctionThrowsError() { + Subscription s = mock(Subscription.class); + TestObservable f = new TestObservable(s, "one"); + Observable w = Observable.create(f); + final AtomicReference capturedException = new AtomicReference(); + + Observable observable = Observable.create(onErrorReturn(w, new Func1() { + + @Override + public String call(Throwable e) { + capturedException.set(e); + throw new RuntimeException("exception from function"); + } + + })); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + + try { + f.t.join(); + } catch (InterruptedException e) { + fail(e.getMessage()); + } + + // we should get the "one" value before the error + verify(aObserver, times(1)).onNext("one"); + + // we should have received an onError call on the Observer since the resume function threw an exception + verify(aObserver, times(1)).onError(any(Throwable.class)); + verify(aObserver, times(0)).onCompleted(); + assertNotNull(capturedException.get()); + } + + private static class TestObservable implements Observable.OnSubscribeFunc { + + final Subscription s; + final String[] values; + Thread t = null; + + public TestObservable(Subscription s, String... values) { + this.s = s; + this.values = values; + } + + @Override + public Subscription onSubscribe(final Observer observer) { + System.out.println("TestObservable subscribed to ..."); + t = new Thread(new Runnable() { + + @Override + public void run() { + try { + System.out.println("running TestObservable thread"); + for (String s : values) { + System.out.println("TestObservable onNext: " + s); + observer.onNext(s); + } + throw new RuntimeException("Forced Failure"); + } catch (Throwable e) { + observer.onError(e); + } + } + + }); + System.out.println("starting TestObservable thread"); + t.start(); + System.out.println("done starting TestObservable thread"); + return s; + } + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationOnExceptionResumeNextViaObservableTest.java b/rxjava-core/src/test/java/rx/operators/OperationOnExceptionResumeNextViaObservableTest.java index 4e8a7c1586..ee85ed7517 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationOnExceptionResumeNextViaObservableTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationOnExceptionResumeNextViaObservableTest.java @@ -1,7 +1,224 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.Mockito; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.util.functions.Func1; + +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationOnExceptionResumeNextViaObservable.onExceptionResumeNextViaObservable; -@Ignore("WIP") public class OperationOnExceptionResumeNextViaObservableTest { + + @Test + public void testResumeNextWithException() { + Subscription s = mock(Subscription.class); + // Trigger failure on second element + TestObservable f = new TestObservable(s, "one", "EXCEPTION", "two", "three"); + Observable w = Observable.create(f); + Observable resume = Observable.from("twoResume", "threeResume"); + Observable observable = Observable.create(onExceptionResumeNextViaObservable(w, resume)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + + try { + f.t.join(); + } catch (InterruptedException e) { + fail(e.getMessage()); + } + + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, Mockito.never()).onNext("two"); + verify(aObserver, Mockito.never()).onNext("three"); + verify(aObserver, times(1)).onNext("twoResume"); + verify(aObserver, times(1)).onNext("threeResume"); + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + verifyNoMoreInteractions(aObserver); + } + + @Test + public void testResumeNextWithRuntimeException() { + Subscription s = mock(Subscription.class); + // Trigger failure on second element + TestObservable f = new TestObservable(s, "one", "RUNTIMEEXCEPTION", "two", "three"); + Observable w = Observable.create(f); + Observable resume = Observable.from("twoResume", "threeResume"); + Observable observable = Observable.create(onExceptionResumeNextViaObservable(w, resume)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + + try { + f.t.join(); + } catch (InterruptedException e) { + fail(e.getMessage()); + } + + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, Mockito.never()).onNext("two"); + verify(aObserver, Mockito.never()).onNext("three"); + verify(aObserver, times(1)).onNext("twoResume"); + verify(aObserver, times(1)).onNext("threeResume"); + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + verifyNoMoreInteractions(aObserver); + } + + @Test + public void testThrowablePassesThru() { + Subscription s = mock(Subscription.class); + // Trigger failure on second element + TestObservable f = new TestObservable(s, "one", "THROWABLE", "two", "three"); + Observable w = Observable.create(f); + Observable resume = Observable.from("twoResume", "threeResume"); + Observable observable = Observable.create(onExceptionResumeNextViaObservable(w, resume)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + + try { + f.t.join(); + } catch (InterruptedException e) { + fail(e.getMessage()); + } + + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, never()).onNext("two"); + verify(aObserver, never()).onNext("three"); + verify(aObserver, never()).onNext("twoResume"); + verify(aObserver, never()).onNext("threeResume"); + verify(aObserver, times(1)).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + verifyNoMoreInteractions(aObserver); + } + + @Test + public void testErrorPassesThru() { + Subscription s = mock(Subscription.class); + // Trigger failure on second element + TestObservable f = new TestObservable(s, "one", "ERROR", "two", "three"); + Observable w = Observable.create(f); + Observable resume = Observable.from("twoResume", "threeResume"); + Observable observable = Observable.create(onExceptionResumeNextViaObservable(w, resume)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + + try { + f.t.join(); + } catch (InterruptedException e) { + fail(e.getMessage()); + } + + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, never()).onNext("two"); + verify(aObserver, never()).onNext("three"); + verify(aObserver, never()).onNext("twoResume"); + verify(aObserver, never()).onNext("threeResume"); + verify(aObserver, times(1)).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + verifyNoMoreInteractions(aObserver); + } + + @Test + public void testMapResumeAsyncNext() { + Subscription sr = mock(Subscription.class); + // Trigger multiple failures + Observable w = Observable.from("one", "fail", "two", "three", "fail"); + // Resume Observable is async + TestObservable f = new TestObservable(sr, "twoResume", "threeResume"); + Observable resume = Observable.create(f); + + // Introduce map function that fails intermittently (Map does not prevent this when the observer is a + // rx.operator incl onErrorResumeNextViaObservable) + w = w.map(new Func1() { + public String call(String s) { + if ("fail".equals(s)) + throw new RuntimeException("Forced Failure"); + System.out.println("BadMapper:" + s); + return s; + } + }); + + Observable observable = Observable.create(onExceptionResumeNextViaObservable(w, resume)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + + try { + // if the thread gets started (which it shouldn't if it's working correctly) + if (f.t != null) { + f.t.join(); + } + } catch (InterruptedException e) { + fail(e.getMessage()); + } + + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, never()).onNext("two"); + verify(aObserver, never()).onNext("three"); + verify(aObserver, times(1)).onNext("twoResume"); + verify(aObserver, times(1)).onNext("threeResume"); + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + private static class TestObservable implements Observable.OnSubscribeFunc { + + final Subscription s; + final String[] values; + Thread t = null; + + public TestObservable(Subscription s, String... values) { + this.s = s; + this.values = values; + } + + @Override + public Subscription onSubscribe(final Observer observer) { + System.out.println("TestObservable subscribed to ..."); + t = new Thread(new Runnable() { + + @Override + public void run() { + try { + System.out.println("running TestObservable thread"); + for (String s : values) { + if ("EXCEPTION".equals(s)) + throw new Exception("Forced Exception"); + else if ("RUNTIMEEXCEPTION".equals(s)) + throw new RuntimeException("Forced RuntimeException"); + else if ("ERROR".equals(s)) + throw new Error("Forced Error"); + else if ("THROWABLE".equals(s)) + throw new Throwable("Forced Throwable"); + System.out.println("TestObservable onNext: " + s); + observer.onNext(s); + } + System.out.println("TestObservable onCompleted"); + observer.onCompleted(); + } catch (Throwable e) { + System.out.println("TestObservable onError: " + e); + observer.onError(e); + } + } + + }); + System.out.println("starting TestObservable thread"); + t.start(); + System.out.println("done starting TestObservable thread"); + return s; + } + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationParallelTest.java b/rxjava-core/src/test/java/rx/operators/OperationParallelTest.java index fee3816e98..fd79f9e9fb 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationParallelTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationParallelTest.java @@ -1,7 +1,45 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Observable; +import rx.util.functions.Action1; +import rx.util.functions.Func1; + +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.Assert.assertEquals; -@Ignore("WIP") public class OperationParallelTest { + + @Test + public void testParallel() { + int NUM = 1000; + final AtomicInteger count = new AtomicInteger(); + Observable.range(1, NUM).parallel( + new Func1, Observable>() { + + @Override + public Observable call(Observable o) { + return o.map(new Func1() { + + @Override + public Integer[] call(Integer t) { + return new Integer[]{t, t * 99}; + } + + }); + } + }).toBlockingObservable().forEach(new Action1() { + + @Override + public void call(Integer[] v) { + count.incrementAndGet(); + System.out.println("V: " + v[0] + " R: " + v[1] + " Thread: " + Thread.currentThread()); + } + + }); + + // just making sure we finish and get the number we expect + assertEquals(NUM, count.get()); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationRetryTest.java b/rxjava-core/src/test/java/rx/operators/OperationRetryTest.java index 768d1f5f9c..5132b84219 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationRetryTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationRetryTest.java @@ -1,7 +1,114 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.InOrder; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.subscriptions.Subscriptions; + +import java.util.concurrent.atomic.AtomicInteger; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationRetry.retry; -@Ignore("WIP") public class OperationRetryTest { + + @Test + public void testOriginFails() { + @SuppressWarnings("unchecked") + Observer observer = mock(Observer.class); + Observable origin = Observable.create(new FuncWithErrors(2)); + origin.subscribe(observer); + + InOrder inOrder = inOrder(observer); + inOrder.verify(observer, times(1)).onNext("beginningEveryTime"); + inOrder.verify(observer, times(1)).onError(any(RuntimeException.class)); + inOrder.verify(observer, never()).onNext("onSuccessOnly"); + inOrder.verify(observer, never()).onCompleted(); + } + + @Test + public void testRetryFail() { + int NUM_RETRIES = 1; + int NUM_FAILURES = 2; + @SuppressWarnings("unchecked") + Observer observer = mock(Observer.class); + Observable origin = Observable.create(new FuncWithErrors(NUM_FAILURES)); + Observable.create(retry(origin, NUM_RETRIES)).subscribe(observer); + + InOrder inOrder = inOrder(observer); + // should show 2 attempts (first time fail, second time (1st retry) fail) + inOrder.verify(observer, times(1 + NUM_RETRIES)).onNext("beginningEveryTime"); + // should only retry once, fail again and emit onError + inOrder.verify(observer, times(1)).onError(any(RuntimeException.class)); + // no success + inOrder.verify(observer, never()).onNext("onSuccessOnly"); + inOrder.verify(observer, never()).onCompleted(); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testRetrySuccess() { + int NUM_RETRIES = 3; + int NUM_FAILURES = 2; + @SuppressWarnings("unchecked") + Observer observer = mock(Observer.class); + Observable origin = Observable.create(new FuncWithErrors(NUM_FAILURES)); + Observable.create(retry(origin, NUM_RETRIES)).subscribe(observer); + + InOrder inOrder = inOrder(observer); + // should show 3 attempts + inOrder.verify(observer, times(1 + NUM_FAILURES)).onNext("beginningEveryTime"); + // should have no errors + inOrder.verify(observer, never()).onError(any(Throwable.class)); + // should have a single success + inOrder.verify(observer, times(1)).onNext("onSuccessOnly"); + // should have a single successful onCompleted + inOrder.verify(observer, times(1)).onCompleted(); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testInfiniteRetry() { + int NUM_FAILURES = 20; + @SuppressWarnings("unchecked") + Observer observer = mock(Observer.class); + Observable origin = Observable.create(new FuncWithErrors(NUM_FAILURES)); + Observable.create(retry(origin)).subscribe(observer); + + InOrder inOrder = inOrder(observer); + // should show 3 attempts + inOrder.verify(observer, times(1 + NUM_FAILURES)).onNext("beginningEveryTime"); + // should have no errors + inOrder.verify(observer, never()).onError(any(Throwable.class)); + // should have a single success + inOrder.verify(observer, times(1)).onNext("onSuccessOnly"); + // should have a single successful onCompleted + inOrder.verify(observer, times(1)).onCompleted(); + inOrder.verifyNoMoreInteractions(); + } + + public static class FuncWithErrors implements Observable.OnSubscribeFunc { + + private final int numFailures; + private final AtomicInteger count = new AtomicInteger(0); + + FuncWithErrors(int count) { + this.numFailures = count; + } + + @Override + public Subscription onSubscribe(Observer o) { + o.onNext("beginningEveryTime"); + if (count.incrementAndGet() <= numFailures) { + o.onError(new RuntimeException("forced failure: " + count.get())); + } else { + o.onNext("onSuccessOnly"); + o.onCompleted(); + } + return Subscriptions.empty(); + } + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationSampleTest.java b/rxjava-core/src/test/java/rx/operators/OperationSampleTest.java index a718adbc0a..789fa9cf2f 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationSampleTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationSampleTest.java @@ -1,7 +1,91 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.concurrency.TestScheduler; +import rx.subscriptions.Subscriptions; +import rx.util.functions.Action0; + +import java.util.concurrent.TimeUnit; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; -@Ignore("WIP") public class OperationSampleTest { + private TestScheduler scheduler; + private Observer observer; + + @Before + @SuppressWarnings("unchecked") // due to mocking + public void before() { + scheduler = new TestScheduler(); + observer = mock(Observer.class); + } + + @Test + public void testSample() { + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(final Observer observer1) { + scheduler.schedule(new Action0() { + @Override + public void call() { + observer1.onNext(1L); + } + }, 1, TimeUnit.SECONDS); + scheduler.schedule(new Action0() { + @Override + public void call() { + observer1.onNext(2L); + } + }, 2, TimeUnit.SECONDS); + scheduler.schedule(new Action0() { + @Override + public void call() { + observer1.onCompleted(); + } + }, 3, TimeUnit.SECONDS); + + return Subscriptions.empty(); + } + }); + + Observable sampled = Observable.create(OperationSample.sample(source, 400L, TimeUnit.MILLISECONDS, scheduler)); + sampled.subscribe(observer); + + InOrder inOrder = inOrder(observer); + + scheduler.advanceTimeTo(800L, TimeUnit.MILLISECONDS); + verify(observer, never()).onNext(any(Long.class)); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + scheduler.advanceTimeTo(1200L, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onNext(1L); + verify(observer, never()).onNext(2L); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + scheduler.advanceTimeTo(1600L, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onNext(1L); + verify(observer, never()).onNext(2L); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + scheduler.advanceTimeTo(2000L, TimeUnit.MILLISECONDS); + inOrder.verify(observer, never()).onNext(1L); + inOrder.verify(observer, times(1)).onNext(2L); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + scheduler.advanceTimeTo(3000L, TimeUnit.MILLISECONDS); + inOrder.verify(observer, never()).onNext(1L); + inOrder.verify(observer, times(2)).onNext(2L); + verify(observer, times(1)).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationScanTest.java b/rxjava-core/src/test/java/rx/operators/OperationScanTest.java index aa3d7d6f9e..691df4b0f1 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationScanTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationScanTest.java @@ -1,7 +1,102 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockitoAnnotations; +import rx.Observable; +import rx.Observer; +import rx.util.functions.Func2; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; +import static rx.operators.OperationScan.scan; -@Ignore("WIP") public class OperationScanTest { + + + @Before + public void before() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testScanIntegersWithInitialValue() { + @SuppressWarnings("unchecked") + Observer observer = mock(Observer.class); + + Observable observable = Observable.from(1, 2, 3); + + Observable m = Observable.create(scan(observable, "", new Func2() { + + @Override + public String call(String s, Integer n) { + return s + n.toString(); + } + + })); + m.subscribe(observer); + + verify(observer, never()).onError(any(Throwable.class)); + verify(observer, times(1)).onNext(""); + verify(observer, times(1)).onNext("1"); + verify(observer, times(1)).onNext("12"); + verify(observer, times(1)).onNext("123"); + verify(observer, times(4)).onNext(anyString()); + verify(observer, times(1)).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + } + + @Test + public void testScanIntegersWithoutInitialValue() { + @SuppressWarnings("unchecked") + Observer Observer = mock(Observer.class); + + Observable observable = Observable.from(1, 2, 3); + + Observable m = Observable.create(scan(observable, new Func2() { + + @Override + public Integer call(Integer t1, Integer t2) { + return t1 + t2; + } + + })); + m.subscribe(Observer); + + verify(Observer, never()).onError(any(Throwable.class)); + verify(Observer, never()).onNext(0); + verify(Observer, times(1)).onNext(1); + verify(Observer, times(1)).onNext(3); + verify(Observer, times(1)).onNext(6); + verify(Observer, times(3)).onNext(anyInt()); + verify(Observer, times(1)).onCompleted(); + verify(Observer, never()).onError(any(Throwable.class)); + } + + @Test + public void testScanIntegersWithoutInitialValueAndOnlyOneValue() { + @SuppressWarnings("unchecked") + Observer Observer = mock(Observer.class); + + Observable observable = Observable.from(1); + + Observable m = Observable.create(scan(observable, new Func2() { + + @Override + public Integer call(Integer t1, Integer t2) { + return t1 + t2; + } + + })); + m.subscribe(Observer); + + verify(Observer, never()).onError(any(Throwable.class)); + verify(Observer, never()).onNext(0); + verify(Observer, times(1)).onNext(1); + verify(Observer, times(1)).onNext(anyInt()); + verify(Observer, times(1)).onCompleted(); + verify(Observer, never()).onError(any(Throwable.class)); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationSkipLastTest.java b/rxjava-core/src/test/java/rx/operators/OperationSkipLastTest.java index 9604c718c7..8b1dd163fb 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationSkipLastTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationSkipLastTest.java @@ -1,7 +1,98 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.InOrder; +import rx.Observable; +import rx.Observer; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationSkipLast.skipLast; -@Ignore("WIP") public class OperationSkipLastTest { + + @Test + public void testSkipLastEmpty() { + Observable w = Observable.empty(); + Observable observable = Observable.create(skipLast(w, 2)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, never()).onNext(any(String.class)); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testSkipLast1() { + Observable w = Observable.from("one", "two", "three"); + Observable observable = Observable.create(skipLast(w, 2)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + InOrder inOrder = inOrder(aObserver); + observable.subscribe(aObserver); + inOrder.verify(aObserver, never()).onNext("two"); + inOrder.verify(aObserver, never()).onNext("three"); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testSkipLast2() { + Observable w = Observable.from("one", "two"); + Observable observable = Observable.create(skipLast(w, 2)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, never()).onNext(any(String.class)); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testSkipLastWithZeroCount() { + Observable w = Observable.from("one", "two"); + Observable observable = Observable.create(skipLast(w, 0)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, times(1)).onNext("two"); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testSkipLastWithNull() { + Observable w = Observable.from("one", null, "two"); + Observable observable = Observable.create(skipLast(w, 1)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, times(1)).onNext(null); + verify(aObserver, never()).onNext("two"); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testSkipLastWithNegativeCount() { + Observable w = Observable.from("one"); + Observable observable = Observable.create(skipLast(w, -1)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, never()).onNext(any(String.class)); + verify(aObserver, times(1)).onError( + any(IndexOutOfBoundsException.class)); + verify(aObserver, never()).onCompleted(); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationSkipTest.java b/rxjava-core/src/test/java/rx/operators/OperationSkipTest.java index 1d74ed6302..acc351de34 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationSkipTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationSkipTest.java @@ -1,7 +1,42 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Observable; +import rx.Observer; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationSkip.skip; -@Ignore("WIP") public class OperationSkipTest { + + @Test + public void testSkip1() { + Observable w = Observable.from("one", "two", "three"); + Observable skip = Observable.create(skip(w, 2)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + skip.subscribe(aObserver); + verify(aObserver, never()).onNext("one"); + verify(aObserver, never()).onNext("two"); + verify(aObserver, times(1)).onNext("three"); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testSkip2() { + Observable w = Observable.from("one", "two", "three"); + Observable skip = Observable.create(skip(w, 1)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + skip.subscribe(aObserver); + verify(aObserver, never()).onNext("one"); + verify(aObserver, times(1)).onNext("two"); + verify(aObserver, times(1)).onNext("three"); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationSkipWhileTest.java b/rxjava-core/src/test/java/rx/operators/OperationSkipWhileTest.java index d9347d907e..f0d8391928 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationSkipWhileTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationSkipWhileTest.java @@ -1,7 +1,104 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.InOrder; +import rx.Observable; +import rx.Observer; +import rx.util.functions.Func1; +import rx.util.functions.Func2; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.*; +import static rx.Observable.create; +import static rx.operators.OperationSkipWhile.skipWhile; +import static rx.operators.OperationSkipWhile.skipWhileWithIndex; -@Ignore("WIP") public class OperationSkipWhileTest { + + @SuppressWarnings("unchecked") + Observer w = mock(Observer.class); + + private static final Func1 LESS_THAN_FIVE = new Func1() { + @Override + public Boolean call(Integer v) { + if (v == 42) throw new RuntimeException("that's not the answer to everything!"); + return v < 5; + } + }; + + private static final Func2 INDEX_LESS_THAN_THREE = new Func2() { + @Override + public Boolean call(Integer value, Integer index) { + return index < 3; + } + }; + + @Test + public void testSkipWithIndex() { + Observable src = Observable.from(1, 2, 3, 4, 5); + create(skipWhileWithIndex(src, INDEX_LESS_THAN_THREE)).subscribe(w); + + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext(4); + inOrder.verify(w, times(1)).onNext(5); + inOrder.verify(w, times(1)).onCompleted(); + inOrder.verify(w, never()).onError(any(Throwable.class)); + } + + @Test + public void testSkipEmpty() { + Observable src = Observable.empty(); + create(skipWhile(src, LESS_THAN_FIVE)).subscribe(w); + verify(w, never()).onNext(anyInt()); + verify(w, never()).onError(any(Throwable.class)); + verify(w, times(1)).onCompleted(); + } + + @Test + public void testSkipEverything() { + Observable src = Observable.from(1, 2, 3, 4, 3, 2, 1); + create(skipWhile(src, LESS_THAN_FIVE)).subscribe(w); + verify(w, never()).onNext(anyInt()); + verify(w, never()).onError(any(Throwable.class)); + verify(w, times(1)).onCompleted(); + } + + @Test + public void testSkipNothing() { + Observable src = Observable.from(5, 3, 1); + create(skipWhile(src, LESS_THAN_FIVE)).subscribe(w); + + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext(5); + inOrder.verify(w, times(1)).onNext(3); + inOrder.verify(w, times(1)).onNext(1); + inOrder.verify(w, times(1)).onCompleted(); + inOrder.verify(w, never()).onError(any(Throwable.class)); + } + + @Test + public void testSkipSome() { + Observable src = Observable.from(1, 2, 3, 4, 5, 3, 1, 5); + create(skipWhile(src, LESS_THAN_FIVE)).subscribe(w); + + InOrder inOrder = inOrder(w); + inOrder.verify(w, times(1)).onNext(5); + inOrder.verify(w, times(1)).onNext(3); + inOrder.verify(w, times(1)).onNext(1); + inOrder.verify(w, times(1)).onNext(5); + inOrder.verify(w, times(1)).onCompleted(); + inOrder.verify(w, never()).onError(any(Throwable.class)); + } + + @Test + public void testSkipError() { + Observable src = Observable.from(1, 2, 42, 5, 3, 1); + create(skipWhile(src, LESS_THAN_FIVE)).subscribe(w); + + InOrder inOrder = inOrder(w); + inOrder.verify(w, never()).onNext(anyInt()); + inOrder.verify(w, never()).onCompleted(); + inOrder.verify(w, times(1)).onError(any(RuntimeException.class)); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationSubscribeOnTest.java b/rxjava-core/src/test/java/rx/operators/OperationSubscribeOnTest.java index 495cbc6713..0c260cf8e8 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationSubscribeOnTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationSubscribeOnTest.java @@ -1,7 +1,40 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Observable; +import rx.Observer; +import rx.Scheduler; +import rx.Subscription; +import rx.concurrency.Schedulers; +import rx.test.OperatorTester; +import rx.util.functions.Action0; +import rx.util.functions.Func2; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.isNull; +import static org.mockito.Mockito.*; +import static rx.operators.OperationSubscribeOn.subscribeOn; -@Ignore("WIP") public class OperationSubscribeOnTest { + + @Test + @SuppressWarnings("unchecked") + public void testSubscribeOn() { + Observable w = Observable.from(1, 2, 3); + + Scheduler scheduler = spy(OperatorTester.forwardingScheduler(Schedulers.immediate())); + + Observer observer = mock(Observer.class); + Subscription subscription = Observable.create(subscribeOn(w, scheduler)).subscribe(observer); + + verify(scheduler, times(1)).schedule(isNull(), any(Func2.class)); + subscription.unsubscribe(); + verify(scheduler, times(1)).schedule(any(Action0.class)); + verifyNoMoreInteractions(scheduler); + + verify(observer, times(1)).onNext(1); + verify(observer, times(1)).onNext(2); + verify(observer, times(1)).onNext(3); + verify(observer, times(1)).onCompleted(); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationSumTest.java b/rxjava-core/src/test/java/rx/operators/OperationSumTest.java index c89121e207..9e826d8343 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationSumTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationSumTest.java @@ -1,7 +1,113 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Observable; +import rx.Observer; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyDouble; +import static org.mockito.Matchers.anyFloat; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Mockito.*; +import static rx.operators.OperationSum.*; -@Ignore("WIP") public class OperationSumTest { + + @SuppressWarnings("unchecked") + Observer w = mock(Observer.class); + @SuppressWarnings("unchecked") + Observer wl = mock(Observer.class); + @SuppressWarnings("unchecked") + Observer wf = mock(Observer.class); + @SuppressWarnings("unchecked") + Observer wd = mock(Observer.class); + + @Test + public void testSumOfAFewInts() throws Throwable { + Observable src = Observable.from(1, 2, 3, 4, 5); + sum(src).subscribe(w); + + verify(w, times(1)).onNext(anyInt()); + verify(w).onNext(15); + verify(w, never()).onError(any(Throwable.class)); + verify(w, times(1)).onCompleted(); + } + + @Test + public void testEmptySum() throws Throwable { + Observable src = Observable.empty(); + sum(src).subscribe(w); + + verify(w, times(1)).onNext(anyInt()); + verify(w).onNext(0); + verify(w, never()).onError(any(Throwable.class)); + verify(w, times(1)).onCompleted(); + } + + @Test + public void testSumOfAFewLongs() throws Throwable { + Observable src = Observable.from(1L, 2L, 3L, 4L, 5L); + sumLongs(src).subscribe(wl); + + verify(wl, times(1)).onNext(anyLong()); + verify(wl).onNext(15L); + verify(wl, never()).onError(any(Throwable.class)); + verify(wl, times(1)).onCompleted(); + } + + @Test + public void testEmptySumLongs() throws Throwable { + Observable src = Observable.empty(); + sumLongs(src).subscribe(wl); + + verify(wl, times(1)).onNext(anyLong()); + verify(wl).onNext(0L); + verify(wl, never()).onError(any(Throwable.class)); + verify(wl, times(1)).onCompleted(); + } + + @Test + public void testSumOfAFewFloats() throws Throwable { + Observable src = Observable.from(1.0f); + sumFloats(src).subscribe(wf); + + verify(wf, times(1)).onNext(anyFloat()); + verify(wf).onNext(1.0f); + verify(wf, never()).onError(any(Throwable.class)); + verify(wf, times(1)).onCompleted(); + } + + @Test + public void testEmptySumFloats() throws Throwable { + Observable src = Observable.empty(); + sumFloats(src).subscribe(wf); + + verify(wf, times(1)).onNext(anyFloat()); + verify(wf).onNext(0.0f); + verify(wf, never()).onError(any(Throwable.class)); + verify(wf, times(1)).onCompleted(); + } + + @Test + public void testSumOfAFewDoubles() throws Throwable { + Observable src = Observable.from(0.0d, 1.0d, 0.5d); + sumDoubles(src).subscribe(wd); + + verify(wd, times(1)).onNext(anyDouble()); + verify(wd).onNext(1.5d); + verify(wd, never()).onError(any(Throwable.class)); + verify(wd, times(1)).onCompleted(); + } + + @Test + public void testEmptySumDoubles() throws Throwable { + Observable src = Observable.empty(); + sumDoubles(src).subscribe(wd); + + verify(wd, times(1)).onNext(anyDouble()); + verify(wd).onNext(0.0d); + verify(wd, never()).onError(any(Throwable.class)); + verify(wd, times(1)).onCompleted(); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationSwitchTest.java b/rxjava-core/src/test/java/rx/operators/OperationSwitchTest.java index d91bb804bf..7c8c9ea21a 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationSwitchTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationSwitchTest.java @@ -1,7 +1,368 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.concurrency.TestScheduler; +import rx.subscriptions.Subscriptions; +import rx.util.functions.Action0; + +import java.util.concurrent.TimeUnit; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; -@Ignore("WIP") public class OperationSwitchTest { + + private TestScheduler scheduler; + private Observer observer; + + @Before + @SuppressWarnings("unchecked") + public void before() { + scheduler = new TestScheduler(); + observer = mock(Observer.class); + } + + @Test + public void testSwitchWhenOuterCompleteBeforeInner() { + Observable> source = Observable.create(new Observable.OnSubscribeFunc>() { + @Override + public Subscription onSubscribe(Observer> observer) { + publishNext(observer, 50, Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + publishNext(observer, 70, "one"); + publishNext(observer, 100, "two"); + publishCompleted(observer, 200); + return Subscriptions.empty(); + } + })); + publishCompleted(observer, 60); + + return Subscriptions.empty(); + } + }); + + Observable sampled = Observable.create(OperationSwitch.switchDo(source)); + sampled.subscribe(observer); + + InOrder inOrder = inOrder(observer); + + scheduler.advanceTimeTo(350, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(2)).onNext(anyString()); + inOrder.verify(observer, times(1)).onCompleted(); + } + + @Test + public void testSwitchWhenInnerCompleteBeforeOuter() { + Observable> source = Observable.create(new Observable.OnSubscribeFunc>() { + @Override + public Subscription onSubscribe(Observer> observer) { + publishNext(observer, 10, Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + publishNext(observer, 0, "one"); + publishNext(observer, 10, "two"); + publishCompleted(observer, 20); + return Subscriptions.empty(); + } + })); + + publishNext(observer, 100, Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + publishNext(observer, 0, "three"); + publishNext(observer, 10, "four"); + publishCompleted(observer, 20); + return Subscriptions.empty(); + } + })); + publishCompleted(observer, 200); + + return Subscriptions.empty(); + } + }); + + Observable sampled = Observable.create(OperationSwitch.switchDo(source)); + sampled.subscribe(observer); + + InOrder inOrder = inOrder(observer); + + scheduler.advanceTimeTo(150, TimeUnit.MILLISECONDS); + inOrder.verify(observer, never()).onCompleted(); + inOrder.verify(observer, times(1)).onNext("one"); + inOrder.verify(observer, times(1)).onNext("two"); + inOrder.verify(observer, times(1)).onNext("three"); + inOrder.verify(observer, times(1)).onNext("four"); + + scheduler.advanceTimeTo(250, TimeUnit.MILLISECONDS); + inOrder.verify(observer, never()).onNext(anyString()); + inOrder.verify(observer, times(1)).onCompleted(); + } + + @Test + public void testSwitchWithComplete() { + Observable> source = Observable.create(new Observable.OnSubscribeFunc>() { + @Override + public Subscription onSubscribe(Observer> observer) { + publishNext(observer, 50, Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + publishNext(observer, 60, "one"); + publishNext(observer, 100, "two"); + return Subscriptions.empty(); + } + })); + + publishNext(observer, 200, Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + publishNext(observer, 0, "three"); + publishNext(observer, 100, "four"); + return Subscriptions.empty(); + } + })); + + publishCompleted(observer, 250); + + return Subscriptions.empty(); + } + }); + + Observable sampled = Observable.create(OperationSwitch.switchDo(source)); + sampled.subscribe(observer); + + InOrder inOrder = inOrder(observer); + + scheduler.advanceTimeTo(90, TimeUnit.MILLISECONDS); + inOrder.verify(observer, never()).onNext(anyString()); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + scheduler.advanceTimeTo(125, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onNext("one"); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + scheduler.advanceTimeTo(175, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onNext("two"); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + scheduler.advanceTimeTo(225, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onNext("three"); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + scheduler.advanceTimeTo(350, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onNext("four"); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + } + + @Test + public void testSwitchWithError() { + Observable> source = Observable.create(new Observable.OnSubscribeFunc>() { + @Override + public Subscription onSubscribe(Observer> observer) { + publishNext(observer, 50, Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + publishNext(observer, 50, "one"); + publishNext(observer, 100, "two"); + return Subscriptions.empty(); + } + })); + + publishNext(observer, 200, Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + publishNext(observer, 0, "three"); + publishNext(observer, 100, "four"); + return Subscriptions.empty(); + } + })); + + publishError(observer, 250, new TestException()); + + return Subscriptions.empty(); + } + }); + + Observable sampled = Observable.create(OperationSwitch.switchDo(source)); + sampled.subscribe(observer); + + InOrder inOrder = inOrder(observer); + + scheduler.advanceTimeTo(90, TimeUnit.MILLISECONDS); + inOrder.verify(observer, never()).onNext(anyString()); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + scheduler.advanceTimeTo(125, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onNext("one"); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + scheduler.advanceTimeTo(175, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onNext("two"); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + scheduler.advanceTimeTo(225, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onNext("three"); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + scheduler.advanceTimeTo(350, TimeUnit.MILLISECONDS); + inOrder.verify(observer, never()).onNext(anyString()); + verify(observer, never()).onCompleted(); + verify(observer, times(1)).onError(any(TestException.class)); + } + + @Test + public void testSwitchWithSubsequenceComplete() { + Observable> source = Observable.create(new Observable.OnSubscribeFunc>() { + @Override + public Subscription onSubscribe(Observer> observer) { + publishNext(observer, 50, Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + publishNext(observer, 50, "one"); + publishNext(observer, 100, "two"); + return Subscriptions.empty(); + } + })); + + publishNext(observer, 130, Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + publishCompleted(observer, 0); + return Subscriptions.empty(); + } + })); + + publishNext(observer, 150, Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + publishNext(observer, 50, "three"); + return Subscriptions.empty(); + } + })); + + return Subscriptions.empty(); + } + }); + + Observable sampled = Observable.create(OperationSwitch.switchDo(source)); + sampled.subscribe(observer); + + InOrder inOrder = inOrder(observer); + + scheduler.advanceTimeTo(90, TimeUnit.MILLISECONDS); + inOrder.verify(observer, never()).onNext(anyString()); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + scheduler.advanceTimeTo(125, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onNext("one"); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + scheduler.advanceTimeTo(250, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onNext("three"); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + } + + @Test + public void testSwitchWithSubsequenceError() { + Observable> source = Observable.create(new Observable.OnSubscribeFunc>() { + @Override + public Subscription onSubscribe(Observer> observer) { + publishNext(observer, 50, Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + publishNext(observer, 50, "one"); + publishNext(observer, 100, "two"); + return Subscriptions.empty(); + } + })); + + publishNext(observer, 130, Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + publishError(observer, 0, new TestException()); + return Subscriptions.empty(); + } + })); + + publishNext(observer, 150, Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + publishNext(observer, 50, "three"); + return Subscriptions.empty(); + } + })); + + return Subscriptions.empty(); + } + }); + + Observable sampled = Observable.create(OperationSwitch.switchDo(source)); + sampled.subscribe(observer); + + InOrder inOrder = inOrder(observer); + + scheduler.advanceTimeTo(90, TimeUnit.MILLISECONDS); + inOrder.verify(observer, never()).onNext(anyString()); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + scheduler.advanceTimeTo(125, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onNext("one"); + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(Throwable.class)); + + scheduler.advanceTimeTo(250, TimeUnit.MILLISECONDS); + inOrder.verify(observer, never()).onNext("three"); + verify(observer, never()).onCompleted(); + verify(observer, times(1)).onError(any(TestException.class)); + } + + private void publishCompleted(final Observer observer, long delay) { + scheduler.schedule(new Action0() { + @Override + public void call() { + observer.onCompleted(); + } + }, delay, TimeUnit.MILLISECONDS); + } + + private void publishError(final Observer observer, long delay, final Throwable error) { + scheduler.schedule(new Action0() { + @Override + public void call() { + observer.onError(error); + } + }, delay, TimeUnit.MILLISECONDS); + } + + private void publishNext(final Observer observer, long delay, final T value) { + scheduler.schedule(new Action0() { + @Override + public void call() { + observer.onNext(value); + } + }, delay, TimeUnit.MILLISECONDS); + } + + @SuppressWarnings("serial") + private class TestException extends Throwable { + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationSynchronizeTest.java b/rxjava-core/src/test/java/rx/operators/OperationSynchronizeTest.java index 2dce4a7d32..28d7676c66 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationSynchronizeTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationSynchronizeTest.java @@ -1,7 +1,203 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.Mockito; +import rx.Observable; +import rx.Observer; +import rx.Subscription; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationSynchronize.synchronize; -@Ignore("WIP") public class OperationSynchronizeTest { + + /** + * Ensure onCompleted can not be called after an Unsubscribe + */ + @Test + public void testOnCompletedAfterUnSubscribe() { + TestObservable t = new TestObservable(null); + Observable st = Observable.create(synchronize(Observable.create(t))); + + @SuppressWarnings("unchecked") + Observer w = mock(Observer.class); + Subscription ws = st.subscribe(w); + + t.sendOnNext("one"); + ws.unsubscribe(); + t.sendOnCompleted(); + + verify(w, times(1)).onNext("one"); + verify(w, Mockito.never()).onCompleted(); + } + + /** + * Ensure onNext can not be called after an Unsubscribe + */ + @Test + public void testOnNextAfterUnSubscribe() { + TestObservable t = new TestObservable(null); + Observable st = Observable.create(synchronize(Observable.create(t))); + + @SuppressWarnings("unchecked") + Observer w = mock(Observer.class); + Subscription ws = st.subscribe(w); + + t.sendOnNext("one"); + ws.unsubscribe(); + t.sendOnNext("two"); + + verify(w, times(1)).onNext("one"); + verify(w, Mockito.never()).onNext("two"); + } + + /** + * Ensure onError can not be called after an Unsubscribe + */ + @Test + public void testOnErrorAfterUnSubscribe() { + TestObservable t = new TestObservable(null); + Observable st = Observable.create(synchronize(Observable.create(t))); + + @SuppressWarnings("unchecked") + Observer w = mock(Observer.class); + Subscription ws = st.subscribe(w); + + t.sendOnNext("one"); + ws.unsubscribe(); + t.sendOnError(new RuntimeException("bad")); + + verify(w, times(1)).onNext("one"); + verify(w, Mockito.never()).onError(any(Throwable.class)); + } + + /** + * Ensure onNext can not be called after onError + */ + @Test + public void testOnNextAfterOnError() { + TestObservable t = new TestObservable(null); + Observable st = Observable.create(synchronize(Observable.create(t))); + + @SuppressWarnings("unchecked") + Observer w = mock(Observer.class); + @SuppressWarnings("unused") + Subscription ws = st.subscribe(w); + + t.sendOnNext("one"); + t.sendOnError(new RuntimeException("bad")); + t.sendOnNext("two"); + + verify(w, times(1)).onNext("one"); + verify(w, times(1)).onError(any(Throwable.class)); + verify(w, Mockito.never()).onNext("two"); + } + + /** + * Ensure onCompleted can not be called after onError + */ + @Test + public void testOnCompletedAfterOnError() { + TestObservable t = new TestObservable(null); + Observable st = Observable.create(synchronize(Observable.create(t))); + + @SuppressWarnings("unchecked") + Observer w = mock(Observer.class); + @SuppressWarnings("unused") + Subscription ws = st.subscribe(w); + + t.sendOnNext("one"); + t.sendOnError(new RuntimeException("bad")); + t.sendOnCompleted(); + + verify(w, times(1)).onNext("one"); + verify(w, times(1)).onError(any(Throwable.class)); + verify(w, Mockito.never()).onCompleted(); + } + + /** + * Ensure onNext can not be called after onCompleted + */ + @Test + public void testOnNextAfterOnCompleted() { + TestObservable t = new TestObservable(null); + Observable st = Observable.create(synchronize(Observable.create(t))); + + @SuppressWarnings("unchecked") + Observer w = mock(Observer.class); + @SuppressWarnings("unused") + Subscription ws = st.subscribe(w); + + t.sendOnNext("one"); + t.sendOnCompleted(); + t.sendOnNext("two"); + + verify(w, times(1)).onNext("one"); + verify(w, Mockito.never()).onNext("two"); + verify(w, times(1)).onCompleted(); + verify(w, Mockito.never()).onError(any(Throwable.class)); + } + + /** + * Ensure onError can not be called after onCompleted + */ + @Test + public void testOnErrorAfterOnCompleted() { + TestObservable t = new TestObservable(null); + Observable st = Observable.create(synchronize(Observable.create(t))); + + @SuppressWarnings("unchecked") + Observer w = mock(Observer.class); + @SuppressWarnings("unused") + Subscription ws = st.subscribe(w); + + t.sendOnNext("one"); + t.sendOnCompleted(); + t.sendOnError(new RuntimeException("bad")); + + verify(w, times(1)).onNext("one"); + verify(w, times(1)).onCompleted(); + verify(w, Mockito.never()).onError(any(Throwable.class)); + } + + /** + * A Observable that doesn't do the right thing on UnSubscribe/Error/etc in that it will keep sending events down the pipe regardless of what happens. + */ + private static class TestObservable implements Observable.OnSubscribeFunc { + + Observer observer = null; + + public TestObservable(Subscription s) { + } + + /* used to simulate subscription */ + public void sendOnCompleted() { + observer.onCompleted(); + } + + /* used to simulate subscription */ + public void sendOnNext(String value) { + observer.onNext(value); + } + + /* used to simulate subscription */ + public void sendOnError(Throwable e) { + observer.onError(e); + } + + @Override + public Subscription onSubscribe(final Observer observer) { + this.observer = observer; + return new Subscription() { + + @Override + public void unsubscribe() { + // going to do nothing to pretend I'm a bad Observable that keeps allowing events to be sent + } + + }; + } + + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationTakeLastTest.java b/rxjava-core/src/test/java/rx/operators/OperationTakeLastTest.java index 234e70d543..89fc932b51 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationTakeLastTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationTakeLastTest.java @@ -1,7 +1,97 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.InOrder; +import rx.Observable; +import rx.Observer; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationTakeLast.takeLast; -@Ignore("WIP") public class OperationTakeLastTest { + + @Test + public void testTakeLastEmpty() { + Observable w = Observable.empty(); + Observable take = Observable.create(takeLast(w, 2)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + take.subscribe(aObserver); + verify(aObserver, never()).onNext(any(String.class)); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testTakeLast1() { + Observable w = Observable.from("one", "two", "three"); + Observable take = Observable.create(takeLast(w, 2)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + InOrder inOrder = inOrder(aObserver); + take.subscribe(aObserver); + inOrder.verify(aObserver, times(1)).onNext("two"); + inOrder.verify(aObserver, times(1)).onNext("three"); + verify(aObserver, never()).onNext("one"); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testTakeLast2() { + Observable w = Observable.from("one"); + Observable take = Observable.create(takeLast(w, 10)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + take.subscribe(aObserver); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testTakeLastWithZeroCount() { + Observable w = Observable.from("one"); + Observable take = Observable.create(takeLast(w, 0)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + take.subscribe(aObserver); + verify(aObserver, never()).onNext("one"); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testTakeLastWithNull() { + Observable w = Observable.from("one", null, "three"); + Observable take = Observable.create(takeLast(w, 2)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + take.subscribe(aObserver); + verify(aObserver, never()).onNext("one"); + verify(aObserver, times(1)).onNext(null); + verify(aObserver, times(1)).onNext("three"); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testTakeLastWithNegativeCount() { + Observable w = Observable.from("one"); + Observable take = Observable.create(takeLast(w, -1)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + take.subscribe(aObserver); + verify(aObserver, never()).onNext("one"); + verify(aObserver, times(1)).onError( + any(IndexOutOfBoundsException.class)); + verify(aObserver, never()).onCompleted(); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationTakeTest.java b/rxjava-core/src/test/java/rx/operators/OperationTakeTest.java index eaa1bdf1d4..b02c4925cd 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationTakeTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationTakeTest.java @@ -1,7 +1,213 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.InOrder; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.subscriptions.Subscriptions; +import rx.util.functions.Func1; + +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; +import static rx.operators.OperationTake.take; -@Ignore("WIP") public class OperationTakeTest { + + @Test + public void testTake1() { + Observable w = Observable.from("one", "two", "three"); + Observable take = Observable.create(take(w, 2)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + take.subscribe(aObserver); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, times(1)).onNext("two"); + verify(aObserver, never()).onNext("three"); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testTake2() { + Observable w = Observable.from("one", "two", "three"); + Observable take = Observable.create(take(w, 1)); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + take.subscribe(aObserver); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, never()).onNext("two"); + verify(aObserver, never()).onNext("three"); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test(expected = IllegalArgumentException.class) + public void testTakeWithError() { + Observable.from(1, 2, 3).take(1).map(new Func1() { + public Integer call(Integer t1) { + throw new IllegalArgumentException("some error"); + } + }).toBlockingObservable().single(); + } + + @Test + public void testTakeWithErrorHappeningInOnNext() { + Observable w = Observable.from(1, 2, 3).take(2).map(new Func1() { + public Integer call(Integer t1) { + throw new IllegalArgumentException("some error"); + } + }); + + @SuppressWarnings("unchecked") + Observer observer = mock(Observer.class); + w.subscribe(observer); + InOrder inOrder = inOrder(observer); + inOrder.verify(observer, times(1)).onError(any(IllegalArgumentException.class)); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testTakeWithErrorHappeningInTheLastOnNext() { + Observable w = Observable.from(1, 2, 3).take(1).map(new Func1() { + public Integer call(Integer t1) { + throw new IllegalArgumentException("some error"); + } + }); + + @SuppressWarnings("unchecked") + Observer observer = mock(Observer.class); + w.subscribe(observer); + InOrder inOrder = inOrder(observer); + inOrder.verify(observer, times(1)).onError(any(IllegalArgumentException.class)); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testTakeDoesntLeakErrors() { + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + observer.onNext("one"); + observer.onError(new Throwable("test failed")); + return Subscriptions.empty(); + } + }); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + + Observable.create(take(source, 1)).subscribe(aObserver); + + verify(aObserver, times(1)).onNext("one"); + // even though onError is called we take(1) so shouldn't see it + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + verifyNoMoreInteractions(aObserver); + } + + @Test + public void testTakeZeroDoesntLeakError() { + final AtomicBoolean subscribed = new AtomicBoolean(false); + final AtomicBoolean unSubscribed = new AtomicBoolean(false); + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + subscribed.set(true); + observer.onError(new Throwable("test failed")); + return new Subscription() { + @Override + public void unsubscribe() { + unSubscribed.set(true); + } + }; + } + }); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + + Observable.create(take(source, 0)).subscribe(aObserver); + assertTrue("source subscribed", subscribed.get()); + assertTrue("source unsubscribed", unSubscribed.get()); + + verify(aObserver, never()).onNext(anyString()); + // even though onError is called we take(0) so shouldn't see it + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + verifyNoMoreInteractions(aObserver); + } + + @Test + public void testUnsubscribeAfterTake() { + final Subscription s = mock(Subscription.class); + TestObservableFunc f = new TestObservableFunc(s, "one", "two", "three"); + Observable w = Observable.create(f); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + Observable take = Observable.create(take(w, 1)); + take.subscribe(aObserver); + + // wait for the Observable to complete + try { + f.t.join(); + } catch (Throwable e) { + e.printStackTrace(); + fail(e.getMessage()); + } + + System.out.println("TestObservable thread finished"); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, never()).onNext("two"); + verify(aObserver, never()).onNext("three"); + verify(aObserver, times(1)).onCompleted(); + verify(s, times(1)).unsubscribe(); + verifyNoMoreInteractions(aObserver); + } + + private static class TestObservableFunc implements Observable.OnSubscribeFunc { + + final Subscription s; + final String[] values; + Thread t = null; + + public TestObservableFunc(Subscription s, String... values) { + this.s = s; + this.values = values; + } + + @Override + public Subscription onSubscribe(final Observer observer) { + System.out.println("TestObservable subscribed to ..."); + t = new Thread(new Runnable() { + + @Override + public void run() { + try { + System.out.println("running TestObservable thread"); + for (String s : values) { + System.out.println("TestObservable onNext: " + s); + observer.onNext(s); + } + observer.onCompleted(); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + }); + System.out.println("starting TestObservable thread"); + t.start(); + System.out.println("done starting TestObservable thread"); + return s; + } + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationTakeUntilTest.java b/rxjava-core/src/test/java/rx/operators/OperationTakeUntilTest.java index 22cd5eb078..0e46af91e8 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationTakeUntilTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationTakeUntilTest.java @@ -1,7 +1,164 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Observable; +import rx.Observer; +import rx.Subscription; + +import static org.mockito.Mockito.*; +import static rx.operators.OperationTakeUntil.takeUntil; -@Ignore("WIP") public class OperationTakeUntilTest { + + @Test + @SuppressWarnings("unchecked") + public void testTakeUntil() { + Subscription sSource = mock(Subscription.class); + Subscription sOther = mock(Subscription.class); + TestObservable source = new TestObservable(sSource); + TestObservable other = new TestObservable(sOther); + + Observer result = mock(Observer.class); + Observable stringObservable = takeUntil(Observable.create(source), Observable.create(other)); + stringObservable.subscribe(result); + source.sendOnNext("one"); + source.sendOnNext("two"); + other.sendOnNext("three"); + source.sendOnNext("four"); + source.sendOnCompleted(); + other.sendOnCompleted(); + + verify(result, times(1)).onNext("one"); + verify(result, times(1)).onNext("two"); + verify(result, times(0)).onNext("three"); + verify(result, times(0)).onNext("four"); + verify(sSource, times(1)).unsubscribe(); + verify(sOther, times(1)).unsubscribe(); + + } + + @Test + @SuppressWarnings("unchecked") + public void testTakeUntilSourceCompleted() { + Subscription sSource = mock(Subscription.class); + Subscription sOther = mock(Subscription.class); + TestObservable source = new TestObservable(sSource); + TestObservable other = new TestObservable(sOther); + + Observer result = mock(Observer.class); + Observable stringObservable = takeUntil(Observable.create(source), Observable.create(other)); + stringObservable.subscribe(result); + source.sendOnNext("one"); + source.sendOnNext("two"); + source.sendOnCompleted(); + + verify(result, times(1)).onNext("one"); + verify(result, times(1)).onNext("two"); + verify(sSource, times(1)).unsubscribe(); + verify(sOther, times(1)).unsubscribe(); + + } + + @Test + @SuppressWarnings("unchecked") + public void testTakeUntilSourceError() { + Subscription sSource = mock(Subscription.class); + Subscription sOther = mock(Subscription.class); + TestObservable source = new TestObservable(sSource); + TestObservable other = new TestObservable(sOther); + Throwable error = new Throwable(); + + Observer result = mock(Observer.class); + Observable stringObservable = takeUntil(Observable.create(source), Observable.create(other)); + stringObservable.subscribe(result); + source.sendOnNext("one"); + source.sendOnNext("two"); + source.sendOnError(error); + + verify(result, times(1)).onNext("one"); + verify(result, times(1)).onNext("two"); + verify(result, times(1)).onError(error); + verify(sSource, times(1)).unsubscribe(); + verify(sOther, times(1)).unsubscribe(); + + } + + @Test + @SuppressWarnings("unchecked") + public void testTakeUntilOtherError() { + Subscription sSource = mock(Subscription.class); + Subscription sOther = mock(Subscription.class); + TestObservable source = new TestObservable(sSource); + TestObservable other = new TestObservable(sOther); + Throwable error = new Throwable(); + + Observer result = mock(Observer.class); + Observable stringObservable = takeUntil(Observable.create(source), Observable.create(other)); + stringObservable.subscribe(result); + source.sendOnNext("one"); + source.sendOnNext("two"); + other.sendOnError(error); + + verify(result, times(1)).onNext("one"); + verify(result, times(1)).onNext("two"); + verify(result, times(1)).onError(error); + verify(result, times(0)).onCompleted(); + verify(sSource, times(1)).unsubscribe(); + verify(sOther, times(1)).unsubscribe(); + + } + + @Test + @SuppressWarnings("unchecked") + public void testTakeUntilOtherCompleted() { + Subscription sSource = mock(Subscription.class); + Subscription sOther = mock(Subscription.class); + TestObservable source = new TestObservable(sSource); + TestObservable other = new TestObservable(sOther); + + Observer result = mock(Observer.class); + Observable stringObservable = takeUntil(Observable.create(source), Observable.create(other)); + stringObservable.subscribe(result); + source.sendOnNext("one"); + source.sendOnNext("two"); + other.sendOnCompleted(); + + verify(result, times(1)).onNext("one"); + verify(result, times(1)).onNext("two"); + verify(result, times(0)).onCompleted(); + verify(sSource, times(0)).unsubscribe(); + verify(sOther, times(0)).unsubscribe(); + + } + + private static class TestObservable implements Observable.OnSubscribeFunc { + + Observer observer = null; + Subscription s; + + public TestObservable(Subscription s) { + this.s = s; + } + + /* used to simulate subscription */ + public void sendOnCompleted() { + observer.onCompleted(); + } + + /* used to simulate subscription */ + public void sendOnNext(String value) { + observer.onNext(value); + } + + /* used to simulate subscription */ + public void sendOnError(Throwable e) { + observer.onError(e); + } + + @Override + public Subscription onSubscribe(final Observer observer) { + this.observer = observer; + return s; + } + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationTakeWhileTest.java b/rxjava-core/src/test/java/rx/operators/OperationTakeWhileTest.java new file mode 100644 index 0000000000..8109c818e0 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationTakeWhileTest.java @@ -0,0 +1,204 @@ +package rx.operators; + +import org.junit.Test; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.subjects.PublishSubject; +import rx.subjects.Subject; +import rx.subscriptions.Subscriptions; +import rx.util.functions.Func1; +import rx.util.functions.Func2; + +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationTakeWhile.takeWhile; +import static rx.operators.OperationTakeWhile.takeWhileWithIndex; + +public class OperationTakeWhileTest { + + @Test + public void testTakeWhile1() { + Observable w = Observable.from(1, 2, 3); + Observable take = Observable.create(takeWhile(w, new Func1() { + @Override + public Boolean call(Integer input) { + return input < 3; + } + })); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + take.subscribe(aObserver); + verify(aObserver, times(1)).onNext(1); + verify(aObserver, times(1)).onNext(2); + verify(aObserver, never()).onNext(3); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testTakeWhileOnSubject1() { + Subject s = PublishSubject.create(); + Observable take = Observable.create(takeWhile(s, new Func1() { + @Override + public Boolean call(Integer input) { + return input < 3; + } + })); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + take.subscribe(aObserver); + + s.onNext(1); + s.onNext(2); + s.onNext(3); + s.onNext(4); + s.onNext(5); + s.onCompleted(); + + verify(aObserver, times(1)).onNext(1); + verify(aObserver, times(1)).onNext(2); + verify(aObserver, never()).onNext(3); + verify(aObserver, never()).onNext(4); + verify(aObserver, never()).onNext(5); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testTakeWhile2() { + Observable w = Observable.from("one", "two", "three"); + Observable take = Observable.create(takeWhileWithIndex(w, new Func2() { + @Override + public Boolean call(String input, Integer index) { + return index < 2; + } + })); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + take.subscribe(aObserver); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, times(1)).onNext("two"); + verify(aObserver, never()).onNext("three"); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testTakeWhileDoesntLeakErrors() { + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + observer.onNext("one"); + observer.onError(new Throwable("test failed")); + return Subscriptions.empty(); + } + }); + + Observable.create(takeWhile(source, new Func1() { + @Override + public Boolean call(String s) { + return false; + } + })).toBlockingObservable().last(); + } + + @Test + public void testTakeWhileProtectsPredicateCall() { + TestObservable source = new TestObservable(mock(Subscription.class), "one"); + final RuntimeException testException = new RuntimeException("test exception"); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + Observable take = Observable.create(takeWhile(Observable.create(source), new Func1() { + @Override + public Boolean call(String s) { + throw testException; + } + })); + take.subscribe(aObserver); + + // wait for the Observable to complete + try { + source.t.join(); + } catch (Throwable e) { + e.printStackTrace(); + fail(e.getMessage()); + } + + verify(aObserver, never()).onNext(any(String.class)); + verify(aObserver, times(1)).onError(testException); + } + + @Test + public void testUnsubscribeAfterTake() { + Subscription s = mock(Subscription.class); + TestObservable w = new TestObservable(s, "one", "two", "three"); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + Observable take = Observable.create(takeWhileWithIndex(Observable.create(w), new Func2() { + @Override + public Boolean call(String s, Integer index) { + return index < 1; + } + })); + take.subscribe(aObserver); + + // wait for the Observable to complete + try { + w.t.join(); + } catch (Throwable e) { + e.printStackTrace(); + fail(e.getMessage()); + } + + System.out.println("TestObservable thread finished"); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, never()).onNext("two"); + verify(aObserver, never()).onNext("three"); + verify(s, times(1)).unsubscribe(); + } + + private static class TestObservable implements Observable.OnSubscribeFunc { + + final Subscription s; + final String[] values; + Thread t = null; + + public TestObservable(Subscription s, String... values) { + this.s = s; + this.values = values; + } + + @Override + public Subscription onSubscribe(final Observer observer) { + System.out.println("TestObservable subscribed to ..."); + t = new Thread(new Runnable() { + + @Override + public void run() { + try { + System.out.println("running TestObservable thread"); + for (String s : values) { + System.out.println("TestObservable onNext: " + s); + observer.onNext(s); + } + observer.onCompleted(); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + }); + System.out.println("starting TestObservable thread"); + t.start(); + System.out.println("done starting TestObservable thread"); + return s; + } + } +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationThrottleFirstTest.java b/rxjava-core/src/test/java/rx/operators/OperationThrottleFirstTest.java index 66301abfca..76cac5dfe9 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationThrottleFirstTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationThrottleFirstTest.java @@ -1,7 +1,114 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.concurrency.TestScheduler; +import rx.subscriptions.Subscriptions; +import rx.util.functions.Action0; + +import java.util.concurrent.TimeUnit; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; -@Ignore("WIP") public class OperationThrottleFirstTest { + + private TestScheduler scheduler; + private Observer observer; + + @Before + @SuppressWarnings("unchecked") + public void before() { + scheduler = new TestScheduler(); + observer = mock(Observer.class); + } + + @Test + public void testThrottlingWithCompleted() { + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + publishNext(observer, 100, "one"); // publish as it's first + publishNext(observer, 300, "two"); // skip as it's last within the first 400 + publishNext(observer, 900, "three"); // publish + publishNext(observer, 905, "four"); // skip + publishCompleted(observer, 1000); // Should be published as soon as the timeout expires. + + return Subscriptions.empty(); + } + }); + + Observable sampled = Observable.create(OperationThrottleFirst.throttleFirst(source, 400, TimeUnit.MILLISECONDS, scheduler)); + sampled.subscribe(observer); + + InOrder inOrder = inOrder(observer); + + scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS); + inOrder.verify(observer, times(1)).onNext("one"); + inOrder.verify(observer, times(0)).onNext("two"); + inOrder.verify(observer, times(1)).onNext("three"); + inOrder.verify(observer, times(0)).onNext("four"); + inOrder.verify(observer, times(1)).onCompleted(); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testThrottlingWithError() { + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + Exception error = new TestException(); + publishNext(observer, 100, "one"); // Should be published since it is first + publishNext(observer, 200, "two"); // Should be skipped since onError will arrive before the timeout expires + publishError(observer, 300, error); // Should be published as soon as the timeout expires. + + return Subscriptions.empty(); + } + }); + + Observable sampled = Observable.create(OperationThrottleFirst.throttleFirst(source, 400, TimeUnit.MILLISECONDS, scheduler)); + sampled.subscribe(observer); + + InOrder inOrder = inOrder(observer); + + scheduler.advanceTimeTo(400, TimeUnit.MILLISECONDS); + inOrder.verify(observer).onNext("one"); + inOrder.verify(observer).onError(any(TestException.class)); + inOrder.verifyNoMoreInteractions(); + } + + private void publishCompleted(final Observer observer, long delay) { + scheduler.schedule(new Action0() { + @Override + public void call() { + observer.onCompleted(); + } + }, delay, TimeUnit.MILLISECONDS); + } + + private void publishError(final Observer observer, long delay, final Exception error) { + scheduler.schedule(new Action0() { + @Override + public void call() { + observer.onError(error); + } + }, delay, TimeUnit.MILLISECONDS); + } + + private void publishNext(final Observer observer, long delay, final T value) { + scheduler.schedule(new Action0() { + @Override + public void call() { + observer.onNext(value); + } + }, delay, TimeUnit.MILLISECONDS); + } + + @SuppressWarnings("serial") + private class TestException extends Exception { + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationTimeIntervalTest.java b/rxjava-core/src/test/java/rx/operators/OperationTimeIntervalTest.java new file mode 100644 index 0000000000..6ce6504b05 --- /dev/null +++ b/rxjava-core/src/test/java/rx/operators/OperationTimeIntervalTest.java @@ -0,0 +1,60 @@ +package rx.operators; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import rx.Observable; +import rx.Observer; +import rx.concurrency.TestScheduler; +import rx.subjects.PublishSubject; +import rx.util.TimeInterval; + +import java.util.concurrent.TimeUnit; + +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.times; + +public class OperationTimeIntervalTest { + + private static final TimeUnit TIME_UNIT = TimeUnit.MILLISECONDS; + + @Mock + private Observer> observer; + + private TestScheduler testScheduler; + private PublishSubject subject; + private Observable> observable; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + testScheduler = new TestScheduler(); + subject = PublishSubject.create(); + observable = subject.timeInterval(testScheduler); + } + + @Test + public void testTimeInterval() { + InOrder inOrder = inOrder(observer); + observable.subscribe(observer); + + testScheduler.advanceTimeBy(1000, TIME_UNIT); + subject.onNext(1); + testScheduler.advanceTimeBy(2000, TIME_UNIT); + subject.onNext(2); + testScheduler.advanceTimeBy(3000, TIME_UNIT); + subject.onNext(3); + subject.onCompleted(); + + inOrder.verify(observer, times(1)).onNext( + new TimeInterval(1000, 1)); + inOrder.verify(observer, times(1)).onNext( + new TimeInterval(2000, 2)); + inOrder.verify(observer, times(1)).onNext( + new TimeInterval(3000, 3)); + inOrder.verify(observer, times(1)).onCompleted(); + inOrder.verifyNoMoreInteractions(); + } +} diff --git a/rxjava-core/src/test/java/rx/operators/OperationToObservableFutureTest.java b/rxjava-core/src/test/java/rx/operators/OperationToObservableFutureTest.java index 3f58b63911..f3891128e1 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationToObservableFutureTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationToObservableFutureTest.java @@ -1,7 +1,47 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import rx.Observer; +import rx.Subscription; + +import java.util.concurrent.Future; + +import static org.mockito.Mockito.*; +import static rx.operators.OperationToObservableFuture.ToObservableFuture; -@Ignore("WIP") public class OperationToObservableFutureTest { + + @Test + public void testSuccess() throws Exception { + Future future = mock(Future.class); + Object value = new Object(); + when(future.get()).thenReturn(value); + ToObservableFuture ob = new ToObservableFuture(future); + Observer o = mock(Observer.class); + + Subscription sub = ob.onSubscribe(o); + sub.unsubscribe(); + + verify(o, times(1)).onNext(value); + verify(o, times(1)).onCompleted(); + verify(o, never()).onError(null); + verify(future, never()).cancel(true); + } + + @Test + public void testFailure() throws Exception { + Future future = mock(Future.class); + RuntimeException e = new RuntimeException(); + when(future.get()).thenThrow(e); + ToObservableFuture ob = new ToObservableFuture(future); + Observer o = mock(Observer.class); + + Subscription sub = ob.onSubscribe(o); + sub.unsubscribe(); + + verify(o, never()).onNext(null); + verify(o, never()).onCompleted(); + verify(o, times(1)).onError(e); + verify(future, never()).cancel(true); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationToObservableIterableTest.java b/rxjava-core/src/test/java/rx/operators/OperationToObservableIterableTest.java index 1805e1cbcd..a24cb92694 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationToObservableIterableTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationToObservableIterableTest.java @@ -1,7 +1,32 @@ package rx.operators; import org.junit.Ignore; +import org.junit.Test; +import org.mockito.Mockito; +import rx.Observable; +import rx.Observer; + +import java.util.Arrays; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static rx.operators.OperationToObservableIterable.toObservableIterable; -@Ignore("WIP") public class OperationToObservableIterableTest { + + @Test + public void testIterable() { + Observable observable = Observable.create(toObservableIterable(Arrays. asList("one", "two", "three"))); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, times(1)).onNext("two"); + verify(aObserver, times(1)).onNext("three"); + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationToObservableListTest.java b/rxjava-core/src/test/java/rx/operators/OperationToObservableListTest.java index 49c7409e86..12e47aa080 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationToObservableListTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationToObservableListTest.java @@ -1,7 +1,53 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.Mockito; +import rx.Observable; +import rx.Observer; + +import java.util.Arrays; +import java.util.List; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationToObservableList.toObservableList; -@Ignore("WIP") public class OperationToObservableListTest { + + @Test + public void testList() { + Observable w = Observable.from("one", "two", "three"); + Observable> observable = Observable.create(toObservableList(w)); + + @SuppressWarnings("unchecked") + Observer> aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, times(1)).onNext(Arrays.asList("one", "two", "three")); + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testListMultipleObservers() { + Observable w = Observable.from("one", "two", "three"); + Observable> observable = Observable.create(toObservableList(w)); + + @SuppressWarnings("unchecked") + Observer> o1 = mock(Observer.class); + observable.subscribe(o1); + + @SuppressWarnings("unchecked") + Observer> o2 = mock(Observer.class); + observable.subscribe(o2); + + List expected = Arrays.asList("one", "two", "three"); + + verify(o1, times(1)).onNext(expected); + verify(o1, Mockito.never()).onError(any(Throwable.class)); + verify(o1, times(1)).onCompleted(); + + verify(o2, times(1)).onNext(expected); + verify(o2, Mockito.never()).onError(any(Throwable.class)); + verify(o2, times(1)).onCompleted(); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationToObservableSortedListTest.java b/rxjava-core/src/test/java/rx/operators/OperationToObservableSortedListTest.java index 62efef680d..11b6c9ff6a 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationToObservableSortedListTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationToObservableSortedListTest.java @@ -1,7 +1,50 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.Mockito; +import rx.Observable; +import rx.Observer; +import rx.util.functions.Func2; + +import java.util.Arrays; +import java.util.List; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static rx.operators.OperationToObservableSortedList.toSortedList; -@Ignore("WIP") public class OperationToObservableSortedListTest { + + @Test + public void testSortedList() { + Observable w = Observable.from(1, 3, 2, 5, 4); + Observable> observable = Observable.create(toSortedList(w)); + + @SuppressWarnings("unchecked") + Observer> aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, times(1)).onNext(Arrays.asList(1, 2, 3, 4, 5)); + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testSortedListWithCustomFunction() { + Observable w = Observable.from(1, 3, 2, 5, 4); + Observable> observable = Observable.create(toSortedList(w, new Func2() { + + @Override + public Integer call(Integer t1, Integer t2) { + return t2 - t1; + } + + })); + + @SuppressWarnings("unchecked") + Observer> aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, times(1)).onNext(Arrays.asList(5, 4, 3, 2, 1)); + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationWindowTest.java b/rxjava-core/src/test/java/rx/operators/OperationWindowTest.java index 0e602254f5..8a552f534f 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationWindowTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationWindowTest.java @@ -1,7 +1,315 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Before; +import org.junit.Test; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.concurrency.TestScheduler; +import rx.subscriptions.Subscriptions; +import rx.util.Closing; +import rx.util.Closings; +import rx.util.Opening; +import rx.util.Openings; +import rx.util.functions.Action0; +import rx.util.functions.Action1; +import rx.util.functions.Func0; +import rx.util.functions.Func1; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static rx.operators.OperationWindow.window; -@Ignore("WIP") public class OperationWindowTest { + + private TestScheduler scheduler; + + @Before + public void before() { + scheduler = new TestScheduler(); + } + + private static List> toLists(Observable> observable) { + final List list = new ArrayList(); + final List> lists = new ArrayList>(); + + observable.subscribe(new Action1>() { + @Override + public void call(Observable tObservable) { + tObservable.subscribe(new Action1() { + @Override + public void call(T t) { + list.add(t); + } + }); + lists.add(new ArrayList(list)); + list.clear(); + } + }); + return lists; + } + + @Test + public void testNonOverlappingWindows() { + Observable subject = Observable.from("one", "two", "three", "four", "five"); + Observable> windowed = Observable.create(window(subject, 3)); + + List> windows = toLists(windowed); + + assertEquals(2, windows.size()); + assertEquals(list("one", "two", "three"), windows.get(0)); + assertEquals(list("four", "five"), windows.get(1)); + } + + @Test + public void testSkipAndCountGaplessEindows() { + Observable subject = Observable.from("one", "two", "three", "four", "five"); + Observable> windowed = Observable.create(window(subject, 3, 3)); + + List> windows = toLists(windowed); + + assertEquals(2, windows.size()); + assertEquals(list("one", "two", "three"), windows.get(0)); + assertEquals(list("four", "five"), windows.get(1)); + } + + @Test + public void testOverlappingWindows() { + Observable subject = Observable.from("zero", "one", "two", "three", "four", "five"); + Observable> windowed = Observable.create(window(subject, 3, 1)); + + List> windows = toLists(windowed); + + assertEquals(6, windows.size()); + assertEquals(list("zero", "one", "two"), windows.get(0)); + assertEquals(list("one", "two", "three"), windows.get(1)); + assertEquals(list("two", "three", "four"), windows.get(2)); + assertEquals(list("three", "four", "five"), windows.get(3)); + assertEquals(list("four", "five"), windows.get(4)); + assertEquals(list("five"), windows.get(5)); + } + + @Test + public void testSkipAndCountWindowsWithGaps() { + Observable subject = Observable.from("one", "two", "three", "four", "five"); + Observable> windowed = Observable.create(window(subject, 2, 3)); + + List> windows = toLists(windowed); + + assertEquals(2, windows.size()); + assertEquals(list("one", "two"), windows.get(0)); + assertEquals(list("four", "five"), windows.get(1)); + } + + @Test + public void testTimedAndCount() { + final List list = new ArrayList(); + final List> lists = new ArrayList>(); + + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + push(observer, "one", 10); + push(observer, "two", 90); + push(observer, "three", 110); + push(observer, "four", 190); + push(observer, "five", 210); + complete(observer, 250); + return Subscriptions.empty(); + } + }); + + Observable> windowed = Observable.create(window(source, 100, TimeUnit.MILLISECONDS, 2, scheduler)); + windowed.subscribe(observeWindow(list, lists)); + + scheduler.advanceTimeTo(100, TimeUnit.MILLISECONDS); + assertEquals(1, lists.size()); + assertEquals(lists.get(0), list("one", "two")); + + scheduler.advanceTimeTo(200, TimeUnit.MILLISECONDS); + assertEquals(2, lists.size()); + assertEquals(lists.get(1), list("three", "four")); + + scheduler.advanceTimeTo(300, TimeUnit.MILLISECONDS); + assertEquals(3, lists.size()); + assertEquals(lists.get(2), list("five")); + } + + @Test + public void testTimed() { + final List list = new ArrayList(); + final List> lists = new ArrayList>(); + + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + push(observer, "one", 98); + push(observer, "two", 99); + push(observer, "three", 100); + push(observer, "four", 101); + push(observer, "five", 102); + complete(observer, 150); + return Subscriptions.empty(); + } + }); + + Observable> windowed = Observable.create(window(source, 100, TimeUnit.MILLISECONDS, scheduler)); + windowed.subscribe(observeWindow(list, lists)); + + scheduler.advanceTimeTo(101, TimeUnit.MILLISECONDS); + assertEquals(1, lists.size()); + assertEquals(lists.get(0), list("one", "two", "three")); + + scheduler.advanceTimeTo(201, TimeUnit.MILLISECONDS); + assertEquals(2, lists.size()); + assertEquals(lists.get(1), list("four", "five")); + } + + @Test + public void testObservableBasedOpenerAndCloser() { + final List list = new ArrayList(); + final List> lists = new ArrayList>(); + + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + push(observer, "one", 10); + push(observer, "two", 60); + push(observer, "three", 110); + push(observer, "four", 160); + push(observer, "five", 210); + complete(observer, 500); + return Subscriptions.empty(); + } + }); + + Observable openings = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + push(observer, Openings.create(), 50); + push(observer, Openings.create(), 200); + complete(observer, 250); + return Subscriptions.empty(); + } + }); + + Func1> closer = new Func1>() { + @Override + public Observable call(Opening opening) { + return Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + push(observer, Closings.create(), 100); + complete(observer, 101); + return Subscriptions.empty(); + } + }); + } + }; + + Observable> windowed = Observable.create(window(source, openings, closer)); + windowed.subscribe(observeWindow(list, lists)); + + scheduler.advanceTimeTo(500, TimeUnit.MILLISECONDS); + assertEquals(2, lists.size()); + assertEquals(lists.get(0), list("two", "three")); + assertEquals(lists.get(1), list("five")); + } + + @Test + public void testObservableBasedCloser() { + final List list = new ArrayList(); + final List> lists = new ArrayList>(); + + Observable source = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + push(observer, "one", 10); + push(observer, "two", 60); + push(observer, "three", 110); + push(observer, "four", 160); + push(observer, "five", 210); + complete(observer, 250); + return Subscriptions.empty(); + } + }); + + Func0> closer = new Func0>() { + @Override + public Observable call() { + return Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(Observer observer) { + push(observer, Closings.create(), 100); + complete(observer, 101); + return Subscriptions.empty(); + } + }); + } + }; + + Observable> windowed = Observable.create(window(source, closer)); + windowed.subscribe(observeWindow(list, lists)); + + scheduler.advanceTimeTo(500, TimeUnit.MILLISECONDS); + assertEquals(3, lists.size()); + assertEquals(lists.get(0), list("one", "two")); + assertEquals(lists.get(1), list("three", "four")); + assertEquals(lists.get(2), list("five")); + } + + private List list(String... args) { + List list = new ArrayList(); + for (String arg : args) { + list.add(arg); + } + return list; + } + + private void push(final Observer observer, final T value, int delay) { + scheduler.schedule(new Action0() { + @Override + public void call() { + observer.onNext(value); + } + }, delay, TimeUnit.MILLISECONDS); + } + + private void complete(final Observer observer, int delay) { + scheduler.schedule(new Action0() { + @Override + public void call() { + observer.onCompleted(); + } + }, delay, TimeUnit.MILLISECONDS); + } + + private Action1> observeWindow(final List list, final List> lists) { + return new Action1>() { + @Override + public void call(Observable stringObservable) { + stringObservable.subscribe(new Observer() { + @Override + public void onCompleted() { + lists.add(new ArrayList(list)); + list.clear(); + } + + @Override + public void onError(Throwable e) { + fail(e.getMessage()); + } + + @Override + public void onNext(String args) { + list.add(args); + } + }); + } + }; + } } diff --git a/rxjava-core/src/test/java/rx/operators/OperationZipTest.java b/rxjava-core/src/test/java/rx/operators/OperationZipTest.java index 3e027193ab..2a73ac3eab 100644 --- a/rxjava-core/src/test/java/rx/operators/OperationZipTest.java +++ b/rxjava-core/src/test/java/rx/operators/OperationZipTest.java @@ -1,7 +1,584 @@ package rx.operators; import org.junit.Ignore; +import org.junit.Test; +import org.mockito.InOrder; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.subscriptions.Subscriptions; +import rx.util.functions.Func2; +import rx.util.functions.Func3; +import rx.util.functions.FuncN; +import rx.util.functions.Functions; + +import java.util.Arrays; +import java.util.Collection; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; +import static rx.operators.OperationZip.Aggregator; +import static rx.operators.OperationZip.ZipObserver; +import static rx.operators.OperationZip.zip; -@Ignore("WIP") public class OperationZipTest { + + @SuppressWarnings("unchecked") + @Test + public void testCollectionSizeDifferentThanFunction() { + FuncN zipr = Functions.fromFunc(getConcatStringIntegerIntArrayZipr()); + //Func3 + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + + @SuppressWarnings("rawtypes") + Collection ws = java.util.Collections.singleton(Observable.from("one", "two")); + Observable w = Observable.create(zip(ws, zipr)); + w.subscribe(aObserver); + + verify(aObserver, times(1)).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + verify(aObserver, never()).onNext(any(String.class)); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testZippingDifferentLengthObservableSequences1() { + Observer w = mock(Observer.class); + + TestObservable w1 = new TestObservable(); + TestObservable w2 = new TestObservable(); + TestObservable w3 = new TestObservable(); + + Observable zipW = Observable.create(zip(Observable.create(w1), Observable.create(w2), Observable.create(w3), getConcat3StringsZipr())); + zipW.subscribe(w); + + /* simulate sending data */ + // once for w1 + w1.observer.onNext("1a"); + w1.observer.onCompleted(); + // twice for w2 + w2.observer.onNext("2a"); + w2.observer.onNext("2b"); + w2.observer.onCompleted(); + // 4 times for w3 + w3.observer.onNext("3a"); + w3.observer.onNext("3b"); + w3.observer.onNext("3c"); + w3.observer.onNext("3d"); + w3.observer.onCompleted(); + + /* we should have been called 1 time on the Observer */ + InOrder inOrder = inOrder(w); + inOrder.verify(w).onNext("1a2a3a"); + + inOrder.verify(w, times(1)).onCompleted(); + } + + @Test + public void testZippingDifferentLengthObservableSequences2() { + @SuppressWarnings("unchecked") + Observer w = mock(Observer.class); + + TestObservable w1 = new TestObservable(); + TestObservable w2 = new TestObservable(); + TestObservable w3 = new TestObservable(); + + Observable zipW = Observable.create(zip(Observable.create(w1), Observable.create(w2), Observable.create(w3), getConcat3StringsZipr())); + zipW.subscribe(w); + + /* simulate sending data */ + // 4 times for w1 + w1.observer.onNext("1a"); + w1.observer.onNext("1b"); + w1.observer.onNext("1c"); + w1.observer.onNext("1d"); + w1.observer.onCompleted(); + // twice for w2 + w2.observer.onNext("2a"); + w2.observer.onNext("2b"); + w2.observer.onCompleted(); + // 1 times for w3 + w3.observer.onNext("3a"); + w3.observer.onCompleted(); + + /* we should have been called 1 time on the Observer */ + InOrder inOrder = inOrder(w); + inOrder.verify(w).onNext("1a2a3a"); + + inOrder.verify(w, times(1)).onCompleted(); + + } + + /** + * Testing internal private logic due to the complexity so I want to use TDD to test as a I build it rather than relying purely on the overall functionality expected by the public methods. + */ + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testAggregatorSimple() { + FuncN zipr = getConcatZipr(); + /* create the aggregator which will execute the zip function when all Observables provide values */ + Aggregator a = new Aggregator(zipr); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + a.onSubscribe(aObserver); + + /* mock the Observable Observers that are 'pushing' data for us */ + ZipObserver r1 = mock(ZipObserver.class); + ZipObserver r2 = mock(ZipObserver.class); + + /* pretend we're starting up */ + a.addObserver(r1); + a.addObserver(r2); + + /* simulate the Observables pushing data into the aggregator */ + a.next(r1, "hello"); + a.next(r2, "world"); + + InOrder inOrder = inOrder(aObserver); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + inOrder.verify(aObserver, times(1)).onNext("helloworld"); + + a.next(r1, "hello "); + a.next(r2, "again"); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + inOrder.verify(aObserver, times(1)).onNext("hello again"); + + a.complete(r1); + a.complete(r2); + + inOrder.verify(aObserver, never()).onNext(anyString()); + verify(aObserver, times(1)).onCompleted(); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testAggregatorDifferentSizedResultsWithOnComplete() { + FuncN zipr = getConcatZipr(); + /* create the aggregator which will execute the zip function when all Observables provide values */ + Aggregator a = new Aggregator(zipr); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + a.onSubscribe(aObserver); + + /* mock the Observable Observers that are 'pushing' data for us */ + ZipObserver r1 = mock(ZipObserver.class); + ZipObserver r2 = mock(ZipObserver.class); + + /* pretend we're starting up */ + a.addObserver(r1); + a.addObserver(r2); + + /* simulate the Observables pushing data into the aggregator */ + a.next(r1, "hello"); + a.next(r2, "world"); + a.complete(r2); + + InOrder inOrder = inOrder(aObserver); + + inOrder.verify(aObserver, never()).onError(any(Throwable.class)); + inOrder.verify(aObserver, never()).onCompleted(); + inOrder.verify(aObserver, times(1)).onNext("helloworld"); + + a.next(r1, "hi"); + a.complete(r1); + + inOrder.verify(aObserver, never()).onError(any(Throwable.class)); + inOrder.verify(aObserver, times(1)).onCompleted(); + inOrder.verify(aObserver, never()).onNext(anyString()); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testAggregateMultipleTypes() { + FuncN zipr = getConcatZipr(); + /* create the aggregator which will execute the zip function when all Observables provide values */ + Aggregator a = new Aggregator(zipr); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + a.onSubscribe(aObserver); + + /* mock the Observable Observers that are 'pushing' data for us */ + ZipObserver r1 = mock(ZipObserver.class); + ZipObserver r2 = mock(ZipObserver.class); + + /* pretend we're starting up */ + a.addObserver(r1); + a.addObserver(r2); + + /* simulate the Observables pushing data into the aggregator */ + a.next(r1, "hello"); + a.next(r2, "world"); + a.complete(r2); + + InOrder inOrder = inOrder(aObserver); + + inOrder.verify(aObserver, never()).onError(any(Throwable.class)); + inOrder.verify(aObserver, never()).onCompleted(); + inOrder.verify(aObserver, times(1)).onNext("helloworld"); + + a.next(r1, "hi"); + a.complete(r1); + + inOrder.verify(aObserver, never()).onError(any(Throwable.class)); + inOrder.verify(aObserver, times(1)).onCompleted(); + inOrder.verify(aObserver, never()).onNext(anyString()); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testAggregate3Types() { + FuncN zipr = getConcatZipr(); + /* create the aggregator which will execute the zip function when all Observables provide values */ + Aggregator a = new Aggregator(zipr); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + a.onSubscribe(aObserver); + + /* mock the Observable Observers that are 'pushing' data for us */ + ZipObserver r1 = mock(ZipObserver.class); + ZipObserver r2 = mock(ZipObserver.class); + ZipObserver r3 = mock(ZipObserver.class); + + /* pretend we're starting up */ + a.addObserver(r1); + a.addObserver(r2); + a.addObserver(r3); + + /* simulate the Observables pushing data into the aggregator */ + a.next(r1, "hello"); + a.next(r2, 2); + a.next(r3, new int[] { 5, 6, 7 }); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + verify(aObserver, times(1)).onNext("hello2[5, 6, 7]"); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testAggregatorsWithDifferentSizesAndTiming() { + FuncN zipr = getConcatZipr(); + /* create the aggregator which will execute the zip function when all Observables provide values */ + Aggregator a = new Aggregator(zipr); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + a.onSubscribe(aObserver); + + /* mock the Observable Observers that are 'pushing' data for us */ + ZipObserver r1 = mock(ZipObserver.class); + ZipObserver r2 = mock(ZipObserver.class); + + /* pretend we're starting up */ + a.addObserver(r1); + a.addObserver(r2); + + /* simulate the Observables pushing data into the aggregator */ + a.next(r1, "one"); + a.next(r1, "two"); + a.next(r1, "three"); + a.next(r2, "A"); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + verify(aObserver, times(1)).onNext("oneA"); + + a.next(r1, "four"); + a.complete(r1); + a.next(r2, "B"); + verify(aObserver, times(1)).onNext("twoB"); + a.next(r2, "C"); + verify(aObserver, times(1)).onNext("threeC"); + a.next(r2, "D"); + verify(aObserver, times(1)).onNext("fourD"); + a.next(r2, "E"); + verify(aObserver, never()).onNext("E"); + a.complete(r2); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testAggregatorError() { + FuncN zipr = getConcatZipr(); + /* create the aggregator which will execute the zip function when all Observables provide values */ + Aggregator a = new Aggregator(zipr); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + a.onSubscribe(aObserver); + + /* mock the Observable Observers that are 'pushing' data for us */ + ZipObserver r1 = mock(ZipObserver.class); + ZipObserver r2 = mock(ZipObserver.class); + + /* pretend we're starting up */ + a.addObserver(r1); + a.addObserver(r2); + + /* simulate the Observables pushing data into the aggregator */ + a.next(r1, "hello"); + a.next(r2, "world"); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + verify(aObserver, times(1)).onNext("helloworld"); + + a.error(r1, new RuntimeException("")); + a.next(r1, "hello"); + a.next(r2, "again"); + + verify(aObserver, times(1)).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + // we don't want to be called again after an error + verify(aObserver, times(0)).onNext("helloagain"); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testAggregatorUnsubscribe() { + FuncN zipr = getConcatZipr(); + /* create the aggregator which will execute the zip function when all Observables provide values */ + Aggregator a = new Aggregator(zipr); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + Subscription subscription = a.onSubscribe(aObserver); + + /* mock the Observable Observers that are 'pushing' data for us */ + ZipObserver r1 = mock(ZipObserver.class); + ZipObserver r2 = mock(ZipObserver.class); + + /* pretend we're starting up */ + a.addObserver(r1); + a.addObserver(r2); + + /* simulate the Observables pushing data into the aggregator */ + a.next(r1, "hello"); + a.next(r2, "world"); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + verify(aObserver, times(1)).onNext("helloworld"); + + subscription.unsubscribe(); + a.next(r1, "hello"); + a.next(r2, "again"); + + verify(aObserver, times(0)).onError(any(Throwable.class)); + verify(aObserver, never()).onCompleted(); + // we don't want to be called again after an error + verify(aObserver, times(0)).onNext("helloagain"); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testAggregatorEarlyCompletion() { + FuncN zipr = getConcatZipr(); + /* create the aggregator which will execute the zip function when all Observables provide values */ + Aggregator a = new Aggregator(zipr); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + a.onSubscribe(aObserver); + + /* mock the Observable Observers that are 'pushing' data for us */ + ZipObserver r1 = mock(ZipObserver.class); + ZipObserver r2 = mock(ZipObserver.class); + + /* pretend we're starting up */ + a.addObserver(r1); + a.addObserver(r2); + + /* simulate the Observables pushing data into the aggregator */ + a.next(r1, "one"); + a.next(r1, "two"); + a.complete(r1); + a.next(r2, "A"); + + InOrder inOrder = inOrder(aObserver); + + inOrder.verify(aObserver, never()).onError(any(Throwable.class)); + inOrder.verify(aObserver, never()).onCompleted(); + inOrder.verify(aObserver, times(1)).onNext("oneA"); + + a.complete(r2); + + inOrder.verify(aObserver, never()).onError(any(Throwable.class)); + inOrder.verify(aObserver, times(1)).onCompleted(); + inOrder.verify(aObserver, never()).onNext(anyString()); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testZip2Types() { + Func2 zipr = getConcatStringIntegerZipr(); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + + Observable w = Observable.create(zip(Observable.from("one", "two"), Observable.from(2, 3, 4), zipr)); + w.subscribe(aObserver); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + verify(aObserver, times(1)).onNext("one2"); + verify(aObserver, times(1)).onNext("two3"); + verify(aObserver, never()).onNext("4"); + } + + @SuppressWarnings("unchecked") + /* mock calls don't do generics */ + @Test + public void testZip3Types() { + Func3 zipr = getConcatStringIntegerIntArrayZipr(); + + /* define a Observer to receive aggregated events */ + Observer aObserver = mock(Observer.class); + + Observable w = Observable.create(zip(Observable.from("one", "two"), Observable.from(2), Observable.from(new int[] { 4, 5, 6 }), zipr)); + w.subscribe(aObserver); + + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + verify(aObserver, times(1)).onNext("one2[4, 5, 6]"); + verify(aObserver, never()).onNext("two"); + } + + @Test + public void testOnNextExceptionInvokesOnError() { + Func2 zipr = getDivideZipr(); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + + Observable w = Observable.create(zip(Observable.from(10, 20, 30), Observable.from(0, 1, 2), zipr)); + w.subscribe(aObserver); + + verify(aObserver, times(1)).onError(any(Throwable.class)); + } + + private Func2 getDivideZipr() { + Func2 zipr = new Func2() { + + @Override + public Integer call(Integer i1, Integer i2) { + return i1 / i2; + } + + }; + return zipr; + } + + private Func3 getConcat3StringsZipr() { + Func3 zipr = new Func3() { + + @Override + public String call(String a1, String a2, String a3) { + if (a1 == null) { + a1 = ""; + } + if (a2 == null) { + a2 = ""; + } + if (a3 == null) { + a3 = ""; + } + return a1 + a2 + a3; + } + + }; + return zipr; + } + + private FuncN getConcatZipr() { + FuncN zipr = new FuncN() { + + @Override + public String call(Object... args) { + String returnValue = ""; + for (Object o : args) { + if (o != null) { + returnValue += getStringValue(o); + } + } + System.out.println("returning: " + returnValue); + return returnValue; + } + + }; + return zipr; + } + + private Func2 getConcatStringIntegerZipr() { + Func2 zipr = new Func2() { + + @Override + public String call(String s, Integer i) { + return getStringValue(s) + getStringValue(i); + } + + }; + return zipr; + } + + private Func3 getConcatStringIntegerIntArrayZipr() { + Func3 zipr = new Func3() { + + @Override + public String call(String s, Integer i, int[] iArray) { + return getStringValue(s) + getStringValue(i) + getStringValue(iArray); + } + + }; + return zipr; + } + + private static String getStringValue(Object o) { + if (o == null) { + return ""; + } else { + if (o instanceof int[]) { + return Arrays.toString((int[]) o); + } else { + return String.valueOf(o); + } + } + } + + private static class TestObservable implements Observable.OnSubscribeFunc { + + Observer observer; + + @Override + public Subscription onSubscribe(Observer Observer) { + // just store the variable where it can be accessed so we can manually trigger it + this.observer = Observer; + return Subscriptions.empty(); + } + + } } diff --git a/rxjava-core/src/test/java/rx/operators/SafeObservableSubscriptionTest.java b/rxjava-core/src/test/java/rx/operators/SafeObservableSubscriptionTest.java index c5b7e6d590..a4bf9e8e8c 100644 --- a/rxjava-core/src/test/java/rx/operators/SafeObservableSubscriptionTest.java +++ b/rxjava-core/src/test/java/rx/operators/SafeObservableSubscriptionTest.java @@ -1,7 +1,21 @@ package rx.operators; import org.junit.Ignore; +import org.junit.Test; +import rx.Subscription; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; -@Ignore("WIP") public class SafeObservableSubscriptionTest { + + @Test + public void testWrapAfterUnsubscribe() { + SafeObservableSubscription atomicObservableSubscription = new SafeObservableSubscription(); + atomicObservableSubscription.unsubscribe(); + Subscription innerSubscription = mock(Subscription.class); + atomicObservableSubscription.wrap(innerSubscription); + verify(innerSubscription, times(1)).unsubscribe(); + } } diff --git a/rxjava-core/src/test/java/rx/operators/SynchronizedObserverTest.java b/rxjava-core/src/test/java/rx/operators/SynchronizedObserverTest.java index 5b4b301590..b9e4b2e278 100644 --- a/rxjava-core/src/test/java/rx/operators/SynchronizedObserverTest.java +++ b/rxjava-core/src/test/java/rx/operators/SynchronizedObserverTest.java @@ -1,7 +1,751 @@ package rx.operators; -import org.junit.Ignore; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import rx.Observable; +import rx.Observer; +import rx.Subscription; + +import java.util.Random; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; -@Ignore("WIP") public class SynchronizedObserverTest { + + @Mock + Observer aObserver; + + @Before + public void before() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testSingleThreadedBasic() { + Subscription s = mock(Subscription.class); + TestSingleThreadedObservable onSubscribe = new TestSingleThreadedObservable(s, "one", "two", "three"); + Observable w = Observable.create(onSubscribe); + + SafeObservableSubscription as = new SafeObservableSubscription(s); + SynchronizedObserver aw = new SynchronizedObserver(aObserver, as); + + w.subscribe(aw); + onSubscribe.waitToFinish(); + + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, times(1)).onNext("two"); + verify(aObserver, times(1)).onNext("three"); + verify(aObserver, never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + // non-deterministic because unsubscribe happens after 'waitToFinish' releases + // so commenting out for now as this is not a critical thing to test here + // verify(s, times(1)).unsubscribe(); + } + + @Test + public void testMultiThreadedBasic() { + Subscription s = mock(Subscription.class); + TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable(s, "one", "two", "three"); + Observable w = Observable.create(onSubscribe); + + SafeObservableSubscription as = new SafeObservableSubscription(s); + BusyObserver busyObserver = new BusyObserver(); + SynchronizedObserver aw = new SynchronizedObserver(busyObserver, as); + + w.subscribe(aw); + onSubscribe.waitToFinish(); + + assertEquals(3, busyObserver.onNextCount.get()); + assertFalse(busyObserver.onError); + assertTrue(busyObserver.onCompleted); + // non-deterministic because unsubscribe happens after 'waitToFinish' releases + // so commenting out for now as this is not a critical thing to test here + // verify(s, times(1)).unsubscribe(); + + // we can have concurrency ... + assertTrue(onSubscribe.maxConcurrentThreads.get() > 1); + // ... but the onNext execution should be single threaded + assertEquals(1, busyObserver.maxConcurrentThreads.get()); + } + + @Test + public void testMultiThreadedBasicWithLock() { + Subscription s = mock(Subscription.class); + TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable(s, "one", "two", "three"); + Observable w = Observable.create(onSubscribe); + + SafeObservableSubscription as = new SafeObservableSubscription(s); + BusyObserver busyObserver = new BusyObserver(); + + Object lock = new Object(); + ExternalBusyThread externalBusyThread = new ExternalBusyThread(busyObserver, lock, 10, 100); + + SynchronizedObserver aw = new SynchronizedObserver(busyObserver, as, lock); + + externalBusyThread.start(); + + w.subscribe(aw); + onSubscribe.waitToFinish(); + + try { + externalBusyThread.join(10000); + assertFalse(externalBusyThread.isAlive()); + assertFalse(externalBusyThread.fail); + } catch (InterruptedException e) { + // ignore + } + + assertEquals(3, busyObserver.onNextCount.get()); + assertFalse(busyObserver.onError); + assertTrue(busyObserver.onCompleted); + // non-deterministic because unsubscribe happens after 'waitToFinish' releases + // so commenting out for now as this is not a critical thing to test here + // verify(s, times(1)).unsubscribe(); + + // we can have concurrency ... + assertTrue(onSubscribe.maxConcurrentThreads.get() > 1); + // ... but the onNext execution should be single threaded + assertEquals(1, busyObserver.maxConcurrentThreads.get()); + } + + @Test + public void testMultiThreadedWithNPE() { + Subscription s = mock(Subscription.class); + TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable(s, "one", "two", "three", null); + Observable w = Observable.create(onSubscribe); + + SafeObservableSubscription as = new SafeObservableSubscription(s); + BusyObserver busyObserver = new BusyObserver(); + SynchronizedObserver aw = new SynchronizedObserver(busyObserver, as); + + w.subscribe(aw); + onSubscribe.waitToFinish(); + + System.out.println("maxConcurrentThreads: " + onSubscribe.maxConcurrentThreads.get()); + + // we can't know how many onNext calls will occur since they each run on a separate thread + // that depends on thread scheduling so 0, 1, 2 and 3 are all valid options + // assertEquals(3, busyObserver.onNextCount.get()); + assertTrue(busyObserver.onNextCount.get() < 4); + assertTrue(busyObserver.onError); + // no onCompleted because onError was invoked + assertFalse(busyObserver.onCompleted); + // non-deterministic because unsubscribe happens after 'waitToFinish' releases + // so commenting out for now as this is not a critical thing to test here + //verify(s, times(1)).unsubscribe(); + + // we can have concurrency ... + assertTrue(onSubscribe.maxConcurrentThreads.get() > 1); + // ... but the onNext execution should be single threaded + assertEquals(1, busyObserver.maxConcurrentThreads.get()); + } + + @Test + public void testMultiThreadedWithNPEAndLock() { + Subscription s = mock(Subscription.class); + TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable(s, "one", "two", "three", null); + Observable w = Observable.create(onSubscribe); + + SafeObservableSubscription as = new SafeObservableSubscription(s); + BusyObserver busyObserver = new BusyObserver(); + + Object lock = new Object(); + ExternalBusyThread externalBusyThread = new ExternalBusyThread(busyObserver, lock, 10, 100); + + SynchronizedObserver aw = new SynchronizedObserver(busyObserver, as, lock); + + externalBusyThread.start(); + + w.subscribe(aw); + onSubscribe.waitToFinish(); + + try { + externalBusyThread.join(10000); + assertFalse(externalBusyThread.isAlive()); + assertFalse(externalBusyThread.fail); + } catch (InterruptedException e) { + // ignore + } + + System.out.println("maxConcurrentThreads: " + onSubscribe.maxConcurrentThreads.get()); + + // we can't know how many onNext calls will occur since they each run on a separate thread + // that depends on thread scheduling so 0, 1, 2 and 3 are all valid options + // assertEquals(3, busyObserver.onNextCount.get()); + assertTrue(busyObserver.onNextCount.get() < 4); + assertTrue(busyObserver.onError); + // no onCompleted because onError was invoked + assertFalse(busyObserver.onCompleted); + // non-deterministic because unsubscribe happens after 'waitToFinish' releases + // so commenting out for now as this is not a critical thing to test here + //verify(s, times(1)).unsubscribe(); + + // we can have concurrency ... + assertTrue(onSubscribe.maxConcurrentThreads.get() > 1); + // ... but the onNext execution should be single threaded + assertEquals(1, busyObserver.maxConcurrentThreads.get()); + } + + @Test + public void testMultiThreadedWithNPEinMiddle() { + Subscription s = mock(Subscription.class); + TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable(s, "one", "two", "three", null, "four", "five", "six", "seven", "eight", "nine"); + Observable w = Observable.create(onSubscribe); + + SafeObservableSubscription as = new SafeObservableSubscription(s); + BusyObserver busyObserver = new BusyObserver(); + SynchronizedObserver aw = new SynchronizedObserver(busyObserver, as); + + w.subscribe(aw); + onSubscribe.waitToFinish(); + + System.out.println("maxConcurrentThreads: " + onSubscribe.maxConcurrentThreads.get()); + // this should not be the full number of items since the error should stop it before it completes all 9 + System.out.println("onNext count: " + busyObserver.onNextCount.get()); + assertTrue(busyObserver.onNextCount.get() < 9); + assertTrue(busyObserver.onError); + // no onCompleted because onError was invoked + assertFalse(busyObserver.onCompleted); + // non-deterministic because unsubscribe happens after 'waitToFinish' releases + // so commenting out for now as this is not a critical thing to test here + // verify(s, times(1)).unsubscribe(); + + // we can have concurrency ... + assertTrue(onSubscribe.maxConcurrentThreads.get() > 1); + // ... but the onNext execution should be single threaded + assertEquals(1, busyObserver.maxConcurrentThreads.get()); + } + + @Test + public void testMultiThreadedWithNPEinMiddleAndLock() { + Subscription s = mock(Subscription.class); + TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable(s, "one", "two", "three", null, "four", "five", "six", "seven", "eight", "nine"); + Observable w = Observable.create(onSubscribe); + + SafeObservableSubscription as = new SafeObservableSubscription(s); + BusyObserver busyObserver = new BusyObserver(); + + Object lock = new Object(); + ExternalBusyThread externalBusyThread = new ExternalBusyThread(busyObserver, lock, 10, 100); + + SynchronizedObserver aw = new SynchronizedObserver(busyObserver, as, lock); + + externalBusyThread.start(); + + w.subscribe(aw); + onSubscribe.waitToFinish(); + + try { + externalBusyThread.join(10000); + assertFalse(externalBusyThread.isAlive()); + assertFalse(externalBusyThread.fail); + } catch (InterruptedException e) { + // ignore + } + + System.out.println("maxConcurrentThreads: " + onSubscribe.maxConcurrentThreads.get()); + // this should not be the full number of items since the error should stop it before it completes all 9 + System.out.println("onNext count: " + busyObserver.onNextCount.get()); + assertTrue(busyObserver.onNextCount.get() < 9); + assertTrue(busyObserver.onError); + // no onCompleted because onError was invoked + assertFalse(busyObserver.onCompleted); + // non-deterministic because unsubscribe happens after 'waitToFinish' releases + // so commenting out for now as this is not a critical thing to test here + // verify(s, times(1)).unsubscribe(); + + // we can have concurrency ... + assertTrue(onSubscribe.maxConcurrentThreads.get() > 1); + // ... but the onNext execution should be single threaded + assertEquals(1, busyObserver.maxConcurrentThreads.get()); + } + + /** + * A non-realistic use case that tries to expose thread-safety issues by throwing lots of out-of-order + * events on many threads. + * + * @param w + * @param tw + */ + @Test + public void runConcurrencyTest() { + ExecutorService tp = Executors.newFixedThreadPool(20); + try { + TestConcurrencyObserver tw = new TestConcurrencyObserver(); + SafeObservableSubscription s = new SafeObservableSubscription(); + SynchronizedObserver w = new SynchronizedObserver(tw, s); + + Future f1 = tp.submit(new OnNextThread(w, 12000)); + Future f2 = tp.submit(new OnNextThread(w, 5000)); + Future f3 = tp.submit(new OnNextThread(w, 75000)); + Future f4 = tp.submit(new OnNextThread(w, 13500)); + Future f5 = tp.submit(new OnNextThread(w, 22000)); + Future f6 = tp.submit(new OnNextThread(w, 15000)); + Future f7 = tp.submit(new OnNextThread(w, 7500)); + Future f8 = tp.submit(new OnNextThread(w, 23500)); + + Future f10 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onCompleted, f1, f2, f3, f4)); + try { + Thread.sleep(1); + } catch (InterruptedException e) { + // ignore + } + Future f11 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onCompleted, f4, f6, f7)); + Future f12 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onCompleted, f4, f6, f7)); + Future f13 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onCompleted, f4, f6, f7)); + Future f14 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onCompleted, f4, f6, f7)); + // // the next 4 onError events should wait on same as f10 + Future f15 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onError, f1, f2, f3, f4)); + Future f16 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onError, f1, f2, f3, f4)); + Future f17 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onError, f1, f2, f3, f4)); + Future f18 = tp.submit(new CompletionThread(w, TestConcurrencyObserverEvent.onError, f1, f2, f3, f4)); + + waitOnThreads(f1, f2, f3, f4, f5, f6, f7, f8, f10, f11, f12, f13, f14, f15, f16, f17, f18); + @SuppressWarnings("unused") + int numNextEvents = tw.assertEvents(null); // no check of type since we don't want to test barging results here, just interleaving behavior + // System.out.println("Number of events executed: " + numNextEvents); + } catch (Throwable e) { + fail("Concurrency test failed: " + e.getMessage()); + e.printStackTrace(); + } finally { + tp.shutdown(); + try { + tp.awaitTermination(5000, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + private static void waitOnThreads(Future... futures) { + for (Future f : futures) { + try { + f.get(10, TimeUnit.SECONDS); + } catch (Throwable e) { + System.err.println("Failed while waiting on future."); + e.printStackTrace(); + } + } + } + + /** + * A thread that will pass data to onNext + */ + public static class OnNextThread implements Runnable { + + private final Observer Observer; + private final int numStringsToSend; + + OnNextThread(Observer Observer, int numStringsToSend) { + this.Observer = Observer; + this.numStringsToSend = numStringsToSend; + } + + @Override + public void run() { + for (int i = 0; i < numStringsToSend; i++) { + Observer.onNext("aString"); + } + } + } + + /** + * A thread that will call onError or onNext + */ + public static class CompletionThread implements Runnable { + + private final Observer Observer; + private final TestConcurrencyObserverEvent event; + private final Future[] waitOnThese; + + CompletionThread(Observer Observer, TestConcurrencyObserverEvent event, Future... waitOnThese) { + this.Observer = Observer; + this.event = event; + this.waitOnThese = waitOnThese; + } + + @Override + public void run() { + /* if we have 'waitOnThese' futures, we'll wait on them before proceeding */ + if (waitOnThese != null) { + for (Future f : waitOnThese) { + try { + f.get(); + } catch (Throwable e) { + System.err.println("Error while waiting on future in CompletionThread"); + } + } + } + + /* send the event */ + if (event == TestConcurrencyObserverEvent.onError) { + Observer.onError(new RuntimeException("mocked exception")); + } else if (event == TestConcurrencyObserverEvent.onCompleted) { + Observer.onCompleted(); + + } else { + throw new IllegalArgumentException("Expecting either onError or onCompleted"); + } + } + } + + private static enum TestConcurrencyObserverEvent { + onCompleted, onError, onNext + } + + private static class TestConcurrencyObserver implements Observer { + + /** + * used to store the order and number of events received + */ + private final LinkedBlockingQueue events = new LinkedBlockingQueue(); + private final int waitTime; + + @SuppressWarnings("unused") + public TestConcurrencyObserver(int waitTimeInNext) { + this.waitTime = waitTimeInNext; + } + + public TestConcurrencyObserver() { + this.waitTime = 0; + } + + @Override + public void onCompleted() { + events.add(TestConcurrencyObserverEvent.onCompleted); + } + + @Override + public void onError(Throwable e) { + events.add(TestConcurrencyObserverEvent.onError); + } + + @Override + public void onNext(String args) { + events.add(TestConcurrencyObserverEvent.onNext); + // do some artificial work to make the thread scheduling/timing vary + int s = 0; + for (int i = 0; i < 20; i++) { + s += s * i; + } + + if (waitTime > 0) { + try { + Thread.sleep(waitTime); + } catch (InterruptedException e) { + // ignore + } + } + } + + /** + * Assert the order of events is correct and return the number of onNext executions. + * + * @param expectedEndingEvent + * @return int count of onNext calls + * @throws IllegalStateException If order of events was invalid. + */ + public int assertEvents(TestConcurrencyObserverEvent expectedEndingEvent) throws IllegalStateException { + int nextCount = 0; + boolean finished = false; + for (TestConcurrencyObserverEvent e : events) { + if (e == TestConcurrencyObserverEvent.onNext) { + if (finished) { + // already finished, we shouldn't get this again + throw new IllegalStateException("Received onNext but we're already finished."); + } + nextCount++; + } else if (e == TestConcurrencyObserverEvent.onError) { + if (finished) { + // already finished, we shouldn't get this again + throw new IllegalStateException("Received onError but we're already finished."); + } + if (expectedEndingEvent != null && TestConcurrencyObserverEvent.onError != expectedEndingEvent) { + throw new IllegalStateException("Received onError ending event but expected " + expectedEndingEvent); + } + finished = true; + } else if (e == TestConcurrencyObserverEvent.onCompleted) { + if (finished) { + // already finished, we shouldn't get this again + throw new IllegalStateException("Received onCompleted but we're already finished."); + } + if (expectedEndingEvent != null && TestConcurrencyObserverEvent.onCompleted != expectedEndingEvent) { + throw new IllegalStateException("Received onCompleted ending event but expected " + expectedEndingEvent); + } + finished = true; + } + } + + return nextCount; + } + + } + + /** + * This spawns a single thread for the subscribe execution + */ + private static class TestSingleThreadedObservable implements Observable.OnSubscribeFunc { + + final Subscription s; + final String[] values; + private Thread t = null; + + public TestSingleThreadedObservable(final Subscription s, final String... values) { + this.s = s; + this.values = values; + + } + + public Subscription onSubscribe(final Observer observer) { + System.out.println("TestSingleThreadedObservable subscribed to ..."); + t = new Thread(new Runnable() { + + @Override + public void run() { + try { + System.out.println("running TestSingleThreadedObservable thread"); + for (String s : values) { + System.out.println("TestSingleThreadedObservable onNext: " + s); + observer.onNext(s); + } + observer.onCompleted(); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + }); + System.out.println("starting TestSingleThreadedObservable thread"); + t.start(); + System.out.println("done starting TestSingleThreadedObservable thread"); + return s; + } + + public void waitToFinish() { + try { + t.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + } + + /** + * This spawns a thread for the subscription, then a separate thread for each onNext call. + */ + private static class TestMultiThreadedObservable implements Observable.OnSubscribeFunc { + + final Subscription s; + final String[] values; + Thread t = null; + AtomicInteger threadsRunning = new AtomicInteger(); + AtomicInteger maxConcurrentThreads = new AtomicInteger(); + ExecutorService threadPool; + + public TestMultiThreadedObservable(Subscription s, String... values) { + this.s = s; + this.values = values; + this.threadPool = Executors.newCachedThreadPool(); + } + + @Override + public Subscription onSubscribe(final Observer observer) { + System.out.println("TestMultiThreadedObservable subscribed to ..."); + t = new Thread(new Runnable() { + + @Override + public void run() { + try { + System.out.println("running TestMultiThreadedObservable thread"); + for (final String s : values) { + threadPool.execute(new Runnable() { + + @Override + public void run() { + threadsRunning.incrementAndGet(); + try { + // perform onNext call + System.out.println("TestMultiThreadedObservable onNext: " + s); + if (s == null) { + // force an error + throw new NullPointerException(); + } + observer.onNext(s); + // capture 'maxThreads' + int concurrentThreads = threadsRunning.get(); + int maxThreads = maxConcurrentThreads.get(); + if (concurrentThreads > maxThreads) { + maxConcurrentThreads.compareAndSet(maxThreads, concurrentThreads); + } + } catch (Throwable e) { + observer.onError(e); + } finally { + threadsRunning.decrementAndGet(); + } + } + }); + } + // we are done spawning threads + threadPool.shutdown(); + } catch (Throwable e) { + throw new RuntimeException(e); + } + + // wait until all threads are done, then mark it as COMPLETED + try { + // wait for all the threads to finish + threadPool.awaitTermination(2, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + observer.onCompleted(); + } + }); + System.out.println("starting TestMultiThreadedObservable thread"); + t.start(); + System.out.println("done starting TestMultiThreadedObservable thread"); + return s; + } + + public void waitToFinish() { + try { + t.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + + private static class BusyObserver implements Observer { + volatile boolean onCompleted = false; + volatile boolean onError = false; + AtomicInteger onNextCount = new AtomicInteger(); + AtomicInteger threadsRunning = new AtomicInteger(); + AtomicInteger maxConcurrentThreads = new AtomicInteger(); + + @Override + public void onCompleted() { + threadsRunning.incrementAndGet(); + + System.out.println(">>> BusyObserver received onCompleted"); + onCompleted = true; + + int concurrentThreads = threadsRunning.get(); + int maxThreads = maxConcurrentThreads.get(); + if (concurrentThreads > maxThreads) { + maxConcurrentThreads.compareAndSet(maxThreads, concurrentThreads); + } + threadsRunning.decrementAndGet(); + } + + @Override + public void onError(Throwable e) { + threadsRunning.incrementAndGet(); + + System.out.println(">>> BusyObserver received onError: " + e.getMessage()); + onError = true; + + int concurrentThreads = threadsRunning.get(); + int maxThreads = maxConcurrentThreads.get(); + if (concurrentThreads > maxThreads) { + maxConcurrentThreads.compareAndSet(maxThreads, concurrentThreads); + } + threadsRunning.decrementAndGet(); + } + + @Override + public void onNext(String args) { + threadsRunning.incrementAndGet(); + try { + onNextCount.incrementAndGet(); + System.out.println(">>> BusyObserver received onNext: " + args); + try { + // simulate doing something computational + Thread.sleep(200); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } finally { + // capture 'maxThreads' + int concurrentThreads = threadsRunning.get(); + int maxThreads = maxConcurrentThreads.get(); + if (concurrentThreads > maxThreads) { + maxConcurrentThreads.compareAndSet(maxThreads, concurrentThreads); + } + threadsRunning.decrementAndGet(); + } + } + + } + + private static class ExternalBusyThread extends Thread { + + private BusyObserver observer; + private Object lock; + private int lockTimes; + private int waitTime; + public volatile boolean fail; + + public ExternalBusyThread(BusyObserver observer, Object lock, int lockTimes, int waitTime) { + this.observer = observer; + this.lock = lock; + this.lockTimes = lockTimes; + this.waitTime = waitTime; + this.fail = false; + } + + @Override + public void run() { + Random r = new Random(); + for (int i = 0; i < lockTimes; i++) { + synchronized (lock) { + int oldOnNextCount = observer.onNextCount.get(); + boolean oldOnCompleted = observer.onCompleted; + boolean oldOnError = observer.onError; + try { + Thread.sleep(r.nextInt(waitTime)); + } catch (InterruptedException e) { + // ignore + } + // Since we own the lock, onNextCount, onCompleted and + // onError must not be changed. + int newOnNextCount = observer.onNextCount.get(); + boolean newOnCompleted = observer.onCompleted; + boolean newOnError = observer.onError; + if (oldOnNextCount != newOnNextCount) { + System.out.println(">>> ExternalBusyThread received different onNextCount: " + + oldOnNextCount + + " -> " + + newOnNextCount); + fail = true; + break; + } + if (oldOnCompleted != newOnCompleted) { + System.out.println(">>> ExternalBusyThread received different onCompleted: " + + oldOnCompleted + + " -> " + + newOnCompleted); + fail = true; + break; + } + if (oldOnError != newOnError) { + System.out.println(">>> ExternalBusyThread received different onError: " + + oldOnError + + " -> " + + newOnError); + fail = true; + break; + } + } + } + } + + } } diff --git a/rxjava-core/src/test/java/rx/plugins/RxJavaPluginsTest.java b/rxjava-core/src/test/java/rx/plugins/RxJavaPluginsTest.java index 1def236246..3ea17bf152 100644 --- a/rxjava-core/src/test/java/rx/plugins/RxJavaPluginsTest.java +++ b/rxjava-core/src/test/java/rx/plugins/RxJavaPluginsTest.java @@ -1,7 +1,77 @@ package rx.plugins; -import org.junit.Ignore; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; -@Ignore("WIP") public class RxJavaPluginsTest { + + @Test + public void testErrorHandlerDefaultImpl() { + RxJavaErrorHandler impl = new RxJavaPlugins().getErrorHandler(); + assertTrue(impl instanceof RxJavaErrorHandlerDefault); + } + + @Test + public void testErrorHandlerViaRegisterMethod() { + RxJavaPlugins p = new RxJavaPlugins(); + p.registerErrorHandler(new RxJavaErrorHandlerTestImpl()); + RxJavaErrorHandler impl = p.getErrorHandler(); + assertTrue(impl instanceof RxJavaErrorHandlerTestImpl); + } + + @Test + public void testErrorHandlerViaProperty() { + try { + RxJavaPlugins p = new RxJavaPlugins(); + String fullClass = getFullClassNameForTestClass(RxJavaErrorHandlerTestImpl.class); + System.setProperty("rxjava.plugin.RxJavaErrorHandler.implementation", fullClass); + RxJavaErrorHandler impl = p.getErrorHandler(); + assertTrue(impl instanceof RxJavaErrorHandlerTestImpl); + } finally { + System.clearProperty("rxjava.plugin.RxJavaErrorHandler.implementation"); + } + } + + // inside test so it is stripped from Javadocs + public static class RxJavaErrorHandlerTestImpl extends RxJavaErrorHandler { + // just use defaults + } + + @Test + public void testObservableExecutionHookDefaultImpl() { + RxJavaPlugins p = new RxJavaPlugins(); + RxJavaObservableExecutionHook impl = p.getObservableExecutionHook(); + assertTrue(impl instanceof RxJavaObservableExecutionHookDefault); + } + + @Test + public void testObservableExecutionHookViaRegisterMethod() { + RxJavaPlugins p = new RxJavaPlugins(); + p.registerObservableExecutionHook(new RxJavaObservableExecutionHookTestImpl()); + RxJavaObservableExecutionHook impl = p.getObservableExecutionHook(); + assertTrue(impl instanceof RxJavaObservableExecutionHookTestImpl); + } + + @Test + public void testObservableExecutionHookViaProperty() { + try { + RxJavaPlugins p = new RxJavaPlugins(); + String fullClass = getFullClassNameForTestClass(RxJavaObservableExecutionHookTestImpl.class); + System.setProperty("rxjava.plugin.RxJavaObservableExecutionHook.implementation", fullClass); + RxJavaObservableExecutionHook impl = p.getObservableExecutionHook(); + assertTrue(impl instanceof RxJavaObservableExecutionHookTestImpl); + } finally { + System.clearProperty("rxjava.plugin.RxJavaObservableExecutionHook.implementation"); + } + } + + // inside test so it is stripped from Javadocs + public static class RxJavaObservableExecutionHookTestImpl extends RxJavaObservableExecutionHook { + // just use defaults + } + + private static String getFullClassNameForTestClass(Class cls) { + return RxJavaPlugins.class.getPackage().getName() + "." + RxJavaPluginsTest.class.getSimpleName() + "$" + cls.getSimpleName(); + } } diff --git a/rxjava-core/src/test/java/rx/subjects/AsyncSubjectTest.java b/rxjava-core/src/test/java/rx/subjects/AsyncSubjectTest.java index bfe0aa0bb0..fb5220640b 100644 --- a/rxjava-core/src/test/java/rx/subjects/AsyncSubjectTest.java +++ b/rxjava-core/src/test/java/rx/subjects/AsyncSubjectTest.java @@ -1,7 +1,135 @@ package rx.subjects; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.Mockito; +import rx.Observer; +import rx.Subscription; +import rx.util.functions.Action1; +import rx.util.functions.Func0; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; -@Ignore("WIP") public class AsyncSubjectTest { + + + private final Throwable testException = new Throwable(); + + @Test + public void testNeverCompleted() { + AsyncSubject subject = AsyncSubject.create(); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + subject.subscribe(aObserver); + + subject.onNext("one"); + subject.onNext("two"); + subject.onNext("three"); + + assertNeverCompletedObserver(aObserver); + } + + private void assertNeverCompletedObserver(Observer aObserver) { + verify(aObserver, Mockito.never()).onNext(anyString()); + verify(aObserver, Mockito.never()).onError(testException); + verify(aObserver, Mockito.never()).onCompleted(); + } + + @Test + public void testCompleted() { + AsyncSubject subject = AsyncSubject.create(); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + subject.subscribe(aObserver); + + subject.onNext("one"); + subject.onNext("two"); + subject.onNext("three"); + subject.onCompleted(); + + assertCompletedObserver(aObserver); + } + + private void assertCompletedObserver(Observer aObserver) { + verify(aObserver, times(1)).onNext("three"); + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testError() { + AsyncSubject subject = AsyncSubject.create(); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + subject.subscribe(aObserver); + + subject.onNext("one"); + subject.onNext("two"); + subject.onNext("three"); + subject.onError(testException); + subject.onNext("four"); + subject.onError(new Throwable()); + subject.onCompleted(); + + assertErrorObserver(aObserver); + } + + private void assertErrorObserver(Observer aObserver) { + verify(aObserver, Mockito.never()).onNext(anyString()); + verify(aObserver, times(1)).onError(testException); + verify(aObserver, Mockito.never()).onCompleted(); + } + + @Test + public void testUnsubscribeBeforeCompleted() { + AsyncSubject subject = AsyncSubject.create(); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + Subscription subscription = subject.subscribe(aObserver); + + subject.onNext("one"); + subject.onNext("two"); + + subscription.unsubscribe(); + assertNoOnNextEventsReceived(aObserver); + + subject.onNext("three"); + subject.onCompleted(); + + assertNoOnNextEventsReceived(aObserver); + } + + private void assertNoOnNextEventsReceived(Observer aObserver) { + verify(aObserver, Mockito.never()).onNext(anyString()); + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, Mockito.never()).onCompleted(); + } + + @Test + public void testUnsubscribe() { + UnsubscribeTester.test( + new Func0>() { + @Override + public AsyncSubject call() { + return AsyncSubject.create(); + } + }, new Action1>() { + @Override + public void call(AsyncSubject DefaultSubject) { + DefaultSubject.onCompleted(); + } + }, new Action1>() { + @Override + public void call(AsyncSubject DefaultSubject) { + DefaultSubject.onError(new Throwable()); + } + }, + null + ); + } } diff --git a/rxjava-core/src/test/java/rx/subjects/BehaviorSubjectTest.java b/rxjava-core/src/test/java/rx/subjects/BehaviorSubjectTest.java index ffee087158..eae3ffbc06 100644 --- a/rxjava-core/src/test/java/rx/subjects/BehaviorSubjectTest.java +++ b/rxjava-core/src/test/java/rx/subjects/BehaviorSubjectTest.java @@ -1,7 +1,135 @@ package rx.subjects; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.Mockito; +import rx.Observer; +import rx.util.functions.Action1; +import rx.util.functions.Func0; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; -@Ignore("WIP") public class BehaviorSubjectTest { + + + private final Throwable testException = new Throwable(); + + @Test + public void testThatObserverReceivesDefaultValueIfNothingWasPublished() { + BehaviorSubject subject = BehaviorSubject.createWithDefaultValue("default"); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + subject.subscribe(aObserver); + + subject.onNext("one"); + subject.onNext("two"); + subject.onNext("three"); + + assertReceivedAllEvents(aObserver); + } + + private void assertReceivedAllEvents(Observer aObserver) { + verify(aObserver, times(1)).onNext("default"); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, times(1)).onNext("two"); + verify(aObserver, times(1)).onNext("three"); + verify(aObserver, Mockito.never()).onError(testException); + verify(aObserver, Mockito.never()).onCompleted(); + } + + @Test + public void testThatObserverDoesNotReceiveDefaultValueIfSomethingWasPublished() { + BehaviorSubject subject = BehaviorSubject.createWithDefaultValue("default"); + + subject.onNext("one"); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + subject.subscribe(aObserver); + + subject.onNext("two"); + subject.onNext("three"); + + assertDidNotReceiveTheDefaultValue(aObserver); + } + + private void assertDidNotReceiveTheDefaultValue(Observer aObserver) { + verify(aObserver, Mockito.never()).onNext("default"); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, times(1)).onNext("two"); + verify(aObserver, times(1)).onNext("three"); + verify(aObserver, Mockito.never()).onError(testException); + verify(aObserver, Mockito.never()).onCompleted(); + } + + @Test + public void testCompleted() { + BehaviorSubject subject = BehaviorSubject.createWithDefaultValue("default"); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + subject.subscribe(aObserver); + + subject.onNext("one"); + subject.onCompleted(); + + assertCompletedObserver(aObserver); + } + + private void assertCompletedObserver(Observer aObserver) { + verify(aObserver, times(1)).onNext("default"); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testCompletedAfterError() { + BehaviorSubject subject = BehaviorSubject.createWithDefaultValue("default"); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + subject.subscribe(aObserver); + + subject.onNext("one"); + subject.onError(testException); + subject.onNext("two"); + subject.onCompleted(); + + assertErrorObserver(aObserver); + } + + private void assertErrorObserver(Observer aObserver) { + verify(aObserver, times(1)).onNext("default"); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, times(1)).onError(testException); + } + + @Test + public void testUnsubscribe() { + UnsubscribeTester.test( + new Func0>() { + @Override + public BehaviorSubject call() { + return BehaviorSubject.createWithDefaultValue("default"); + } + }, new Action1>() { + @Override + public void call(BehaviorSubject DefaultSubject) { + DefaultSubject.onCompleted(); + } + }, new Action1>() { + @Override + public void call(BehaviorSubject DefaultSubject) { + DefaultSubject.onError(new Throwable()); + } + }, new Action1>() { + @Override + public void call(BehaviorSubject DefaultSubject) { + DefaultSubject.onNext("one"); + } + } + ); + } } diff --git a/rxjava-core/src/test/java/rx/subjects/PublishSubjectTest.java b/rxjava-core/src/test/java/rx/subjects/PublishSubjectTest.java index 25cebbf510..da6abf7c44 100644 --- a/rxjava-core/src/test/java/rx/subjects/PublishSubjectTest.java +++ b/rxjava-core/src/test/java/rx/subjects/PublishSubjectTest.java @@ -1,7 +1,364 @@ package rx.subjects; -import org.junit.Ignore; +import junit.framework.Assert; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mockito; +import rx.Notification; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.util.functions.Action1; +import rx.util.functions.Func0; +import rx.util.functions.Func1; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; -@Ignore("WIP") public class PublishSubjectTest { + + @Test + public void test() { + PublishSubject subject = PublishSubject.create(); + final AtomicReference>> actualRef = new AtomicReference>>(); + + Observable>> wNotificationsList = subject.materialize().toList(); + wNotificationsList.subscribe(new Action1>>() { + @Override + public void call(List> actual) { + actualRef.set(actual); + } + }); + + Subscription sub = Observable.create(new Observable.OnSubscribeFunc() { + @Override + public Subscription onSubscribe(final Observer observer) { + final AtomicBoolean stop = new AtomicBoolean(false); + new Thread() { + @Override + public void run() { + int i = 1; + while (!stop.get()) { + observer.onNext(i++); + } + observer.onCompleted(); + } + }.start(); + return new Subscription() { + @Override + public void unsubscribe() { + stop.set(true); + } + }; + } + }).subscribe(subject); + // the subject has received an onComplete from the first subscribe because + // it is synchronous and the next subscribe won't do anything. + Observable.from(-1, -2, -3).subscribe(subject); + + List> expected = new ArrayList>(); + expected.add(new Notification(-1)); + expected.add(new Notification(-2)); + expected.add(new Notification(-3)); + expected.add(new Notification()); + Assert.assertTrue(actualRef.get().containsAll(expected)); + + sub.unsubscribe(); + } + + private final Throwable testException = new Throwable(); + + @Test + public void testCompleted() { + PublishSubject subject = PublishSubject.create(); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + subject.subscribe(aObserver); + + subject.onNext("one"); + subject.onNext("two"); + subject.onNext("three"); + subject.onCompleted(); + + @SuppressWarnings("unchecked") + Observer anotherObserver = mock(Observer.class); + subject.subscribe(anotherObserver); + + subject.onNext("four"); + subject.onCompleted(); + subject.onError(new Throwable()); + + assertCompletedObserver(aObserver); + // todo bug? assertNeverObserver(anotherObserver); + } + + private void assertCompletedObserver(Observer aObserver) { + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, times(1)).onNext("two"); + verify(aObserver, times(1)).onNext("three"); + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testError() { + PublishSubject subject = PublishSubject.create(); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + subject.subscribe(aObserver); + + subject.onNext("one"); + subject.onNext("two"); + subject.onNext("three"); + subject.onError(testException); + + @SuppressWarnings("unchecked") + Observer anotherObserver = mock(Observer.class); + subject.subscribe(anotherObserver); + + subject.onNext("four"); + subject.onError(new Throwable()); + subject.onCompleted(); + + assertErrorObserver(aObserver); + // todo bug? assertNeverObserver(anotherObserver); + } + + private void assertErrorObserver(Observer aObserver) { + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, times(1)).onNext("two"); + verify(aObserver, times(1)).onNext("three"); + verify(aObserver, times(1)).onError(testException); + verify(aObserver, Mockito.never()).onCompleted(); + } + + @Test + public void testSubscribeMidSequence() { + PublishSubject subject = PublishSubject.create(); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + subject.subscribe(aObserver); + + subject.onNext("one"); + subject.onNext("two"); + + assertObservedUntilTwo(aObserver); + + @SuppressWarnings("unchecked") + Observer anotherObserver = mock(Observer.class); + subject.subscribe(anotherObserver); + + subject.onNext("three"); + subject.onCompleted(); + + assertCompletedObserver(aObserver); + assertCompletedStartingWithThreeObserver(anotherObserver); + } + + private void assertCompletedStartingWithThreeObserver(Observer aObserver) { + verify(aObserver, Mockito.never()).onNext("one"); + verify(aObserver, Mockito.never()).onNext("two"); + verify(aObserver, times(1)).onNext("three"); + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testUnsubscribeFirstObserver() { + PublishSubject subject = PublishSubject.create(); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + Subscription subscription = subject.subscribe(aObserver); + + subject.onNext("one"); + subject.onNext("two"); + + subscription.unsubscribe(); + assertObservedUntilTwo(aObserver); + + @SuppressWarnings("unchecked") + Observer anotherObserver = mock(Observer.class); + subject.subscribe(anotherObserver); + + subject.onNext("three"); + subject.onCompleted(); + + assertObservedUntilTwo(aObserver); + assertCompletedStartingWithThreeObserver(anotherObserver); + } + + private void assertObservedUntilTwo(Observer aObserver) { + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, times(1)).onNext("two"); + verify(aObserver, Mockito.never()).onNext("three"); + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, Mockito.never()).onCompleted(); + } + + @Test + public void testUnsubscribe() { + UnsubscribeTester.test( + new Func0>() { + @Override + public PublishSubject call() { + return PublishSubject.create(); + } + }, new Action1>() { + @Override + public void call(PublishSubject DefaultSubject) { + DefaultSubject.onCompleted(); + } + }, new Action1>() { + @Override + public void call(PublishSubject DefaultSubject) { + DefaultSubject.onError(new Throwable()); + } + }, new Action1>() { + @Override + public void call(PublishSubject DefaultSubject) { + DefaultSubject.onNext("one"); + } + } + ); + } + + @Test + public void testNestedSubscribe() { + final PublishSubject s = PublishSubject.create(); + + final AtomicInteger countParent = new AtomicInteger(); + final AtomicInteger countChildren = new AtomicInteger(); + final AtomicInteger countTotal = new AtomicInteger(); + + final ArrayList list = new ArrayList(); + + s.mapMany(new Func1>() { + + @Override + public Observable call(final Integer v) { + countParent.incrementAndGet(); + + // then subscribe to subject again (it will not receive the previous value) + return s.map(new Func1() { + + @Override + public String call(Integer v2) { + countChildren.incrementAndGet(); + return "Parent: " + v + " Child: " + v2; + } + + }); + } + + }).subscribe(new Action1() { + + @Override + public void call(String v) { + countTotal.incrementAndGet(); + list.add(v); + } + + }); + + for (int i = 0; i < 10; i++) { + s.onNext(i); + } + s.onCompleted(); + + // System.out.println("countParent: " + countParent.get()); + // System.out.println("countChildren: " + countChildren.get()); + // System.out.println("countTotal: " + countTotal.get()); + + // 9+8+7+6+5+4+3+2+1+0 == 45 + assertEquals(45, list.size()); + } + + /** + * Should be able to unsubscribe all Observers, have it stop emitting, then subscribe new ones and it start emitting again. + */ + @Test + public void testReSubscribe() { + final PublishSubject ps = PublishSubject.create(); + + Observer o1 = mock(Observer.class); + Subscription s1 = ps.subscribe(o1); + + // emit + ps.onNext(1); + + // validate we got it + InOrder inOrder1 = inOrder(o1); + inOrder1.verify(o1, times(1)).onNext(1); + inOrder1.verifyNoMoreInteractions(); + + // unsubscribe + s1.unsubscribe(); + + // emit again but nothing will be there to receive it + ps.onNext(2); + + Observer o2 = mock(Observer.class); + Subscription s2 = ps.subscribe(o2); + + // emit + ps.onNext(3); + + // validate we got it + InOrder inOrder2 = inOrder(o2); + inOrder2.verify(o2, times(1)).onNext(3); + inOrder2.verifyNoMoreInteractions(); + + s2.unsubscribe(); + } + + /** + * Even if subject received an onError/onCompleted, new subscriptions should be able to restart it. + */ + @Test + public void testReSubscribeAfterTerminalState() { + final PublishSubject ps = PublishSubject.create(); + + Observer o1 = mock(Observer.class); + Subscription s1 = ps.subscribe(o1); + + // emit + ps.onNext(1); + + // validate we got it + InOrder inOrder1 = inOrder(o1); + inOrder1.verify(o1, times(1)).onNext(1); + inOrder1.verifyNoMoreInteractions(); + + // unsubscribe + s1.unsubscribe(); + + ps.onCompleted(); + + // emit again but nothing will be there to receive it + ps.onNext(2); + + Observer o2 = mock(Observer.class); + Subscription s2 = ps.subscribe(o2); + + // emit + ps.onNext(3); + + // validate we got it + InOrder inOrder2 = inOrder(o2); + inOrder2.verify(o2, times(1)).onNext(3); + inOrder2.verifyNoMoreInteractions(); + + s2.unsubscribe(); + } } diff --git a/rxjava-core/src/test/java/rx/subjects/ReplaySubjectTest.java b/rxjava-core/src/test/java/rx/subjects/ReplaySubjectTest.java index 1e722e5e5e..dc0298a7e3 100644 --- a/rxjava-core/src/test/java/rx/subjects/ReplaySubjectTest.java +++ b/rxjava-core/src/test/java/rx/subjects/ReplaySubjectTest.java @@ -1,7 +1,169 @@ package rx.subjects; -import org.junit.Ignore; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mockito; +import rx.Observer; +import rx.Subscription; +import rx.util.functions.Action1; +import rx.util.functions.Func0; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; -@Ignore("WIP") public class ReplaySubjectTest { + + private final Throwable testException = new Throwable(); + + @SuppressWarnings("unchecked") + @Test + public void testCompleted() { + ReplaySubject subject = ReplaySubject.create(); + + Observer o1 = mock(Observer.class); + subject.subscribe(o1); + + subject.onNext("one"); + subject.onNext("two"); + subject.onNext("three"); + subject.onCompleted(); + + subject.onNext("four"); + subject.onCompleted(); + subject.onError(new Throwable()); + + assertCompletedObserver(o1); + + // assert that subscribing a 2nd time gets the same data + Observer o2 = mock(Observer.class); + subject.subscribe(o2); + assertCompletedObserver(o2); + } + + private void assertCompletedObserver(Observer aObserver) { + InOrder inOrder = inOrder(aObserver); + + inOrder.verify(aObserver, times(1)).onNext("one"); + inOrder.verify(aObserver, times(1)).onNext("two"); + inOrder.verify(aObserver, times(1)).onNext("three"); + inOrder.verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + inOrder.verify(aObserver, times(1)).onCompleted(); + inOrder.verifyNoMoreInteractions(); + } + + @SuppressWarnings("unchecked") + @Test + public void testError() { + ReplaySubject subject = ReplaySubject.create(); + + Observer aObserver = mock(Observer.class); + subject.subscribe(aObserver); + + subject.onNext("one"); + subject.onNext("two"); + subject.onNext("three"); + subject.onError(testException); + + subject.onNext("four"); + subject.onError(new Throwable()); + subject.onCompleted(); + + assertErrorObserver(aObserver); + + aObserver = mock(Observer.class); + subject.subscribe(aObserver); + assertErrorObserver(aObserver); + } + + private void assertErrorObserver(Observer aObserver) { + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, times(1)).onNext("two"); + verify(aObserver, times(1)).onNext("three"); + verify(aObserver, times(1)).onError(testException); + verify(aObserver, Mockito.never()).onCompleted(); + } + + @SuppressWarnings("unchecked") + @Test + public void testSubscribeMidSequence() { + ReplaySubject subject = ReplaySubject.create(); + + Observer aObserver = mock(Observer.class); + subject.subscribe(aObserver); + + subject.onNext("one"); + subject.onNext("two"); + + assertObservedUntilTwo(aObserver); + + Observer anotherObserver = mock(Observer.class); + subject.subscribe(anotherObserver); + assertObservedUntilTwo(anotherObserver); + + subject.onNext("three"); + subject.onCompleted(); + + assertCompletedObserver(aObserver); + assertCompletedObserver(anotherObserver); + } + + @SuppressWarnings("unchecked") + @Test + public void testUnsubscribeFirstObserver() { + ReplaySubject subject = ReplaySubject.create(); + + Observer aObserver = mock(Observer.class); + Subscription subscription = subject.subscribe(aObserver); + + subject.onNext("one"); + subject.onNext("two"); + + subscription.unsubscribe(); + assertObservedUntilTwo(aObserver); + + Observer anotherObserver = mock(Observer.class); + subject.subscribe(anotherObserver); + assertObservedUntilTwo(anotherObserver); + + subject.onNext("three"); + subject.onCompleted(); + + assertObservedUntilTwo(aObserver); + assertCompletedObserver(anotherObserver); + } + + private void assertObservedUntilTwo(Observer aObserver) { + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, times(1)).onNext("two"); + verify(aObserver, Mockito.never()).onNext("three"); + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, Mockito.never()).onCompleted(); + } + + @Test + public void testUnsubscribe() { + UnsubscribeTester.test( + new Func0>() { + @Override + public ReplaySubject call() { + return ReplaySubject.create(); + } + }, new Action1>() { + @Override + public void call(ReplaySubject repeatSubject) { + repeatSubject.onCompleted(); + } + }, new Action1>() { + @Override + public void call(ReplaySubject repeatSubject) { + repeatSubject.onError(new Throwable()); + } + }, new Action1>() { + @Override + public void call(ReplaySubject repeatSubject) { + repeatSubject.onNext("one"); + } + } + ); + } } diff --git a/rxjava-core/src/test/java/rx/subscriptions/CompositeSubscriptionTest.java b/rxjava-core/src/test/java/rx/subscriptions/CompositeSubscriptionTest.java index 43830564ce..3bb8b718a0 100644 --- a/rxjava-core/src/test/java/rx/subscriptions/CompositeSubscriptionTest.java +++ b/rxjava-core/src/test/java/rx/subscriptions/CompositeSubscriptionTest.java @@ -1,7 +1,70 @@ package rx.subscriptions; -import org.junit.Ignore; +import org.junit.Test; +import rx.Subscription; +import rx.util.CompositeException; + +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; -@Ignore("WIP") public class CompositeSubscriptionTest { + + @Test + public void testSuccess() { + final AtomicInteger counter = new AtomicInteger(); + CompositeSubscription s = new CompositeSubscription(); + s.add(new Subscription() { + + @Override + public void unsubscribe() { + counter.incrementAndGet(); + } + }); + + s.add(new Subscription() { + + @Override + public void unsubscribe() { + counter.incrementAndGet(); + } + }); + + s.unsubscribe(); + + assertEquals(2, counter.get()); + } + + @Test + public void testException() { + final AtomicInteger counter = new AtomicInteger(); + CompositeSubscription s = new CompositeSubscription(); + s.add(new Subscription() { + + @Override + public void unsubscribe() { + throw new RuntimeException("failed on first one"); + } + }); + + s.add(new Subscription() { + + @Override + public void unsubscribe() { + counter.incrementAndGet(); + } + }); + + try { + s.unsubscribe(); + fail("Expecting an exception"); + } catch (CompositeException e) { + // we expect this + assertEquals(1, e.getExceptions().size()); + } + + // we should still have unsubscribed to the second one + assertEquals(1, counter.get()); + } } diff --git a/rxjava-core/src/test/java/rx/subscriptions/SubscriptionsTest.java b/rxjava-core/src/test/java/rx/subscriptions/SubscriptionsTest.java index 17bb5b4619..5ac0242a95 100644 --- a/rxjava-core/src/test/java/rx/subscriptions/SubscriptionsTest.java +++ b/rxjava-core/src/test/java/rx/subscriptions/SubscriptionsTest.java @@ -1,7 +1,20 @@ package rx.subscriptions; -import org.junit.Ignore; +import org.junit.Test; +import rx.Subscription; +import rx.util.functions.Action0; + +import static org.mockito.Mockito.*; +import static rx.subscriptions.Subscriptions.create; -@Ignore("WIP") public class SubscriptionsTest { + + @Test + public void testUnsubscribeOnlyOnce() { + Action0 unsubscribe = mock(Action0.class); + Subscription subscription = create(unsubscribe); + subscription.unsubscribe(); + subscription.unsubscribe(); + verify(unsubscribe, times(1)).call(); + } } diff --git a/rxjava-core/src/test/java/rx/test/OperatorTester.java b/rxjava-core/src/test/java/rx/test/OperatorTester.java new file mode 100644 index 0000000000..ab64251583 --- /dev/null +++ b/rxjava-core/src/test/java/rx/test/OperatorTester.java @@ -0,0 +1,94 @@ +/** + * Copyright 2013 Netflix, Inc. + * + * 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 rx.test; + +import rx.Scheduler; +import rx.Subscription; +import rx.util.functions.Action0; +import rx.util.functions.Func2; + +import java.util.concurrent.TimeUnit; + +/** + * Common utility functions for testing operator implementations. + */ +public class OperatorTester { + /* + * This is purposefully package-only so it does not leak into the public API outside of this package. + * + * This package is implementation details and not part of the Javadocs and thus can change without breaking backwards compatibility. + * + * benjchristensen => I'm procrastinating the decision of where and how these types of classes (see rx.subjects.UnsubscribeTester) should exist. + * If they are only for internal implementations then I don't want them as part of the API. + * If they are truly useful for everyone to use then an "rx.testing" package may make sense. + */ + + private OperatorTester() { + } + + /** + * Used for mocking of Schedulers since many Scheduler implementations are static/final. + * + * @param underlying + * @return + */ + public static Scheduler forwardingScheduler(Scheduler underlying) { + return new ForwardingScheduler(underlying); + } + + public static class ForwardingScheduler extends Scheduler { + private final Scheduler underlying; + + public ForwardingScheduler(Scheduler underlying) { + this.underlying = underlying; + } + + @Override + public Subscription schedule(Action0 action) { + return underlying.schedule(action); + } + + @Override + public Subscription schedule(T state, Func2 action) { + return underlying.schedule(state, action); + } + + @Override + public Subscription schedule(Action0 action, long dueTime, TimeUnit unit) { + return underlying.schedule(action, dueTime, unit); + } + + @Override + public Subscription schedule(T state, Func2 action, long dueTime, TimeUnit unit) { + return underlying.schedule(state, action, dueTime, unit); + } + + @Override + public Subscription schedulePeriodically(Action0 action, long initialDelay, long period, TimeUnit unit) { + return underlying.schedulePeriodically(action, initialDelay, period, unit); + } + + @Override + public Subscription schedulePeriodically(T state, Func2 action, long initialDelay, long period, TimeUnit unit) { + return underlying.schedulePeriodically(state, action, initialDelay, period, unit); + } + + @Override + public long now() { + return underlying.now(); + } + } +} \ No newline at end of file diff --git a/rxjava-core/src/test/java/rx/util/RangeTest.java b/rxjava-core/src/test/java/rx/util/RangeTest.java index 640678b5c3..03ec6eef19 100644 --- a/rxjava-core/src/test/java/rx/util/RangeTest.java +++ b/rxjava-core/src/test/java/rx/util/RangeTest.java @@ -1,7 +1,50 @@ package rx.util; -import org.junit.Ignore; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertEquals; -@Ignore("WIP") public class RangeTest { + + @Test + public void testSimpleRange() { + assertEquals(Arrays.asList(1, 2, 3, 4), toList(Range.create(1, 5))); + } + + @Test + public void testRangeWithStep() { + assertEquals(Arrays.asList(1, 3, 5, 7, 9), toList(Range.createWithStep(1, 10, 2))); + } + + @Test + public void testRangeWithCount() { + assertEquals(Arrays.asList(1, 2, 3, 4, 5), toList(Range.createWithCount(1, 5))); + } + + @Test + public void testRangeWithCount2() { + assertEquals(Arrays.asList(2, 3, 4, 5), toList(Range.createWithCount(2, 4))); + } + + @Test + public void testRangeWithCount3() { + assertEquals(Arrays.asList(0, 1, 2, 3), toList(Range.createWithCount(0, 4))); + } + + @Test + public void testRangeWithCount4() { + assertEquals(Arrays.asList(10, 11, 12, 13, 14), toList(Range.createWithCount(10, 5))); + } + + private static List toList(Iterable iterable) { + List result = new ArrayList(); + for (T element : iterable) { + result.add(element); + } + return result; + } }