diff --git a/.circleci/config.yml b/.circleci/config.yml index ebf33d9..d06c8ce 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ jobs: build: working_directory: ~/sharedsequence docker: - - image: circleci/android:api-25-alpha + - image: circleci/android:api-26-alpha environment: JVM_OPTS: -Xmx3200m steps: diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index e76985d..0000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 99202cc..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index ab8da8f..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml deleted file mode 100644 index 7f68460..0000000 --- a/.idea/runConfigurations.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/SharedSequence/build.gradle b/SharedSequence/build.gradle index 3d4ec73..d29b9e9 100644 --- a/SharedSequence/build.gradle +++ b/SharedSequence/build.gradle @@ -31,13 +31,6 @@ android { flavorDimensions "mode" - sourceSets { - main.java.srcDirs += "src/main/kotlin" - test.java.srcDirs += 'src/test/kotlin' - debug.java.srcDirs += "${buildDir.absolutePath}/generated/source/kaptKotlin/debug" - release.java.srcDirs += "${buildDir.absolutePath}/generated/source/kaptKotlin/release" - } - lintOptions { disable 'OldTargetApi' } diff --git a/SharedSequence/src/main/kotlin/org/notests/sharedsequence/DriverTraits.kt b/SharedSequence/src/main/java/org/notests/sharedsequence/DriverTraits.kt similarity index 100% rename from SharedSequence/src/main/kotlin/org/notests/sharedsequence/DriverTraits.kt rename to SharedSequence/src/main/java/org/notests/sharedsequence/DriverTraits.kt diff --git a/SharedSequence/src/main/kotlin/org/notests/sharedsequence/SignalTraits.kt b/SharedSequence/src/main/java/org/notests/sharedsequence/SignalTraits.kt similarity index 100% rename from SharedSequence/src/main/kotlin/org/notests/sharedsequence/SignalTraits.kt rename to SharedSequence/src/main/java/org/notests/sharedsequence/SignalTraits.kt diff --git a/SharedSequence/src/test/java/org/notests/sharedsequence/DriverTest.kt b/SharedSequence/src/test/java/org/notests/sharedsequence/DriverTest.kt new file mode 100644 index 0000000..7b1fa1d --- /dev/null +++ b/SharedSequence/src/test/java/org/notests/sharedsequence/DriverTest.kt @@ -0,0 +1,917 @@ +package org.notests.sharedsequence + +import io.reactivex.Observable +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.TestScheduler +import org.junit.After +import org.junit.Assert +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.notests.sharedsequence.api.ErrorReporting +import org.notests.sharedsequence.utils.MyTestSubscriber +import org.notests.sharedsequence.utils.TestSchedulerRule +import org.notests.sharedsequence.utils.advanceTimeBy +import org.notests.sharedsequence.utils.complete +import org.notests.sharedsequence.utils.createColdObservable +import org.notests.sharedsequence.utils.createMyTestSubscriber +import org.notests.sharedsequence.utils.error +import org.notests.sharedsequence.utils.next +import org.notests.sharedsequence.utils.scheduleAt + +/** + * Created by juraj begovac on 13/9/18 + */ +class DriverTest : Assert() { + + private lateinit var scheduler: TestScheduler + private lateinit var observer: MyTestSubscriber + + @get:Rule + val testSchedulerRule = TestSchedulerRule() + + @Before + fun setUp() { + scheduler = testSchedulerRule.testScheduler + observer = scheduler.createMyTestSubscriber() + } + + @After + fun tearDown() { + observer.dispose() + } + + @Test + fun driverCompleteOnError() { + scheduler.scheduleAt(0) { + observableRange() + .map { + if (it == 5) throw Exception() + else it + } + .asDriverCompleteOnError() + .drive(observer) + } + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 1), + next(0, 2), + next(0, 3), + next(0, 4), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun driverOnErrorJustReturn() { + val returnOnError = 7 + + scheduler.scheduleAt(0) { + observableRange() + .map { + if (it == 5) throw Exception() + else it + } + .asDriver(returnOnError) + .drive(observer) + } + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 1), + next(0, 2), + next(0, 3), + next(0, 4), + next(0, 7), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun driverOnErrorDriveWith() { + scheduler.scheduleAt(0) { + observableRange() + .map { + if (it == 5) throw Exception() + else it + } + .asDriver(observableRange().asDriverCompleteOnError()) + .drive(observer) + } + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 1), + next(0, 2), + next(0, 3), + next(0, 4), + next(0, 1), + next(0, 2), + next(0, 3), + next(0, 4), + next(0, 5), + next(0, 6), + next(0, 7), + next(0, 8), + next(0, 9), + next(0, 10), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun defer() { + scheduler.scheduleAt(0) { + Driver.defer { observableRange().asDriverCompleteOnError() } + .drive(observer) + } + scheduler.triggerActions() + + assertEquals( + arrayListOf( + next(0, 1), + next(0, 2), + next(0, 3), + next(0, 4), + next(0, 5), + next(0, 6), + next(0, 7), + next(0, 8), + next(0, 9), + next(0, 10), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Suppress("ConstantConditionIf") + @Test + fun deferOnErrorComplete() { + scheduler.scheduleAt(0) { + Driver.defer { + if (true) throw Exception() + else + observableRange().asDriverCompleteOnError() + } + .drive(observer) + } + scheduler.triggerActions() + + assertEquals(listOf(complete(0)), observer.recordedEvents()) + } + + @Test + fun catchErrorAndComplete() { + scheduler.scheduleAt(0) { + observableRange() + .map { + if (it == 5) + throw Exception() + else it + } + .asDriverCompleteOnError() + .drive(observer) + } + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 1), + next(0, 2), + next(0, 3), + next(0, 4), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun catchErrorAndReturn() { + val returnOnError = 7 + + observableRange() + .map { + if (it == 5) + throw Exception() + else it + } + .asDriver(Driver.just(returnOnError)) + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 1), + next(0, 2), + next(0, 3), + next(0, 4), + next(0, 7), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun map() { + val exception = Exception("5 reached") + + val errorObserver = scheduler.createMyTestSubscriber() + + ErrorReporting.exceptions() + .subscribe(errorObserver) + + observableRange() + .asDriverCompleteOnError() + .map { + if (it == 5) + throw exception + else it + } + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 1), + next(0, 2), + next(0, 3), + next(0, 4), + next(0, 6), + next(0, 7), + next(0, 8), + next(0, 9), + next(0, 10), + complete(0) + ), + observer.recordedEvents() + ) + + assertEquals( + listOf(next(0, exception)), + errorObserver.recordedEvents() + ) + } + + @Test + fun filter() { + observableRange() + .asDriverCompleteOnError() + .filter { + if (it == 5) + throw Exception() + else true + } + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 1), + next(0, 2), + next(0, 3), + next(0, 4), + next(0, 6), + next(0, 7), + next(0, 8), + next(0, 9), + next(0, 10), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun flatMap() { + observableRange() + .asDriverCompleteOnError() + .flatMapDriver { + if (it == 5) + throw Exception() + else Driver.just(it) + } + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 1), + next(0, 2), + next(0, 3), + next(0, 4), + next(0, 6), + next(0, 7), + next(0, 8), + next(0, 9), + next(0, 10), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun driverSharing_WhenErroring() { + val observer1 = scheduler.createMyTestSubscriber() + val observer2 = scheduler.createMyTestSubscriber() + val observer3 = scheduler.createMyTestSubscriber() + + var disposable1: Disposable? = null + var disposable2: Disposable? = null + var disposable3: Disposable? = null + + val coldObservable = scheduler.createColdObservable( + next(10, 0), + next(20, 1), + next(30, 2), + next(40, 3), + error(50, Error("Test")) + ) + + val driver = coldObservable.asDriver(-1) + + scheduler.scheduleAt(200) { + disposable1 = + driver.asObservable() + .subscribe({ observer1.onNext(it) }, + { observer1.onError(it) }, + { observer1.onComplete() }) + } + + scheduler.scheduleAt(225) { + disposable2 = + driver.asObservable() + .subscribe({ observer2.onNext(it) }, + { observer2.onError(it) }, + { observer2.onComplete() }) + } + + scheduler.scheduleAt(235) { disposable1!!.dispose() } + + scheduler.scheduleAt(260) { disposable2!!.dispose() } + + // resubscription + scheduler.scheduleAt(260) { + disposable3 = + driver.asObservable() + .subscribe({ observer3.onNext(it) }, + { observer3.onError(it) }, + { observer3.onComplete() }) + } + + scheduler.scheduleAt(285) { disposable3!!.dispose() } + + scheduler.advanceTimeBy(1000) + + assertEquals( + listOf( + next(210, 0), + next(220, 1), + next(230, 2) + ), + observer1.recordedEvents() + ) + + assertEquals( + listOf( + next(225, 1), + next(230, 2), + next(240, 3), + next(250, -1), + complete(250) + ), + observer2.recordedEvents() + ) + + assertEquals( + listOf( + next(270, 0), + next(280, 1) + ), + observer3.recordedEvents() + ) + } + + @Test + fun driverSharing_WhenCompleted() { + val observer1 = scheduler.createMyTestSubscriber() + val observer2 = scheduler.createMyTestSubscriber() + val observer3 = scheduler.createMyTestSubscriber() + + var disposable1: Disposable? = null + var disposable2: Disposable? = null + var disposable3: Disposable? = null + + val coldObservable = scheduler.createColdObservable( + next(10, 0), + next(20, 1), + next(30, 2), + next(40, 3), + complete(50) + ) + + val driver = coldObservable.asDriver(-1) + + scheduler.scheduleAt(200) { + disposable1 = + driver.asObservable() + .subscribe({ observer1.onNext(it) }, + { observer1.onError(it) }, + { observer1.onComplete() }) + } + + scheduler.scheduleAt(225) { + disposable2 = + driver.asObservable() + .subscribe({ observer2.onNext(it) }, + { observer2.onError(it) }, + { observer2.onComplete() }) + } + + scheduler.scheduleAt(235) { disposable1!!.dispose() } + + scheduler.scheduleAt(260) { disposable2!!.dispose() } + + // resubscription + scheduler.scheduleAt(260) { + disposable3 = + driver.asObservable() + .subscribe({ observer3.onNext(it) }, + { observer3.onError(it) }, + { observer3.onComplete() }) + } + + scheduler.scheduleAt(285) { disposable3!!.dispose() } + + scheduler.advanceTimeBy(1000) + + assertEquals( + listOf( + next(210, 0), + next(220, 1), + next(230, 2) + ), + observer1.recordedEvents() + ) + + assertEquals( + listOf( + next(225, 1), + next(230, 2), + next(240, 3), + complete(250) + ), + observer2.recordedEvents() + ) + + assertEquals( + listOf( + next(270, 0), + next(280, 1) + ), + observer3.recordedEvents() + ) + } + + @Test + fun asDriver_onErrorJustReturn() { + val source = scheduler.createColdObservable(next(0, 1), next(0, 2), error(0, Error("Test"))) + + source.asDriver(-1) + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 1), + next(0, 2), + next(0, -1), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun asDriver_onErrorDriveWith() { + val source = scheduler.createColdObservable(next(0, 1), next(0, 2), error(0, Error("Test"))) + + source.asDriver(Driver.just(-1)) + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 1), + next(0, 2), + next(0, -1), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun asDriver_onErrorRecover() { + val source = scheduler.createColdObservable(next(0, 1), next(0, 2), error(0, Error("Test"))) + + source.asDriver(Driver.empty()) + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 1), + next(0, 2), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun asDriver_defer() { + val source = scheduler.createColdObservable(next(0, 1), next(0, 2), error(0, Error("Test"))) + + Driver.defer { source.asDriver(-1) } + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 1), + next(0, 2), + next(0, -1), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun asDriver_map() { + val source = scheduler.createColdObservable(next(0, 1), next(0, 2), error(0, Error("Test"))) + + source.asDriver(-1) + .map { it + 1 } + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 2), + next(0, 3), + next(0, 0), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun asDriver_filter() { + val source = scheduler.createColdObservable(next(0, 1), next(0, 2), error(0, Error("Test"))) + + source.asDriver(-1) + .filter { it % 2 == 0 } + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 2), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun asDriver_switchMap() { + val observable = scheduler.createColdObservable( + next(0, 0), + next(1, 1), + error(2, Error("Test")), + complete(3) + ) + val observable1 = scheduler.createColdObservable( + next(0, 1), + next(0, 2), + error(0, Error("Test")) + ) + val observable2 = scheduler.createColdObservable( + next(0, 10), + next(0, 11), + error(0, Error("Test")) + ) + val errorObservable = scheduler.createColdObservable(complete(0)) + + val drivers = arrayListOf( + observable1.asDriver(-2), + observable2.asDriver(-3), + errorObservable.asDriver(-4) + ) + + observable.asDriver(2) + .switchMapDriver { drivers[it] } + .drive(observer) + + scheduler.advanceTimeBy(10) + + assertEquals( + listOf( + next(0, 1), + next(0, 2), + next(0, -2), + next(1, 10), + next(1, 11), + next(1, -3), + complete(2) + ), + observer.recordedEvents() + ) + } + + @Test + fun asDriver_switchMap_overlapping() { + val observable = scheduler.createColdObservable( + next(0, 0), + next(1, 1), + error(2, Error("Test")), + complete(3) + ) + val observable1 = scheduler.createColdObservable( + next(0, 1), + error(0, Error("Test")), + next(1, 2) + ) + val observable2 = scheduler.createColdObservable( + next(0, 10), + error(0, Error("Test")), + next(1, 11) + ) + val errorObservable = scheduler.createColdObservable(complete(0)) + + val drivers = arrayListOf( + observable1.asDriver(-2), + observable2.asDriver(-3), + errorObservable.asDriver(-4) + ) + + observable.asDriver(2) + .switchMapDriver { drivers[it] } + .drive(observer) + + scheduler.advanceTimeBy(10) + + assertEquals( + listOf( + next(0, 1), + next(0, -2), + next(1, 10), + next(1, -3), + complete(2) + ), + observer.recordedEvents() + ) + } + + @Test + fun asDriver_doOnNext() { + val observable = scheduler.createColdObservable( + next(0, 1), + next(0, 2), + error(0, Error("Test")) + ) + + var events = emptyArray() + + observable.asDriver(-1) + .doOnNext { + events += it + } + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 1), + next(0, 2), + next(0, -1), + complete(0) + ), + observer.recordedEvents() + ) + + val expectedEvents = arrayOf(1, 2, -1) + assertArrayEquals(expectedEvents, events) + } + + @Test + fun asDriver_distinctUntilChanged1() { + val observable = scheduler.createColdObservable( + next(0, 1), + next(0, 2), + next(0, 2), + error(0, Error("Test")) + ) + observable.asDriver(-1) + .distinctUntilChanged() + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 1), + next(0, 2), + next(0, -1), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun asDriver_distinctUntilChanged2() { + val observable = scheduler.createColdObservable( + next(0, 1), + next(0, 2), + next(0, 2), + error(0, Error("Test")) + ) + observable.asDriver(-1) + .distinctUntilChanged { e -> e } + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 1), + next(0, 2), + next(0, -1), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun asDriver_distinctUntilChanged3() { + val observable = scheduler.createColdObservable( + next(0, 1), + next(0, 2), + next(0, 2), + error(0, Error("Test")) + ) + observable.asDriver(-1) + .distinctUntilChanged { e1, e2 -> e1 == e2 } + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 1), + next(0, 2), + next(0, -1), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun asDriver_flatMap() { + val observable = scheduler.createColdObservable( + next(0, 1), + next(0, 2), + error(0, Error("Test")) + ) + observable.asDriver(-1) + .flatMapDriver { + Driver.just(it + 1) + } + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 2), + next(0, 3), + next(0, 0), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun asDriver_merge() { + val observable: Observable = scheduler.createColdObservable( + next(0, 1), + next(0, 2), + error(0, Error("Test")) + ) + + Driver.merge(arrayListOf(observable.asDriver(-1).flatMapDriver { Driver.just(it + 1) })) + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 2), + next(0, 3), + next(0, 0), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun asDriver_scan() { + val observable: Observable = scheduler.createColdObservable( + next(0, 1), + next(0, 2), + error(0, Error("Test")) + ) + + observable.asDriver(-1) + .scan(0) { a, n -> a + n } + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 0), + next(0, 1), + next(0, 3), + next(0, 2), + complete(0) + ), + observer.recordedEvents() + ) + } + + @Test + fun asDriver_startWith() { + val observable: Observable = scheduler.createColdObservable( + next(0, 1), + next(0, 2), + error(0, Error("Test")) + ) + observable.asDriver(-1) + .startWith(0) + .drive(observer) + + scheduler.triggerActions() + + assertEquals( + listOf( + next(0, 0), + next(0, 1), + next(0, 2), + next(0, -1), + complete(0) + ), + observer.recordedEvents() + ) + } + + private fun observableRange() = Observable.range(1, 10) + + private fun Observable.asDriverCompleteOnError(): Driver = + asDriver(Driver.empty()) + + private fun Observable.asDriver(onErrorJustReturn: Element): Driver = + asDriver(Driver.just(onErrorJustReturn)) +} diff --git a/SharedSequence/src/test/kotlin/org/notests/sharedsequence/utils/MyTestSubscriber.kt b/SharedSequence/src/test/java/org/notests/sharedsequence/utils/MyTestSubscriber.kt similarity index 100% rename from SharedSequence/src/test/kotlin/org/notests/sharedsequence/utils/MyTestSubscriber.kt rename to SharedSequence/src/test/java/org/notests/sharedsequence/utils/MyTestSubscriber.kt diff --git a/SharedSequence/src/test/kotlin/org/notests/sharedsequence/utils/TestScheduler+Extensions.kt b/SharedSequence/src/test/java/org/notests/sharedsequence/utils/TestScheduler+Extensions.kt similarity index 100% rename from SharedSequence/src/test/kotlin/org/notests/sharedsequence/utils/TestScheduler+Extensions.kt rename to SharedSequence/src/test/java/org/notests/sharedsequence/utils/TestScheduler+Extensions.kt diff --git a/SharedSequence/src/test/kotlin/org/notests/sharedsequence/utils/TestSchedulerRule.kt b/SharedSequence/src/test/java/org/notests/sharedsequence/utils/TestSchedulerRule.kt similarity index 97% rename from SharedSequence/src/test/kotlin/org/notests/sharedsequence/utils/TestSchedulerRule.kt rename to SharedSequence/src/test/java/org/notests/sharedsequence/utils/TestSchedulerRule.kt index 02264f8..6e325f4 100644 --- a/SharedSequence/src/test/kotlin/org/notests/sharedsequence/utils/TestSchedulerRule.kt +++ b/SharedSequence/src/test/java/org/notests/sharedsequence/utils/TestSchedulerRule.kt @@ -15,7 +15,7 @@ import org.junit.runners.model.Statement class TestSchedulerRule : TestRule { private val immediate = object : Scheduler() { - override fun createWorker(): Worker = ExecutorScheduler(Runnable::run).createWorker() + override fun createWorker(): Worker = ExecutorScheduler(Runnable::run, false).createWorker() } val testScheduler = TestScheduler() diff --git a/SharedSequence/src/test/kotlin/org/notests/sharedsequence/DriverTest.kt b/SharedSequence/src/test/kotlin/org/notests/sharedsequence/DriverTest.kt deleted file mode 100644 index 07aabbd..0000000 --- a/SharedSequence/src/test/kotlin/org/notests/sharedsequence/DriverTest.kt +++ /dev/null @@ -1,762 +0,0 @@ -package org.notests.sharedsequence - -import io.reactivex.Observable -import io.reactivex.disposables.Disposable -import io.reactivex.schedulers.TestScheduler -import org.junit.After -import org.junit.Assert -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.notests.sharedsequence.api.ErrorReporting -import org.notests.sharedsequence.utils.MyTestSubscriber -import org.notests.sharedsequence.utils.TestSchedulerRule -import org.notests.sharedsequence.utils.advanceTimeBy -import org.notests.sharedsequence.utils.complete -import org.notests.sharedsequence.utils.createColdObservable -import org.notests.sharedsequence.utils.createMyTestSubscriber -import org.notests.sharedsequence.utils.error -import org.notests.sharedsequence.utils.next -import org.notests.sharedsequence.utils.scheduleAt - -/** - * Created by juraj begovac on 13/9/18 - */ -class DriverTest : Assert() { - - private lateinit var scheduler: TestScheduler - private lateinit var observer: MyTestSubscriber - - @get:Rule - val testSchedulerRule = TestSchedulerRule() - - @Before - fun setUp() { - scheduler = testSchedulerRule.testScheduler - observer = scheduler.createMyTestSubscriber() - } - - @After - fun tearDown() { - observer.dispose() - } - - @Test - fun driverCompleteOnError() { - scheduler.scheduleAt(0) { - observableRange() - .map { - if (it == 5) throw Exception() - else it - } - .asDriverCompleteOnError() - .drive(observer) - } - scheduler.triggerActions() - - assertEquals(listOf(next(0, 1), - next(0, 2), - next(0, 3), - next(0, 4), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun driverOnErrorJustReturn() { - val returnOnError = 7 - - scheduler.scheduleAt(0) { - observableRange() - .map { - if (it == 5) throw Exception() - else it - } - .asDriver(returnOnError) - .drive(observer) - } - scheduler.triggerActions() - - assertEquals(listOf(next(0, 1), - next(0, 2), - next(0, 3), - next(0, 4), - next(0, 7), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun driverOnErrorDriveWith() { - scheduler.scheduleAt(0) { - observableRange() - .map { - if (it == 5) throw Exception() - else it - } - .asDriver(observableRange().asDriverCompleteOnError()) - .drive(observer) - } - scheduler.triggerActions() - - assertEquals( - listOf(next(0, 1), - next(0, 2), - next(0, 3), - next(0, 4), - next(0, 1), - next(0, 2), - next(0, 3), - next(0, 4), - next(0, 5), - next(0, 6), - next(0, 7), - next(0, 8), - next(0, 9), - next(0, 10), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun defer() { - scheduler.scheduleAt(0) { - Driver.defer { observableRange().asDriverCompleteOnError() } - .drive(observer) - } - scheduler.triggerActions() - - assertEquals( - arrayListOf( - next(0, 1), - next(0, 2), - next(0, 3), - next(0, 4), - next(0, 5), - next(0, 6), - next(0, 7), - next(0, 8), - next(0, 9), - next(0, 10), - complete(0)), - observer.recordedEvents()) - } - - @Suppress("ConstantConditionIf") - @Test - fun deferOnErrorComplete() { - scheduler.scheduleAt(0) { - Driver.defer { - if (true) throw Exception() - else - observableRange().asDriverCompleteOnError() - } - .drive(observer) - } - scheduler.triggerActions() - - assertEquals(listOf(complete(0)), observer.recordedEvents()) - } - - @Test - fun catchErrorAndComplete() { - scheduler.scheduleAt(0) { - observableRange() - .map { - if (it == 5) - throw Exception() - else it - } - .asDriverCompleteOnError() - .drive(observer) - } - scheduler.triggerActions() - - assertEquals( - listOf(next(0, 1), - next(0, 2), - next(0, 3), - next(0, 4), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun catchErrorAndReturn() { - val returnOnError = 7 - - observableRange() - .map { - if (it == 5) - throw Exception() - else it - } - .asDriver(Driver.just(returnOnError)) - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 1), - next(0, 2), - next(0, 3), - next(0, 4), - next(0, 7), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun map() { - val exception = Exception("5 reached") - - val errorObserver = scheduler.createMyTestSubscriber() - - ErrorReporting.exceptions() - .subscribe(errorObserver) - - observableRange() - .asDriverCompleteOnError() - .map { - if (it == 5) - throw exception - else it - } - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 1), - next(0, 2), - next(0, 3), - next(0, 4), - next(0, 6), - next(0, 7), - next(0, 8), - next(0, 9), - next(0, 10), - complete(0)), - observer.recordedEvents()) - - assertEquals(listOf(next(0, exception)), - errorObserver.recordedEvents()) - } - - @Test - fun filter() { - observableRange() - .asDriverCompleteOnError() - .filter { - if (it == 5) - throw Exception() - else true - } - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 1), - next(0, 2), - next(0, 3), - next(0, 4), - next(0, 6), - next(0, 7), - next(0, 8), - next(0, 9), - next(0, 10), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun flatMap() { - observableRange() - .asDriverCompleteOnError() - .flatMapDriver { - if (it == 5) - throw Exception() - else Driver.just(it) - } - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 1), - next(0, 2), - next(0, 3), - next(0, 4), - next(0, 6), - next(0, 7), - next(0, 8), - next(0, 9), - next(0, 10), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun driverSharing_WhenErroring() { - val observer1 = scheduler.createMyTestSubscriber() - val observer2 = scheduler.createMyTestSubscriber() - val observer3 = scheduler.createMyTestSubscriber() - - var disposable1: Disposable? = null - var disposable2: Disposable? = null - var disposable3: Disposable? = null - - val coldObservable = scheduler.createColdObservable( - next(10, 0), - next(20, 1), - next(30, 2), - next(40, 3), - error(50, Error("Test"))) - - val driver = coldObservable.asDriver(-1) - - scheduler.scheduleAt(200) { - disposable1 = - driver.asObservable() - .subscribe({ observer1.onNext(it) }, - { observer1.onError(it) }, - { observer1.onComplete() }) - } - - scheduler.scheduleAt(225) { - disposable2 = - driver.asObservable() - .subscribe({ observer2.onNext(it) }, - { observer2.onError(it) }, - { observer2.onComplete() }) - } - - scheduler.scheduleAt(235) { disposable1!!.dispose() } - - scheduler.scheduleAt(260) { disposable2!!.dispose() } - - // resubscription - scheduler.scheduleAt(260) { - disposable3 = - driver.asObservable() - .subscribe({ observer3.onNext(it) }, - { observer3.onError(it) }, - { observer3.onComplete() }) - } - - scheduler.scheduleAt(285) { disposable3!!.dispose() } - - scheduler.advanceTimeBy(1000) - - assertEquals(listOf(next(210, 0), - next(220, 1), - next(230, 2)), - observer1.recordedEvents()) - - assertEquals(listOf(next(225, 1), - next(230, 2), - next(240, 3), - next(250, -1), - complete(250)), - observer2.recordedEvents()) - - assertEquals(listOf(next(270, 0), - next(280, 1)), - observer3.recordedEvents()) - } - - @Test - fun driverSharing_WhenCompleted() { - val observer1 = scheduler.createMyTestSubscriber() - val observer2 = scheduler.createMyTestSubscriber() - val observer3 = scheduler.createMyTestSubscriber() - - var disposable1: Disposable? = null - var disposable2: Disposable? = null - var disposable3: Disposable? = null - - val coldObservable = scheduler.createColdObservable( - next(10, 0), - next(20, 1), - next(30, 2), - next(40, 3), - complete(50)) - - val driver = coldObservable.asDriver(-1) - - scheduler.scheduleAt(200) { - disposable1 = - driver.asObservable() - .subscribe({ observer1.onNext(it) }, - { observer1.onError(it) }, - { observer1.onComplete() }) - } - - scheduler.scheduleAt(225) { - disposable2 = - driver.asObservable() - .subscribe({ observer2.onNext(it) }, - { observer2.onError(it) }, - { observer2.onComplete() }) - } - - scheduler.scheduleAt(235) { disposable1!!.dispose() } - - scheduler.scheduleAt(260) { disposable2!!.dispose() } - - // resubscription - scheduler.scheduleAt(260) { - disposable3 = - driver.asObservable() - .subscribe({ observer3.onNext(it) }, - { observer3.onError(it) }, - { observer3.onComplete() }) - } - - scheduler.scheduleAt(285) { disposable3!!.dispose() } - - scheduler.advanceTimeBy(1000) - - assertEquals(listOf(next(210, 0), - next(220, 1), - next(230, 2)), - observer1.recordedEvents()) - - assertEquals(listOf(next(225, 1), - next(230, 2), - next(240, 3), - complete(250)), - observer2.recordedEvents()) - - assertEquals(listOf(next(270, 0), - next(280, 1)), - observer3.recordedEvents()) - } - - @Test - fun asDriver_onErrorJustReturn() { - val source = scheduler.createColdObservable(next(0, 1), next(0, 2), error(0, Error("Test"))) - - source.asDriver(-1) - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 1), - next(0, 2), - next(0, -1), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun asDriver_onErrorDriveWith() { - val source = scheduler.createColdObservable(next(0, 1), next(0, 2), error(0, Error("Test"))) - - source.asDriver(Driver.just(-1)) - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 1), - next(0, 2), - next(0, -1), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun asDriver_onErrorRecover() { - val source = scheduler.createColdObservable(next(0, 1), next(0, 2), error(0, Error("Test"))) - - source.asDriver(Driver.empty()) - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 1), - next(0, 2), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun asDriver_defer() { - val source = scheduler.createColdObservable(next(0, 1), next(0, 2), error(0, Error("Test"))) - - Driver.defer { source.asDriver(-1) } - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 1), - next(0, 2), - next(0, -1), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun asDriver_map() { - val source = scheduler.createColdObservable(next(0, 1), next(0, 2), error(0, Error("Test"))) - - source.asDriver(-1) - .map { it + 1 } - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 2), - next(0, 3), - next(0, 0), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun asDriver_filter() { - val source = scheduler.createColdObservable(next(0, 1), next(0, 2), error(0, Error("Test"))) - - source.asDriver(-1) - .filter { it % 2 == 0 } - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 2), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun asDriver_switchMap() { - val observable = scheduler.createColdObservable(next(0, 0), - next(1, 1), - error(2, Error("Test")), - complete(3)) - val observable1 = scheduler.createColdObservable(next(0, 1), - next(0, 2), - error(0, Error("Test"))) - val observable2 = scheduler.createColdObservable(next(0, 10), - next(0, 11), - error(0, Error("Test"))) - val errorObservable = scheduler.createColdObservable(complete(0)) - - val drivers = arrayListOf( - observable1.asDriver(-2), - observable2.asDriver(-3), - errorObservable.asDriver(-4)) - - observable.asDriver(2) - .switchMapDriver { drivers[it] } - .drive(observer) - - scheduler.advanceTimeBy(10) - - assertEquals(listOf(next(0, 1), - next(0, 2), - next(0, -2), - next(1, 10), - next(1, 11), - next(1, -3), - complete(2)), - observer.recordedEvents()) - } - - @Test - fun asDriver_switchMap_overlapping() { - val observable = scheduler.createColdObservable(next(0, 0), - next(1, 1), - error(2, Error("Test")), - complete(3)) - val observable1 = scheduler.createColdObservable(next(0, 1), - error(0, Error("Test")), - next(1, 2)) - val observable2 = scheduler.createColdObservable(next(0, 10), - error(0, Error("Test")), - next(1, 11)) - val errorObservable = scheduler.createColdObservable(complete(0)) - - val drivers = arrayListOf(observable1.asDriver(-2), - observable2.asDriver(-3), - errorObservable.asDriver(-4)) - - observable.asDriver(2) - .switchMapDriver { drivers[it] } - .drive(observer) - - scheduler.advanceTimeBy(10) - - assertEquals(listOf(next(0, 1), - next(0, -2), - next(1, 10), - next(1, -3), - complete(2)), - observer.recordedEvents()) - } - - @Test - fun asDriver_doOnNext() { - val observable = scheduler.createColdObservable(next(0, 1), - next(0, 2), - error(0, Error("Test"))) - - var events = emptyArray() - - observable.asDriver(-1) - .doOnNext { - events += it - } - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 1), - next(0, 2), - next(0, -1), - complete(0)), - observer.recordedEvents()) - - val expectedEvents = arrayOf(1, 2, -1) - assertArrayEquals(expectedEvents, events) - } - - @Test - fun asDriver_distinctUntilChanged1() { - val observable = scheduler.createColdObservable(next(0, 1), - next(0, 2), - next(0, 2), - error(0, Error("Test"))) - observable.asDriver(-1) - .distinctUntilChanged() - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 1), - next(0, 2), - next(0, -1), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun asDriver_distinctUntilChanged2() { - val observable = scheduler.createColdObservable(next(0, 1), - next(0, 2), - next(0, 2), - error(0, Error("Test"))) - observable.asDriver(-1) - .distinctUntilChanged { e -> e } - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 1), - next(0, 2), - next(0, -1), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun asDriver_distinctUntilChanged3() { - val observable = scheduler.createColdObservable(next(0, 1), - next(0, 2), - next(0, 2), - error(0, Error("Test"))) - observable.asDriver(-1) - .distinctUntilChanged { e1, e2 -> e1 == e2 } - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 1), - next(0, 2), - next(0, -1), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun asDriver_flatMap() { - val observable = scheduler.createColdObservable(next(0, 1), - next(0, 2), - error(0, Error("Test"))) - observable.asDriver(-1) - .flatMapDriver { - Driver.just(it + 1) - } - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 2), - next(0, 3), - next(0, 0), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun asDriver_merge() { - val observable: Observable = scheduler.createColdObservable(next(0, 1), - next(0, 2), - error(0, Error("Test"))) - - Driver.merge(arrayListOf(observable.asDriver(-1).flatMapDriver { Driver.just(it + 1) })) - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 2), - next(0, 3), - next(0, 0), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun asDriver_scan() { - val observable: Observable = scheduler.createColdObservable(next(0, 1), - next(0, 2), - error(0, Error("Test"))) - - observable.asDriver(-1) - .scan(0) { a, n -> a + n } - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 0), - next(0, 1), - next(0, 3), - next(0, 2), - complete(0)), - observer.recordedEvents()) - } - - @Test - fun asDriver_startWith() { - val observable: Observable = scheduler.createColdObservable(next(0, 1), - next(0, 2), - error(0, Error("Test"))) - observable.asDriver(-1) - .startWith(0) - .drive(observer) - - scheduler.triggerActions() - - assertEquals(listOf(next(0, 0), - next(0, 1), - next(0, 2), - next(0, -1), - complete(0)), - observer.recordedEvents()) - } - - private fun observableRange() = Observable.range(1, 10) - - private fun Observable.asDriverCompleteOnError(): Driver = - asDriver(Driver.empty()) - - private fun Observable.asDriver(onErrorJustReturn: Element): Driver = - asDriver(Driver.just(onErrorJustReturn)) -} diff --git a/SharedSequenceApi/build.gradle b/SharedSequenceApi/build.gradle index ad20a9d..66b2f2a 100644 --- a/SharedSequenceApi/build.gradle +++ b/SharedSequenceApi/build.gradle @@ -10,9 +10,5 @@ dependencies { implementation 'io.reactivex.rxjava2:rxjava:' + versions.rxjava2 } -sourceSets { - main.java.srcDirs += "src/main/kotlin" -} - sourceCompatibility = "1.7" targetCompatibility = "1.7" diff --git a/SharedSequenceApi/src/main/kotlin/org/notests/sharedsequence/api/ErrorReporting.kt b/SharedSequenceApi/src/main/java/org/notests/sharedsequence/api/ErrorReporting.kt similarity index 100% rename from SharedSequenceApi/src/main/kotlin/org/notests/sharedsequence/api/ErrorReporting.kt rename to SharedSequenceApi/src/main/java/org/notests/sharedsequence/api/ErrorReporting.kt diff --git a/SharedSequenceApi/src/main/kotlin/org/notests/sharedsequence/api/Observable+Extensions.kt b/SharedSequenceApi/src/main/java/org/notests/sharedsequence/api/Observable+Extensions.kt similarity index 100% rename from SharedSequenceApi/src/main/kotlin/org/notests/sharedsequence/api/Observable+Extensions.kt rename to SharedSequenceApi/src/main/java/org/notests/sharedsequence/api/Observable+Extensions.kt diff --git a/SharedSequenceApi/src/main/kotlin/org/notests/sharedsequence/api/SharedSequence.kt b/SharedSequenceApi/src/main/java/org/notests/sharedsequence/api/SharedSequence.kt similarity index 100% rename from SharedSequenceApi/src/main/kotlin/org/notests/sharedsequence/api/SharedSequence.kt rename to SharedSequenceApi/src/main/java/org/notests/sharedsequence/api/SharedSequence.kt diff --git a/SharedSequenceApi/src/main/kotlin/org/notests/sharedsequence/api/SharingTraits.kt b/SharedSequenceApi/src/main/java/org/notests/sharedsequence/api/SharingTraits.kt similarity index 100% rename from SharedSequenceApi/src/main/kotlin/org/notests/sharedsequence/api/SharingTraits.kt rename to SharedSequenceApi/src/main/java/org/notests/sharedsequence/api/SharingTraits.kt diff --git a/SharedSequenceProcessor/build.gradle b/SharedSequenceProcessor/build.gradle index 5e4552c..48a8ddc 100644 --- a/SharedSequenceProcessor/build.gradle +++ b/SharedSequenceProcessor/build.gradle @@ -14,10 +14,6 @@ dependencies { sourceCompatibility = "1.7" targetCompatibility = "1.7" -sourceSets { - main.java.srcDirs += "src/main/kotlin" -} - buildscript { repositories { mavenCentral() diff --git a/SharedSequenceProcessor/src/main/kotlin/org/notests/sharedsequence/processor/SharedSequenceProcessor.kt b/SharedSequenceProcessor/src/main/java/org/notests/sharedsequence/processor/SharedSequenceProcessor.kt similarity index 100% rename from SharedSequenceProcessor/src/main/kotlin/org/notests/sharedsequence/processor/SharedSequenceProcessor.kt rename to SharedSequenceProcessor/src/main/java/org/notests/sharedsequence/processor/SharedSequenceProcessor.kt diff --git a/build.gradle b/build.gradle index ade7efd..524dd43 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:3.3.1' classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:' + versions.kotlin // NOTE: Do not place your application dependencies here; they belong diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index aac7c9b..0000000 --- a/gradle.properties +++ /dev/null @@ -1,17 +0,0 @@ -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx1536m - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5dcd22e..3111d8c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Nov 06 16:52:11 CET 2017 +#Sat Mar 23 22:22:11 CET 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip diff --git a/versions.gradle b/versions.gradle index 90a5375..f58fb77 100644 --- a/versions.gradle +++ b/versions.gradle @@ -5,9 +5,9 @@ ext.versions = [:] def versions = [:] -versions.rxjava2 = '2.2.0' -versions.rx_android = '2.0.2' -versions.kotlin = '1.2.51' +versions.rxjava2 = '2.2.7' +versions.rx_android = '2.1.1' +versions.kotlin = '1.3.21' versions.support = '26.1.0' versions.constraint_layout = '1.1.2' versions.rxbinding = '2.1.1'