Skip to content

Commit 7e7b223

Browse files
authored
3.x: Improve error messages in the test consumers (#7126)
* 3.x: Improve error reporting in the test consumers * Verify assertValueAt with negative index
1 parent 67c1a36 commit 7e7b223

File tree

3 files changed

+112
-27
lines changed

3 files changed

+112
-27
lines changed

src/main/java/io/reactivex/rxjava3/observers/BaseTestConsumer.java

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ public final U assertNoErrors() {
228228
*/
229229
@NonNull
230230
public final U assertError(@NonNull Throwable error) {
231-
return assertError(Functions.equalsWith(error));
231+
return assertError(Functions.equalsWith(error), true);
232232
}
233233

234234
/**
@@ -240,7 +240,7 @@ public final U assertError(@NonNull Throwable error) {
240240
@SuppressWarnings({ "unchecked", "rawtypes" })
241241
@NonNull
242242
public final U assertError(@NonNull Class<? extends Throwable> errorClass) {
243-
return (U)assertError((Predicate)Functions.isInstanceOf(errorClass));
243+
return (U)assertError((Predicate)Functions.isInstanceOf(errorClass), true);
244244
}
245245

246246
/**
@@ -251,9 +251,14 @@ public final U assertError(@NonNull Class<? extends Throwable> errorClass) {
251251
* and should return {@code true} for expected errors.
252252
* @return this
253253
*/
254-
@SuppressWarnings("unchecked")
255254
@NonNull
256255
public final U assertError(@NonNull Predicate<Throwable> errorPredicate) {
256+
return assertError(errorPredicate, false);
257+
}
258+
259+
@SuppressWarnings("unchecked")
260+
@NonNull
261+
private U assertError(@NonNull Predicate<Throwable> errorPredicate, boolean exact) {
257262
int s = errors.size();
258263
if (s == 0) {
259264
throw fail("No errors");
@@ -274,10 +279,16 @@ public final U assertError(@NonNull Predicate<Throwable> errorPredicate) {
274279

275280
if (found) {
276281
if (s != 1) {
277-
throw fail("Error present but other errors as well");
282+
if (exact) {
283+
throw fail("Error present but other errors as well");
284+
}
285+
throw fail("One error passed the predicate but other errors are present as well");
278286
}
279287
} else {
280-
throw fail("Error not present");
288+
if (exact) {
289+
throw fail("Error not present");
290+
}
291+
throw fail("No error(s) passed the predicate");
281292
}
282293
return (U)this;
283294
}
@@ -316,7 +327,7 @@ public final U assertValue(@NonNull Predicate<T> valuePredicate) {
316327
assertValueAt(0, valuePredicate);
317328

318329
if (values.size() > 1) {
319-
throw fail("Value present but other values as well");
330+
throw fail("The first value passed the predicate but this consumer received more than one value");
320331
}
321332

322333
return (U)this;
@@ -339,13 +350,13 @@ public final U assertValueAt(int index, @NonNull T value) {
339350
throw fail("No values");
340351
}
341352

342-
if (index >= s) {
343-
throw fail("Invalid index: " + index);
353+
if (index < 0 || index >= s) {
354+
throw fail("Index " + index + " is out of range [0, " + s + ")");
344355
}
345356

346357
T v = values.get(index);
347358
if (!Objects.equals(value, v)) {
348-
throw fail("expected: " + valueAndClass(value) + " but was: " + valueAndClass(v));
359+
throw fail("expected: " + valueAndClass(value) + " but was: " + valueAndClass(v) + " at position " + index);
349360
}
350361
return (U)this;
351362
}
@@ -367,22 +378,23 @@ public final U assertValueAt(int index, @NonNull Predicate<T> valuePredicate) {
367378
throw fail("No values");
368379
}
369380

370-
if (index >= values.size()) {
371-
throw fail("Invalid index: " + index);
381+
if (index < 0 || index >= s) {
382+
throw fail("Index " + index + " is out of range [0, " + s + ")");
372383
}
373384

374385
boolean found = false;
375386

387+
T v = values.get(index);
376388
try {
377-
if (valuePredicate.test(values.get(index))) {
389+
if (valuePredicate.test(v)) {
378390
found = true;
379391
}
380392
} catch (Throwable ex) {
381393
throw ExceptionHelper.wrapOrThrow(ex);
382394
}
383395

384396
if (!found) {
385-
throw fail("Value not present");
397+
throw fail("Value " + valueAndClass(v) + " at position " + index + " did not pass the predicate");
386398
}
387399
return (U)this;
388400
}

src/test/java/io/reactivex/rxjava3/observers/TestObserverTest.java

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.concurrent.TimeUnit;
2222

2323
import org.junit.Test;
24+
import org.junit.function.ThrowingRunnable;
2425
import org.mockito.InOrder;
2526
import org.reactivestreams.Subscriber;
2627

@@ -39,6 +40,10 @@
3940

4041
public class TestObserverTest extends RxJavaTest {
4142

43+
static void assertThrowsWithMessage(String message, Class<? extends Throwable> clazz, ThrowingRunnable run) {
44+
assertEquals(message, assertThrows(clazz, run).getMessage());
45+
}
46+
4247
@Test
4348
public void assertTestObserver() {
4449
Flowable<Integer> oi = Flowable.fromIterable(Arrays.asList(1, 2));
@@ -843,7 +848,7 @@ public void errorMeansDisposed() {
843848

844849
@Test
845850
public void assertValuePredicateEmpty() {
846-
assertThrows("No values", AssertionError.class, () -> {
851+
assertThrowsWithMessage("No values (latch = 0, values = 0, errors = 0, completions = 1)", AssertionError.class, () -> {
847852
TestObserver<Object> to = new TestObserver<>();
848853

849854
Observable.empty().subscribe(to);
@@ -871,7 +876,7 @@ public void assertValuePredicateMatch() {
871876

872877
@Test
873878
public void assertValuePredicateNoMatch() {
874-
assertThrows("Value not present", AssertionError.class, () -> {
879+
assertThrowsWithMessage("Value 1 (class: Integer) at position 0 did not pass the predicate (latch = 0, values = 1, errors = 0, completions = 1)", AssertionError.class, () -> {
875880
TestObserver<Integer> to = new TestObserver<>();
876881

877882
Observable.just(1).subscribe(to);
@@ -886,7 +891,7 @@ public void assertValuePredicateNoMatch() {
886891

887892
@Test
888893
public void assertValuePredicateMatchButMore() {
889-
assertThrows("Value present but other values as well", AssertionError.class, () -> {
894+
assertThrowsWithMessage("The first value passed the predicate but this consumer received more than one value (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> {
890895
TestObserver<Integer> to = new TestObserver<>();
891896

892897
Observable.just(1, 2).subscribe(to);
@@ -901,7 +906,7 @@ public void assertValuePredicateMatchButMore() {
901906

902907
@Test
903908
public void assertValueAtPredicateEmpty() {
904-
assertThrows("No values", AssertionError.class, () -> {
909+
assertThrowsWithMessage("No values (latch = 0, values = 0, errors = 0, completions = 1)", AssertionError.class, () -> {
905910
TestObserver<Object> to = new TestObserver<>();
906911

907912
Observable.empty().subscribe(to);
@@ -929,7 +934,7 @@ public void assertValueAtPredicateMatch() {
929934

930935
@Test
931936
public void assertValueAtPredicateNoMatch() {
932-
assertThrows("Value not present", AssertionError.class, () -> {
937+
assertThrowsWithMessage("Value 3 (class: Integer) at position 2 did not pass the predicate (latch = 0, values = 3, errors = 0, completions = 1)", AssertionError.class, () -> {
933938
TestObserver<Integer> to = new TestObserver<>();
934939

935940
Observable.just(1, 2, 3).subscribe(to);
@@ -944,7 +949,7 @@ public void assertValueAtPredicateNoMatch() {
944949

945950
@Test
946951
public void assertValueAtInvalidIndex() {
947-
assertThrows("Invalid index: 2 (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> {
952+
assertThrowsWithMessage("Index 2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> {
948953
TestObserver<Integer> to = new TestObserver<>();
949954

950955
Observable.just(1, 2).subscribe(to);
@@ -957,9 +962,24 @@ public void assertValueAtInvalidIndex() {
957962
});
958963
}
959964

965+
@Test
966+
public void assertValueAtInvalidIndexNegative() {
967+
assertThrowsWithMessage("Index -2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> {
968+
TestObserver<Integer> to = new TestObserver<>();
969+
970+
Observable.just(1, 2).subscribe(to);
971+
972+
to.assertValueAt(-2, new Predicate<Integer>() {
973+
@Override public boolean test(final Integer o) throws Exception {
974+
return o == 1;
975+
}
976+
});
977+
});
978+
}
979+
960980
@Test
961981
public void assertValueAtIndexEmpty() {
962-
assertThrows("No values", AssertionError.class, () -> {
982+
assertThrowsWithMessage("No values (latch = 0, values = 0, errors = 0, completions = 1)", AssertionError.class, () -> {
963983
TestObserver<Object> to = new TestObserver<>();
964984

965985
Observable.empty().subscribe(to);
@@ -979,7 +999,7 @@ public void assertValueAtIndexMatch() {
979999

9801000
@Test
9811001
public void assertValueAtIndexNoMatch() {
982-
assertThrows("expected: b (class: String) but was: c (class: String) (latch = 0, values = 3, errors = 0, completions = 1)", AssertionError.class, () -> {
1002+
assertThrowsWithMessage("expected: b (class: String) but was: c (class: String) at position 2 (latch = 0, values = 3, errors = 0, completions = 1)", AssertionError.class, () -> {
9831003
TestObserver<String> to = new TestObserver<>();
9841004

9851005
Observable.just("a", "b", "c").subscribe(to);
@@ -990,7 +1010,7 @@ public void assertValueAtIndexNoMatch() {
9901010

9911011
@Test
9921012
public void assertValueAtIndexInvalidIndex() {
993-
assertThrows("Invalid index: 2 (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> {
1013+
assertThrowsWithMessage("Index 2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> {
9941014
TestObserver<String> to = new TestObserver<>();
9951015

9961016
Observable.just("a", "b").subscribe(to);
@@ -999,6 +1019,17 @@ public void assertValueAtIndexInvalidIndex() {
9991019
});
10001020
}
10011021

1022+
@Test
1023+
public void assertValueAtIndexInvalidIndexNegative() {
1024+
assertThrowsWithMessage("Index -2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> {
1025+
TestObserver<String> to = new TestObserver<>();
1026+
1027+
Observable.just("a", "b").subscribe(to);
1028+
1029+
to.assertValueAt(-2, "c");
1030+
});
1031+
}
1032+
10021033
@Test
10031034
public void withTag() {
10041035
try {

src/test/java/io/reactivex/rxjava3/subscribers/TestSubscriberTest.java

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.concurrent.atomic.AtomicBoolean;
2323

2424
import org.junit.Test;
25+
import org.junit.function.ThrowingRunnable;
2526
import org.mockito.InOrder;
2627
import org.reactivestreams.*;
2728

@@ -1391,9 +1392,13 @@ public void assertValuePredicateMatch() {
13911392
});
13921393
}
13931394

1395+
static void assertThrowsWithMessage(String message, Class<? extends Throwable> clazz, ThrowingRunnable run) {
1396+
assertEquals(message, assertThrows(clazz, run).getMessage());
1397+
}
1398+
13941399
@Test
13951400
public void assertValuePredicateNoMatch() {
1396-
assertThrows("Value not present", AssertionError.class, () -> {
1401+
assertThrowsWithMessage("Value 1 (class: Integer) at position 0 did not pass the predicate (latch = 0, values = 1, errors = 0, completions = 1)", AssertionError.class, () -> {
13971402
TestSubscriber<Integer> ts = new TestSubscriber<>();
13981403

13991404
Flowable.just(1).subscribe(ts);
@@ -1408,7 +1413,7 @@ public void assertValuePredicateNoMatch() {
14081413

14091414
@Test
14101415
public void assertValuePredicateMatchButMore() {
1411-
assertThrows("Value present but other values as well", AssertionError.class, () -> {
1416+
assertThrowsWithMessage("The first value passed the predicate but this consumer received more than one value (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> {
14121417
TestSubscriber<Integer> ts = new TestSubscriber<>();
14131418

14141419
Flowable.just(1, 2).subscribe(ts);
@@ -1423,7 +1428,7 @@ public void assertValuePredicateMatchButMore() {
14231428

14241429
@Test
14251430
public void assertValueAtPredicateEmpty() {
1426-
assertThrows("No values", AssertionError.class, () -> {
1431+
assertThrowsWithMessage("No values (latch = 0, values = 0, errors = 0, completions = 1)", AssertionError.class, () -> {
14271432
TestSubscriber<Object> ts = new TestSubscriber<>();
14281433

14291434
Flowable.empty().subscribe(ts);
@@ -1451,7 +1456,7 @@ public void assertValueAtPredicateMatch() {
14511456

14521457
@Test
14531458
public void assertValueAtPredicateNoMatch() {
1454-
assertThrows("Value not present", AssertionError.class, () -> {
1459+
assertThrowsWithMessage("Value 3 (class: Integer) at position 2 did not pass the predicate (latch = 0, values = 3, errors = 0, completions = 1)", AssertionError.class, () -> {
14551460
TestSubscriber<Integer> ts = new TestSubscriber<>();
14561461

14571462
Flowable.just(1, 2, 3).subscribe(ts);
@@ -1466,7 +1471,7 @@ public void assertValueAtPredicateNoMatch() {
14661471

14671472
@Test
14681473
public void assertValueAtInvalidIndex() {
1469-
assertThrows("Invalid index: 2 (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> {
1474+
assertThrowsWithMessage("Index 2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> {
14701475
TestSubscriber<Integer> ts = new TestSubscriber<>();
14711476

14721477
Flowable.just(1, 2).subscribe(ts);
@@ -1479,6 +1484,43 @@ public void assertValueAtInvalidIndex() {
14791484
});
14801485
}
14811486

1487+
@Test
1488+
public void assertValueAtIndexInvalidIndex() {
1489+
assertThrowsWithMessage("Index 2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> {
1490+
TestSubscriber<Integer> ts = new TestSubscriber<>();
1491+
1492+
Flowable.just(1, 2).subscribe(ts);
1493+
1494+
ts.assertValueAt(2, 3);
1495+
});
1496+
}
1497+
1498+
@Test
1499+
public void assertValueAtIndexInvalidIndexNegative() {
1500+
assertThrowsWithMessage("Index -2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> {
1501+
TestSubscriber<Integer> ts = new TestSubscriber<>();
1502+
1503+
Flowable.just(1, 2).subscribe(ts);
1504+
1505+
ts.assertValueAt(-2, 3);
1506+
});
1507+
}
1508+
1509+
@Test
1510+
public void assertValueAtInvalidIndexNegative() {
1511+
assertThrowsWithMessage("Index -2 is out of range [0, 2) (latch = 0, values = 2, errors = 0, completions = 1)", AssertionError.class, () -> {
1512+
TestSubscriber<Integer> ts = new TestSubscriber<>();
1513+
1514+
Flowable.just(1, 2).subscribe(ts);
1515+
1516+
ts.assertValueAt(-2, new Predicate<Integer>() {
1517+
@Override public boolean test(final Integer o) throws Exception {
1518+
return o == 1;
1519+
}
1520+
});
1521+
});
1522+
}
1523+
14821524
@Test
14831525
public void requestMore() {
14841526
Flowable.range(1, 5)

0 commit comments

Comments
 (0)