package com.github.davidmoten.rx.internal.operators; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; import com.github.davidmoten.rx.Actions; import com.github.davidmoten.rx.Functions; import com.github.davidmoten.rx.Obs; import com.github.davidmoten.rx.Transformers; import com.github.davidmoten.rx.testing.TestSubscriber2; import com.github.davidmoten.rx.testing.TestingHelper; import rx.Observable; import rx.Subscriber; import rx.functions.Func1; import rx.functions.Func2; import rx.schedulers.Schedulers; public class OnSubscribeMatchTest { @Test public void test() { Observable<Integer> a = Observable.just(1, 2); Observable<Integer> b = Observable.just(2, 1); match(a, b, 2, 1); } @Test public void testAsynchronous() { Observable<Integer> a = Observable.just(1, 2).subscribeOn(Schedulers.computation()); Observable<Integer> b = Observable.just(2, 1); match(a, b) // .awaitTerminalEvent(5, TimeUnit.SECONDS) // .assertCompleted().assertValuesSet(1, 2); } @Test public void testKeepsRequesting() { Observable<Integer> a = Observable.just(1); Observable<Integer> b = Observable.just(2).repeat(1000).concatWith(Observable.just(1)); match(a, b, 1); } @Test public void testKeepsRequestingSwitched() { Observable<Integer> a = Observable.just(2).repeat(1000).concatWith(Observable.just(1)); Observable<Integer> b = Observable.just(1); match(a, b, 1); } @Test public void test2() { Observable<Integer> a = Observable.just(1, 2); Observable<Integer> b = Observable.just(1, 2); match(a, b, 1, 2); } @Test public void test3() { Observable<Integer> a = Observable.just(1, 2, 3); Observable<Integer> b = Observable.just(3, 2, 1); match(a, b, 3, 2, 1); } @Test public void testOneMatch() { Observable<Integer> a = Observable.just(1); Observable<Integer> b = Observable.just(1); match(a, b, 1); } @Test public void testEmpties() { Observable<Integer> a = Observable.empty(); Observable<Integer> b = Observable.empty(); match(a, b); } @Test public void testRepeats() { Observable<Integer> a = Observable.just(1, 1); Observable<Integer> b = Observable.just(1, 1); match(a, b, 1, 1); } @Test public void testRepeats2() { Observable<Integer> a = Observable.just(1, 1, 2, 3, 1); Observable<Integer> b = Observable.just(1, 2, 1, 3, 1); match(a, b, 1, 2, 1, 3, 1); } @Test public void testNoMatchExistsForAtLeastOneFirstLonger() { Observable<Integer> a = Observable.just(1, 2); Observable<Integer> b = Observable.just(1); match(a, b, 1); } @Test public void testNoMatchExistsForAtLeastOneFirstLongerSwitched() { Observable<Integer> a = Observable.just(1); Observable<Integer> b = Observable.just(1, 2); match(a, b, 1); } @Test public void testNoMatchExistsForAtLeastOneSameLength() { Observable<Integer> a = Observable.just(1, 2); Observable<Integer> b = Observable.just(1, 3); match(a, b, 1); } @Test public void testNoMatchExistsForAtLeastOneSecondLonger() { Observable<Integer> a = Observable.just(1); Observable<Integer> b = Observable.just(1, 2); match(a, b, 1); } @Test public void testNoMatchExistsAtAll() { Observable<Integer> a = Observable.just(1, 2); Observable<Integer> b = Observable.just(3, 4); match(a, b, new Integer[] {}); } @Test public void testBackpressure1() { Observable<Integer> a = Observable.just(1, 2, 5, 7, 6, 8); Observable<Integer> b = Observable.just(3, 4, 5, 6, 7); matchThem(a, b) // .to(TestingHelper.<Integer> testWithRequest(0)) // .assertNoValues()// .assertNoTerminalEvent()// .requestMore(1)// .assertValuesAndClear(5)// .assertNoTerminalEvent()// .requestMore(1)// .assertValuesAndClear(6)// .assertNoTerminalEvent()// .requestMore(1)// .assertValuesAndClear(7)// .requestMore(1) // .assertNoValues().assertCompleted(); } @Test public void testUnsubscribe() { AtomicBoolean unsubA = new AtomicBoolean(false); AtomicBoolean unsubB = new AtomicBoolean(false); Observable<Integer> a = Observable.just(1, 2, 5, 7, 6, 8) .doOnUnsubscribe(Actions.setToTrue0(unsubA)); Observable<Integer> b = Observable.just(3, 4, 5, 6, 7) .doOnUnsubscribe(Actions.setToTrue0(unsubB)); final List<Integer> list = new ArrayList<Integer>(); final AtomicBoolean terminal = new AtomicBoolean(); matchThem(a, b).subscribe(new Subscriber<Integer>() { @Override public void onCompleted() { terminal.set(true); } @Override public void onError(Throwable e) { terminal.set(true); } @Override public void onNext(Integer t) { list.add(t); unsubscribe(); } }); assertFalse(terminal.get()); assertEquals(Arrays.asList(5), list); assertTrue(unsubA.get()); assertTrue(unsubB.get()); } @Test public void testError() { RuntimeException e = new RuntimeException(); Observable<Integer> a = Observable.just(1, 2).concatWith(Observable.<Integer> error(e)); Observable<Integer> b = Observable.just(1, 2, 3); match(a, b).assertNoValues().assertError(e); } @Test public void testKeyFunctionAThrowsResultsInErrorEmission() { Observable<Integer> a = Observable.just(1); Observable<Integer> b = Observable.just(1); Obs.match(a, b, Functions.throwing(), Functions.identity(), COMBINER) .to(TestingHelper.<Integer> test()).assertNoValues() .assertError(Functions.ThrowingException.class); } @Test public void testKeyFunctionBThrowsResultsInErrorEmission() { Observable<Integer> a = Observable.just(1); Observable<Integer> b = Observable.just(1); Obs.match(a, b, Functions.identity(), Functions.throwing(), COMBINER) .to(TestingHelper.<Integer> test()) // .assertNoValues() // .assertError(Functions.ThrowingException.class); } @Test public void testCombinerFunctionBThrowsResultsInErrorEmission() { Observable<Integer> a = Observable.just(1, 2); Observable<Integer> b = Observable.just(2, 1); Obs.match(a, b, Functions.identity(), Functions.identity(), Functions.<Integer, Integer, Integer> throwing2()) .to(TestingHelper.<Integer> test()) // .assertNoValues() // .assertError(Functions.ThrowingException.class); } @Test public void testHandlesNulls() { Observable<Integer> a = Observable.just(null, null); Observable<Integer> b = Observable.just(null, null); Obs.match(a, b, Functions.constant(1), Functions.constant(1), COMBINER) .to(TestingHelper.<Integer> test()) // .assertValues(null, null) // .assertCompleted(); } @Test public void testCombinerFunctionBThrowsResultsInErrorEmissionSwitched() { Observable<Integer> a = Observable.just(2, 1); Observable<Integer> b = Observable.just(1, 2); Obs.match(a, b, Functions.identity(), Functions.identity(), Functions.<Integer, Integer, Integer> throwing2()) .to(TestingHelper.<Integer> test()).assertNoValues() .assertError(Functions.ThrowingException.class); } @Test(timeout = 5000) public void testOneDoesNotCompleteAndOtherMatchedAllShouldFinish() { Observable<Integer> a = Observable.just(1, 2).concatWith(Observable.<Integer> never()); Observable<Integer> b = Observable.just(1, 2); match(a, b).assertValues(1, 2).assertCompleted(); } @Test(timeout = 5000) public void testOneDoesNotCompleteAndOtherMatchedAllShouldFinishSwitched() { Observable<Integer> a = Observable.just(1, 2); Observable<Integer> b = Observable.just(1, 2).concatWith(Observable.<Integer> never()); match(a, b).assertValues(1, 2).assertCompleted(); } @Test public void testOneDoesNotCompleteAndOtherMatchedAllShouldFinishSwitched2() { Observable<Integer> a = Observable.just(1, 2); Observable<Integer> b = Observable.just(1, 3).concatWith(Observable.<Integer> never()); match(a, b).assertValues(1).assertNoTerminalEvent(); } @Test public void testLongReversed() { for (int n = 1; n < 1000; n++) { final int N = n; Observable<Integer> a = Observable.range(1, n).map(new Func1<Integer, Integer>() { @Override public Integer call(Integer x) { return N + 1 - x; } }); Observable<Integer> b = Observable.range(1, n); boolean equals = Observable .sequenceEqual(matchThem(a, b).sorted(), Observable.range(1, n)).toBlocking() .single(); assertTrue(equals); } } @Test public void testLongShifted() { for (int n = 1; n < 1000; n++) { testShifted(n, false); } } @Test public void testVeryLongShifted() { testShifted(1000000, false); } @Test public void testVeryLongShiftedAsync() { testShifted(1000000, true); } @Test(expected = IllegalArgumentException.class) public void testNegativeArgumentThrowsIAE() { Observable<Integer> a = Observable.just(1); Observable<Integer> b = Observable.just(1); Obs.match(a, b, Functions.identity(), Functions.identity(), COMBINER, -1); } private void testShifted(int n, boolean async) { Observable<Integer> a = Observable.just(0).concatWith(Observable.range(1, n)); if (async) { a = a.subscribeOn(Schedulers.computation()); } Observable<Integer> b = Observable.range(1, n); assertTrue(Observable.sequenceEqual(matchThem(a, b), Observable.range(1, n)).toBlocking() .single()); } private static Observable<Integer> matchThem(Observable<Integer> a, Observable<Integer> b) { return a.compose( Transformers.matchWith(b, Functions.identity(), Functions.identity(), COMBINER)); } private static void match(Observable<Integer> a, Observable<Integer> b, Integer... expected) { List<Integer> list = Arrays.asList(expected); TestSubscriber2<Integer> ts = match(a, b).assertCompleted(); assertEquals(list, ts.getOnNextEvents()); } private static TestSubscriber2<Integer> match(Observable<Integer> a, Observable<Integer> b) { return matchThem(a, b).to(TestingHelper.<Integer> test()); } private static final Func2<Integer, Integer, Integer> COMBINER = new Func2<Integer, Integer, Integer>() { @Override public Integer call(Integer x, Integer y) { return x; } }; }