Only build OutputCapture strings when necessary

Update `OutputCapture` so that expensive build operations are only
performed when necessary. This update is especially important for Kotlin
users calling `"Expected String" in output` since this results in a call
to Kotlin's `CharSequence.contains` which calls the `length()` and
`charAt()` methods many times.

Closes gh-32033
This commit is contained in:
Phillip Webb
2022-10-03 16:55:44 -07:00
parent 75f4d9e3fd
commit e917bd0ed0
2 changed files with 100 additions and 25 deletions

View File

@@ -19,6 +19,7 @@ package org.springframework.boot.test.system;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.NoSuchElementException;
import java.util.function.Predicate;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
@@ -42,7 +43,7 @@ class OutputCaptureTests {
private TestPrintStream systemErr;
private OutputCapture output = new OutputCapture();
private TestOutputCapture output = new TestOutputCapture();
@BeforeEach
void replaceSystemStreams() {
@@ -129,38 +130,69 @@ class OutputCaptureTests {
@Test
void getAllReturnsAllCapturedOutput() {
this.output.push();
System.out.print("A");
System.err.print("B");
System.out.print("C");
pushAndPrint();
assertThat(this.output.getAll()).isEqualTo("ABC");
}
@Test
void toStringReturnsAllCapturedOutput() {
this.output.push();
System.out.print("A");
System.err.print("B");
System.out.print("C");
pushAndPrint();
assertThat(this.output.toString()).isEqualTo("ABC");
}
@Test
void getErrReturnsOnlyCapturedErrOutput() {
this.output.push();
System.out.print("A");
System.err.print("B");
System.out.print("C");
pushAndPrint();
assertThat(this.output.getErr()).isEqualTo("B");
}
@Test
void getOutReturnsOnlyCapturedOutOutput() {
pushAndPrint();
assertThat(this.output.getOut()).isEqualTo("AC");
}
@Test
void getAllUsesCache() {
pushAndPrint();
for (int i = 0; i < 10; i++) {
assertThat(this.output.getAll()).isEqualTo("ABC");
}
assertThat(this.output.buildCount).isEqualTo(1);
System.out.print("X");
assertThat(this.output.getAll()).isEqualTo("ABCX");
assertThat(this.output.buildCount).isEqualTo(2);
}
@Test
void getOutUsesCache() {
pushAndPrint();
for (int i = 0; i < 10; i++) {
assertThat(this.output.getOut()).isEqualTo("AC");
}
assertThat(this.output.buildCount).isEqualTo(1);
System.out.print("X");
assertThat(this.output.getOut()).isEqualTo("ACX");
assertThat(this.output.buildCount).isEqualTo(2);
}
@Test
void getErrUsesCache() {
pushAndPrint();
for (int i = 0; i < 10; i++) {
assertThat(this.output.getErr()).isEqualTo("B");
}
assertThat(this.output.buildCount).isEqualTo(1);
System.err.print("X");
assertThat(this.output.getErr()).isEqualTo("BX");
assertThat(this.output.buildCount).isEqualTo(2);
}
private void pushAndPrint() {
this.output.push();
System.out.print("A");
System.err.print("B");
System.out.print("C");
assertThat(this.output.getOut()).isEqualTo("AC");
}
static class TestPrintStream extends PrintStream {
@@ -176,4 +208,16 @@ class OutputCaptureTests {
}
static class TestOutputCapture extends OutputCapture {
int buildCount;
@Override
String build(Predicate<Type> filter) {
this.buildCount++;
return super.build(filter);
}
}
}