blob: 3080cc2d4221a6643d7c99e9d956f9dd095dec84 [file]
/*
* Copyright 2015-2022 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v2.0 which
* accompanies this distribution and is available at
*
* https://www.eclipse.org/legal/epl-v20.html
*/
package org.junit.jupiter.api;
import static org.junit.jupiter.api.AssertLinesMatch.isFastForwardLine;
import static org.junit.jupiter.api.AssertLinesMatch.parseFastForwardLimit;
import static org.junit.jupiter.api.AssertionTestUtils.assertMessageEquals;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertLinesMatch;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.platform.commons.PreconditionViolationException;
import org.opentest4j.AssertionFailedError;
/**
* Unit tests for JUnit Jupiter {@link Assertions}.
*
* @since 5.0
*/
class AssertLinesMatchAssertionsTests {
@Test
void assertLinesMatchEmptyLists() {
assertLinesMatch(Collections.emptyList(), new ArrayList<>());
}
@Test
void assertLinesMatchSameListInstance() {
List<String> list = List.of("first line", "second line", "third line", "last line");
assertLinesMatch(list, list);
}
@Test
void assertLinesMatchPlainEqualLists() {
List<String> expected = List.of("first line", "second line", "third line", "last line");
List<String> actual = List.of("first line", "second line", "third line", "last line");
assertLinesMatch(expected, actual);
}
@Test
void assertLinesMatchUsingRegexPatterns() {
List<String> expected = List.of("^first.+line", "second\\s*line", "th.rd l.ne", "last line$");
List<String> actual = List.of("first line", "second line", "third line", "last line");
assertLinesMatch(expected, actual);
}
@Test
void assertLinesMatchUsingFastForwardMarkerAtEndOfExpectedLines() {
List<String> expected = List.of("first line", ">> ignore all following lines >>");
List<String> actual = List.of("first line", "I", "II", "III", "IV", "V", "VI", "last line");
assertLinesMatch(expected, actual);
}
@Test
void assertLinesMatchUsingFastForwardMarker() {
List<String> expected = List.of("first line", ">> skip lines until next matches >>", "V", "last line");
List<String> actual = List.of("first line", "I", "II", "III", "IV", "V", "last line");
assertLinesMatch(expected, actual);
}
@Test
void assertLinesMatchUsingFastForwardMarkerWithLimit1() {
List<String> expected = List.of("first line", ">> 1 >>", "last line");
List<String> actual = List.of("first line", "skipped", "last line");
assertLinesMatch(expected, actual);
}
@Test
void assertLinesMatchUsingFastForwardMarkerWithLimit3() {
List<String> expected = Collections.singletonList(">> 3 >>");
List<String> actual = List.of("first line", "skipped", "last line");
assertLinesMatch(expected, actual);
}
@Test
@SuppressWarnings({ "unchecked", "rawtypes" })
void assertLinesMatchWithNullFails() {
assertThrows(PreconditionViolationException.class, () -> assertLinesMatch((List) null, (List) null));
assertThrows(PreconditionViolationException.class, () -> assertLinesMatch(null, Collections.emptyList()));
assertThrows(PreconditionViolationException.class, () -> assertLinesMatch(Collections.emptyList(), null));
}
@Test
void assertLinesMatchWithNullElementsFails() {
var list = List.of("1", "2", "3");
var withNullElement = Arrays.asList("1", null, "3"); // List.of() doesn't permit null values.
assertDoesNotThrow(() -> assertLinesMatch(withNullElement, withNullElement));
var e1 = assertThrows(PreconditionViolationException.class, () -> assertLinesMatch(withNullElement, list));
assertEquals("expected line must not be null", e1.getMessage());
var e2 = assertThrows(PreconditionViolationException.class, () -> assertLinesMatch(list, withNullElement));
assertEquals("actual line must not be null", e2.getMessage());
}
private void assertError(AssertionFailedError error, String expectedMessage, List<String> expectedLines,
List<String> actualLines) {
assertEquals(expectedMessage, error.getMessage());
assertEquals(String.join(System.lineSeparator(), expectedLines), error.getExpected().getStringRepresentation());
assertEquals(String.join(System.lineSeparator(), actualLines), error.getActual().getStringRepresentation());
}
@Test
void assertLinesMatchMoreExpectedThanActualAvailableFails() {
var expected = List.of("first line", "second line", "third line");
var actual = List.of("first line", "third line");
var error = assertThrows(AssertionFailedError.class, () -> assertLinesMatch(expected, actual));
assertError(error, "expected 3 lines, but only got 2", expected, actual);
}
@Test
void assertLinesMatchFailsWithDescriptiveErrorMessage() {
var expected = List.of("first line", "second line", "third line");
var actual = List.of("first line", "sec0nd line", "third line");
var error = assertThrows(AssertionFailedError.class, () -> assertLinesMatch(expected, actual));
var expectedMessage = String.join(System.lineSeparator(), List.of( //
"expected line #2 doesn't match actual line #2", //
"\texpected: `second line`", //
"\t actual: `sec0nd line`"));
assertError(error, expectedMessage, expected, actual);
}
@Test
void assertLinesMatchMoreActualLinesThenExpectedFails() {
var expected = List.of("first line", "second line", "third line");
var actual = List.of("first line", "second line", "third line", "last line");
var error = assertThrows(AssertionFailedError.class, () -> assertLinesMatch(expected, actual));
assertError(error, "more actual lines than expected: 1", expected, actual);
}
@Test
void assertLinesMatchUsingFastForwardMarkerWithTooLowLimitFails() {
var expected = List.of("first line", ">> 1 >>");
var actual = List.of("first line", "skipped", "last line");
var error = assertThrows(AssertionFailedError.class, () -> assertLinesMatch(expected, actual));
assertError(error, "terminal fast-forward(1) error: fast-forward(2) expected", expected, actual);
}
@Test
void assertLinesMatchUsingFastForwardMarkerWithTooHighLimitFails() {
var expected = List.of("first line", ">> 100 >>");
var actual = List.of("first line", "skipped", "last line");
var error = assertThrows(AssertionFailedError.class, () -> assertLinesMatch(expected, actual));
assertError(error, "terminal fast-forward(100) error: fast-forward(2) expected", expected, actual);
}
@Test
void assertLinesMatchUsingFastForwardMarkerWithTooHighLimitAndFollowingLineFails() {
/*
* It is important here that the line counts are expected <= actual, that the
* fast-forward exceeds the available actual lines and that it is not a
* terminal fast-forward.
*/
var expected = List.of("first line", ">> 3 >>", "not present");
var actual = List.of("first line", "first skipped", "second skipped");
var error = assertThrows(AssertionFailedError.class, () -> assertLinesMatch(expected, actual));
assertError(error, "fast-forward(3) error: not enough actual lines remaining (2)", expected, actual);
}
@Test
void assertLinesMatchUsingFastForwardMarkerWithoutMatchingNextLineFails() {
var expected = List.of("first line", ">> fails, because next line is >>", "not present");
var actual = List.of("first line", "skipped", "last line");
var error = assertThrows(AssertionFailedError.class, () -> assertLinesMatch(expected, actual));
assertError(error, "fast-forward(∞) didn't find: `not present`", expected, actual);
}
@Test
void assertLinesMatchUsingFastForwardMarkerWithExtraExpectLineFails() {
var expected = List.of("first line", ">> fails, because final line is missing >>", "last line", "not present");
var actual = List.of("first line", "first skipped", "second skipped", "last line");
var error = assertThrows(AssertionFailedError.class, () -> assertLinesMatch(expected, actual));
assertError(error, "expected line #4:`not present` not found - actual lines depleted", expected, actual);
}
@Test
void assertLinesMatchIsFastForwardLine() {
assertAll("valid fast-forward lines", //
() -> assertTrue(isFastForwardLine(">>>>")), () -> assertTrue(isFastForwardLine(">> >>")),
() -> assertTrue(isFastForwardLine(">> stacktrace >>")),
() -> assertTrue(isFastForwardLine(">> single line, non Integer.parse()-able comment >>")),
() -> assertTrue(isFastForwardLine(">>9>>")), () -> assertTrue(isFastForwardLine(">> 9 >>")),
() -> assertTrue(isFastForwardLine(">> -9 >>")), () -> assertTrue(isFastForwardLine(" >> 9 >> ")),
() -> assertTrue(isFastForwardLine(" >> 9 >> ")));
}
@Test
void assertLinesMatchParseFastForwardLimit() {
assertAll("valid fast-forward limits", //
() -> assertEquals(Integer.MAX_VALUE, parseFastForwardLimit(">>>>")),
() -> assertEquals(Integer.MAX_VALUE, parseFastForwardLimit(">> >>")),
() -> assertEquals(Integer.MAX_VALUE, parseFastForwardLimit(">> stacktrace >>")),
() -> assertEquals(Integer.MAX_VALUE, parseFastForwardLimit(">> non Integer.parse()-able comment >>")),
() -> assertEquals(9, parseFastForwardLimit(">>9>>")),
() -> assertEquals(9, parseFastForwardLimit(">> 9 >>")),
() -> assertEquals(9, parseFastForwardLimit(" >> 9 >> ")),
() -> assertEquals(9, parseFastForwardLimit(" >> 9 >> ")));
Throwable error = assertThrows(PreconditionViolationException.class, () -> parseFastForwardLimit(">>0>>"));
assertMessageEquals(error, "fast-forward(0) limit must be greater than zero");
error = assertThrows(PreconditionViolationException.class, () -> parseFastForwardLimit(">>-1>>"));
assertMessageEquals(error, "fast-forward(-1) limit must be greater than zero");
error = assertThrows(PreconditionViolationException.class, () -> parseFastForwardLimit(">>-2147483648>>"));
assertMessageEquals(error, "fast-forward(-2147483648) limit must be greater than zero");
}
@Test
void assertLinesMatchMatches() {
Random random = new Random();
assertAll("do match", //
() -> assertTrue(
AssertLinesMatch.matches("duration: [\\d]+ ms", "duration: " + random.nextInt(1000) + " ms")),
() -> assertTrue(AssertLinesMatch.matches("123", "123")),
() -> assertTrue(AssertLinesMatch.matches(".*", "123")),
() -> assertTrue(AssertLinesMatch.matches("\\d+", "123")));
assertAll("don't match", //
() -> assertFalse(
AssertLinesMatch.matches("duration: [\\d]+ ms", "duration: " + random.nextGaussian() + " ms")),
() -> assertFalse(AssertLinesMatch.matches("12", "123")),
() -> assertFalse(AssertLinesMatch.matches("..+", "1")),
() -> assertFalse(AssertLinesMatch.matches("\\d\\d+", "1")));
}
@Test
void largeListsThatDoNotMatchAreTruncated() {
var expected = IntStream.range(1, 999).boxed().map(Object::toString).collect(Collectors.toList());
var actual = IntStream.range(0, 1000).boxed().map(Object::toString).collect(Collectors.toList());
var error = assertThrows(AssertionFailedError.class,
() -> assertLinesMatch(expected, actual, "custom message"));
var expectedMessage = String.join(System.lineSeparator(), List.of( //
"custom message ==> expected line #1 doesn't match actual line #1", //
"\texpected: `1`", //
"\t actual: `0`"));
assertError(error, expectedMessage, expected, actual);
}
/**
* @since 5.5
*/
@Nested
class WithCustomFailureMessage {
@Test
void simpleStringMessage() {
String message = "XXX";
var expected = List.of("a", "b", "c");
var actual = List.of("a", "d", "c");
var error = assertThrows(AssertionFailedError.class, () -> assertLinesMatch(expected, actual, message));
var expectedMessage = String.join(System.lineSeparator(), List.of( //
message + " ==> expected line #2 doesn't match actual line #2", //
"\texpected: `b`", //
"\t actual: `d`"));
assertError(error, expectedMessage, expected, actual);
}
@Test
void stringSupplierWithMultiLineMessage() {
var message = "XXX\nYYY";
Supplier<String> supplier = () -> message;
var expected = List.of("a", "b", "c");
var actual = List.of("a", "d", "c");
var error = assertThrows(AssertionFailedError.class, () -> assertLinesMatch(expected, actual, supplier));
var expectedMessage = String.join(System.lineSeparator(), List.of( //
message + " ==> expected line #2 doesn't match actual line #2", //
"\texpected: `b`", //
"\t actual: `d`"));
assertError(error, expectedMessage, expected, actual);
}
}
@Nested
class WithStreamsOfStrings {
@Test
void assertLinesMatchEmptyStreams() {
assertLinesMatch(Stream.empty(), Stream.empty());
}
@Test
void assertLinesMatchSameListInstance() {
Stream<String> stream = Stream.of("first line", "second line", "third line", "last line");
assertLinesMatch(stream, stream);
}
@Test
void assertLinesMatchPlainEqualLists() {
var expected = """
first line
second line
third line
last line
""";
var actual = """
first line
second line
third line
last line
""";
assertLinesMatch(expected.lines(), actual.lines());
}
@Test
void assertLinesMatchUsingRegexPatterns() {
var expected = """
^first.+line
second\\s*line
th.rd l.ne
last line$
""";
var actual = """
first line
second line
third line
last line
""";
assertLinesMatch(expected.lines(), actual.lines());
}
}
}