Skip to content

Commit

Permalink
TestScopeProvider + build fixes (#49)
Browse files Browse the repository at this point in the history
* Fix TestLifecycleScopeProvider compilation

This didn't compile before

* Fix test

* Fix formatting in TestLifecycleScopeProvider

* Add TestScopeProvider

* Add Tests for TestScopeProvider

* Remove object instantiation and just have a single emit()

* Remove emitError() APIs

* Remove emitComplete()

Also not really necessary
  • Loading branch information
ZacSweers committed Mar 13, 2017
1 parent 3e2c0c3 commit fa31acb
Show file tree
Hide file tree
Showing 4 changed files with 241 additions and 94 deletions.
Expand Up @@ -18,89 +18,89 @@

import io.reactivex.Observable;
import io.reactivex.annotations.NonNull;
import io.reactivex.annotations.Nullable;
import io.reactivex.functions.Function;
import io.reactivex.subjects.BehaviorSubject;

import static com.uber.autodispose.TestLifecycleScopeProvider.TestLifecycle.UNINITIALIZED;

/**
* Test utility to create {@link LifecycleScopeProvider} instances for tests.
*
* Supports a start and stop lifecycle. Subscribing when outside of the lifecycle will throw either a
* {@link LifecycleNotStartedException} or {@link LifecycleEndedException}.
* Supports a start and stop lifecycle. Subscribing when outside of the lifecycle will throw either
* a {@link LifecycleNotStartedException} or {@link LifecycleEndedException}.
* }
*/
public final class TestLifecycleScopeProvider
implements LifecycleScopeProvider<TestLifecycleScopeProvider.TestLifecycle> {

private final BehaviorSubject<TestLifecycle> lifecycleSubject = BehaviorSubject.createDefault();
implements LifecycleScopeProvider<TestLifecycleScopeProvider.TestLifecycle> {

private TestLifecycleScopeProvider() { }
private final BehaviorSubject<TestLifecycle> lifecycleSubject;

/**
* @return a new {@link TestLifecycleScopeProvider} instance.
*/
public static TestLifecycleScopeProvider create() {
return new TestLifecycleScopeProvider();
private TestLifecycleScopeProvider(@Nullable TestLifecycle initialValue) {
if (initialValue == null) {
lifecycleSubject = BehaviorSubject.create();
} else {
lifecycleSubject = BehaviorSubject.createDefault(initialValue);
}
}

/**
* @param initialValue the initial lifecycle event to create the {@link TestLifecycleScopeProvider} with.
* @return a new {@link TestLifecycleScopeProvider} instance with {@param initialValue} as its initial lifecycle
* event.
*/
public static TestLifecycleScopeProvider createInitial(TestLifecycle initialValue) {
TestLifecycleScopeProvider testLifecycleScopeProvider = new TestLifecycleScopeProvider();
testLifecycleScopeProvider.lifecycleSubject.onNext(initialValue);
return testLifecycleScopeProvider;
}
/**
* @return a new {@link TestLifecycleScopeProvider} instance.
*/
public static TestLifecycleScopeProvider create() {
return new TestLifecycleScopeProvider(null);
}

@Override
public Observable<TestLifecycle> lifecycle() {
return lifecycleSubject.hide();
}
/**
* @param initialValue the initial lifecycle event to create the {@link
* TestLifecycleScopeProvider} with.
* @return a new {@link TestLifecycleScopeProvider} instance with {@param initialValue} as its
* initial lifecycle
* event.
*/
public static TestLifecycleScopeProvider createInitial(TestLifecycle initialValue) {
return new TestLifecycleScopeProvider(initialValue);
}

@Override
public Function<TestLifecycle, TestLifecycle> correspondingEvents() {
return new Function<TestLifecycle, TestLifecycle>() {
@Override
public TestLifecycle apply(@NonNull TestLifecycle testLifecycle) {
switch (testLifecycle) {
case STARTED:
return TestLifecycle.STOPPED;
case STOPPED:
throw new LifecycleEndedException();
default:
throw new IllegalStateException("Unknown lifecycle event.");
}
}
};
}
@Override public Observable<TestLifecycle> lifecycle() {
return lifecycleSubject.hide();
}

@Override
public TestLifecycle peekLifecycle() {
return lifecycleSubject.getValue();
}
@Override public Function<TestLifecycle, TestLifecycle> correspondingEvents() {
return new Function<TestLifecycle, TestLifecycle>() {
@Override public TestLifecycle apply(@NonNull TestLifecycle testLifecycle) {
switch (testLifecycle) {
case STARTED:
return TestLifecycle.STOPPED;
case STOPPED:
throw new LifecycleEndedException();
default:
throw new IllegalStateException("Unknown lifecycle event.");
}
}
};
}

/**
* Start the test lifecycle.
*/
public void start() {
lifecycleSubject.onNext(TestLifecycle.STARTED);
}
@Override public TestLifecycle peekLifecycle() {
return lifecycleSubject.getValue();
}

/**
* Stop the test lifecycle.
*/
public void stop() {
if (lifecycleSubject.getValue() != TestLifecycle.STARTED) {
throw new IllegalStateException("Attempting to stop lifecycle before starting it.");
}
lifecycleSubject.onNext(TestLifecycle.STOPPED);
}
/**
* Start the test lifecycle.
*/
public void start() {
lifecycleSubject.onNext(TestLifecycle.STARTED);
}

public enum TestLifecycle {
STARTED,
STOPPED
/**
* Stop the test lifecycle.
*/
public void stop() {
if (lifecycleSubject.getValue() != TestLifecycle.STARTED) {
throw new IllegalStateException("Attempting to stop lifecycle before starting it.");
}
lifecycleSubject.onNext(TestLifecycle.STOPPED);
}

public enum TestLifecycle {
STARTED, STOPPED
}
}
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2017. Uber Technologies
*
* 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 com.uber.autodispose;

import io.reactivex.Maybe;
import io.reactivex.subjects.MaybeSubject;

import static com.uber.autodispose.ScopeUtil.LifecycleEndNotification.INSTANCE;

/**
* ScopeProvider implementation for testing. You can either back it with your own instance, or just
* stub it in place and use its public emit APIs.
*/
public final class TestScopeProvider implements ScopeProvider {

/**
* Creates a new provider backed by an internal MaybeSubject. Useful for stubbing or if you only
* want to use the emit APIs
*
* @return the created TestScopeProvider.
*/
public static TestScopeProvider create() {
return create(MaybeSubject.create());
}

/**
* Creates a new provider backed by {@code delegate}.
*
* @param delegate the delegate to back this with.
* @return the created TestScopeProvider.
*/
public static TestScopeProvider create(Maybe<?> delegate) {
return new TestScopeProvider(delegate);
}

private final MaybeSubject<Object> innerMaybe = MaybeSubject.create();

private TestScopeProvider(Maybe<?> delegate) {
delegate.subscribe(innerMaybe);
}

@Override public Maybe<?> requestScope() {
return innerMaybe;
}

/**
* Emits a success event, just a simple Object.
*/
public void emit() {
innerMaybe.onSuccess(INSTANCE);
}
}
Expand Up @@ -24,33 +24,38 @@

public class TestLifecycleScopeProviderTest {

private final TestLifecycleScopeProvider testLifecycleScopeProvider = TestLifecycleScopeProvider.create();

@Test(expected = LifecycleNotStartedException.class) public void create_shouldReturnInUninitializedState() throws Exception {
testLifecycleScopeProvider.correspondingEvents().apply(testLifecycleScopeProvider.peekLifecycle());
}

@Test public void createInitial_shouldUseInitialValuePassedIn() {
assertThat(TestLifecycleScopeProvider.createInitial(STARTED).peekLifecycle()).isEqualTo(STARTED);
}

@Test public void start_shouldTriggerStartEvent() throws Exception {
testLifecycleScopeProvider.start();

assertThat(testLifecycleScopeProvider.peekLifecycle()).isEqualTo(STARTED);
assertThat(testLifecycleScopeProvider.correspondingEvents().apply(testLifecycleScopeProvider.peekLifecycle()))
.isEqualTo(STOPPED);
}

@Test(expected = LifecycleEndedException.class) public void stop_afterStart_shouldTriggerStopEvent() throws Exception {
testLifecycleScopeProvider.start();
testLifecycleScopeProvider.stop();

assertThat(testLifecycleScopeProvider.peekLifecycle()).isEqualTo(STOPPED);
testLifecycleScopeProvider.correspondingEvents().apply(testLifecycleScopeProvider.peekLifecycle());
}

@Test(expected = IllegalStateException.class) public void stop_beforeStart_shouldThrowException() throws Exception {
testLifecycleScopeProvider.stop();
}
private final TestLifecycleScopeProvider testLifecycleScopeProvider =
TestLifecycleScopeProvider.create();

@Test public void create_noArgs_shouldHaveNoState() throws Exception {
assertThat(testLifecycleScopeProvider.peekLifecycle()).isNull();
}

@Test public void createInitial_shouldUseInitialValuePassedIn() {
assertThat(TestLifecycleScopeProvider.createInitial(STARTED)
.peekLifecycle()).isEqualTo(STARTED);
}

@Test public void start_shouldTriggerStartEvent() throws Exception {
testLifecycleScopeProvider.start();

assertThat(testLifecycleScopeProvider.peekLifecycle()).isEqualTo(STARTED);
assertThat(testLifecycleScopeProvider.correspondingEvents()
.apply(testLifecycleScopeProvider.peekLifecycle())).isEqualTo(STOPPED);
}

@Test(expected = LifecycleEndedException.class)
public void stop_afterStart_shouldTriggerStopEvent() throws Exception {
testLifecycleScopeProvider.start();
testLifecycleScopeProvider.stop();

assertThat(testLifecycleScopeProvider.peekLifecycle()).isEqualTo(STOPPED);
testLifecycleScopeProvider.correspondingEvents()
.apply(testLifecycleScopeProvider.peekLifecycle());
}

@Test(expected = IllegalStateException.class) public void stop_beforeStart_shouldThrowException()
throws Exception {
testLifecycleScopeProvider.stop();
}
}
@@ -0,0 +1,76 @@
/*
* Copyright (c) 2017. Uber Technologies
*
* 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 com.uber.autodispose;

import io.reactivex.observers.TestObserver;
import io.reactivex.subjects.MaybeSubject;
import org.junit.Test;

public class TestScopeProviderTest {

private final TestObserver<Object> o = new TestObserver<>();

@Test public void noArgs() {
TestScopeProvider provider = TestScopeProvider.create();
provider.requestScope()
.subscribe(o);

provider.emit();
o.assertValueCount(1);
}

@Test public void delegateArg() {
MaybeSubject<Integer> s = MaybeSubject.create();
TestScopeProvider provider = TestScopeProvider.create(s);
provider.requestScope()
.subscribe(o);

provider.emit();
o.assertValueCount(1);
}

@Test public void delegateArgEmits() {
MaybeSubject<Integer> s = MaybeSubject.create();
TestScopeProvider provider = TestScopeProvider.create(s);
provider.requestScope()
.subscribe(o);

s.onSuccess(1);
o.assertValueCount(1);
o.assertValue(1);
}

@Test public void delegateArg_error() {
MaybeSubject<Integer> s = MaybeSubject.create();
TestScopeProvider provider = TestScopeProvider.create(s);
provider.requestScope()
.subscribe(o);

s.onError(new IllegalArgumentException());
o.assertError(IllegalArgumentException.class);
}

@Test public void delegateArg_complete() {
MaybeSubject<Integer> s = MaybeSubject.create();
TestScopeProvider provider = TestScopeProvider.create(s);
provider.requestScope()
.subscribe(o);

s.onComplete();
o.assertComplete();
}
}

0 comments on commit fa31acb

Please sign in to comment.