Skip to content

Commit

Permalink
Disable muting for failing tests only. Fixes #22.
Browse files Browse the repository at this point in the history
In case of a failed test it is sometimes helpful to see the output to
{@code System.err} and {@code System.out}. Therefore
{@code SystemErrRule} and {@code SystemOutRule} have a new method
{@code muteForSuccessfulTests().

    @rule
    public final SystemErrRule systemErrRule
            = new SystemErrRule().muteForSuccessfulTests();
    @rule
    public final SystemOutRule systemOutRule
            = new SystemOutRule().muteForSuccessfulTests();
  • Loading branch information
stefanbirkner committed May 18, 2015
1 parent 4c5cd67 commit e6d3ae8
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,27 @@
* }
* </pre>
*
* <p>In case of a failed test it is sometimes helpful to see the output. This
* is when the method {@link #muteForSuccessfulTests()} comes into play.
*
* <pre>
* public class SystemErrTest {
* &#064;Rule
* public final SystemErrRule systemErrRule = new SystemErrRule().muteForSuccessfulTests();
*
* &#064;Test
* public void testWithSuppressedOutput() {
* System.err.print("some text");
* }
*
* &#064;Test
* public void testWithNormalOutput() {
* System.err.print("some text");
* fail();
* }
* }
* </pre>
*
* <h2>Combine Logging and Muting</h2>
*
* <p>Logging and muting can be combined. No output is actually written to
Expand Down Expand Up @@ -141,6 +162,17 @@ public SystemErrRule mute() {
return this;
}

/**
* Suppress the output to {@code System.err} for successful tests only.
* The output is still written to {@code System.err} for failing tests.
*
* @return the rule itself.
*/
public SystemErrRule muteForSuccessfulTests() {
printStreamRule.muteForSuccessfulTests();
return this;
}

/**
* Clears the current log.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,28 @@
* }
* </pre>
*
* <p>You don't have to enable logging for every test. It can be enabled for
* specific tests only.
*
* <pre>
* public class SystemOutTest {
* &#064;Rule
* public final SystemOutRule systemOutRule = new SystemOutRule();
*
* &#064;Test
* public void testWithLogging() {
* systemOutRule.enableLog()
* System.out.print("some text");
* assertEquals("some text", systemOutRule.getLog());
* }
*
* &#064;Test
* public void testWithoutLogging() {
* System.out.print("some text");
* }
* }
* </pre>
*
* <h2>Combine Logging and Muting</h2>
*
* <p>Logging and muting can be combined. No output is actually written to
Expand Down Expand Up @@ -141,6 +163,17 @@ public SystemOutRule mute() {
return this;
}

/**
* Suppress the output to {@code System.out} for successful tests only.
* The output is still written to {@code System.out} for failing tests.
*
* @return the rule itself.
*/
public SystemOutRule muteForSuccessfulTests() {
printStreamRule.muteForSuccessfulTests();
return this;
}

/**
* Clears the current log.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,28 @@ public PrintStreamRule(PrintStreamHandler printStreamHandler) {
}
}

public void enableLog() {
muteableLogStream.enableLog();
}

public Statement apply(final Statement base, final Description description) {
return printStreamHandler.createRestoreStatement(new Statement() {
return new Statement() {
@Override
public void evaluate() throws Throwable {
printStreamHandler.replaceCurrentStreamWithStream(muteableLogStream);
base.evaluate();
try {
printStreamHandler.createRestoreStatement(new Statement() {
@Override
public void evaluate() throws Throwable {
printStreamHandler.replaceCurrentStreamWithStream(muteableLogStream);
base.evaluate();
}
}).evaluate();
} catch(Throwable e) {
write(muteableLogStream.getFailureLog(), printStreamHandler.getStream());
throw e;
}
}
});
}

public void clearLog() {
muteableLogStream.clearLog();
}

public void enableLog() {
muteableLogStream.enableLog();
};
}

public String getLog() {
Expand All @@ -52,46 +58,64 @@ public void mute() {
muteableLogStream.mute();
}

public void muteForSuccessfulTests() {
mute();
muteableLogStream.enableFailureLog();
}

public void clearLog() {
muteableLogStream.clearLog();
}

private static class MuteableLogStream extends PrintStream {
private static final boolean AUTO_FLUSH = true;
private static final String ENCODING = "UTF-8";
private final ByteArrayOutputStream failureLog;
private final ByteArrayOutputStream log;
private final MutableOutputStream mutableOriginalStream;
private final MutableOutputStream mutableLog;
private final MutableOutputStream muteableOriginalStream;
private final MutableOutputStream muteableFailureLog;
private final MutableOutputStream muteableLog;

MuteableLogStream(OutputStream out) throws UnsupportedEncodingException {
this(out, new ByteArrayOutputStream());
this(out, new ByteArrayOutputStream(), new ByteArrayOutputStream());
}

MuteableLogStream(OutputStream out, ByteArrayOutputStream log)
throws UnsupportedEncodingException {
MuteableLogStream(OutputStream out, ByteArrayOutputStream failureLog,
ByteArrayOutputStream log) throws UnsupportedEncodingException {
this(new MutableOutputStream(out),
failureLog, new MutableOutputStream(failureLog),
log, new MutableOutputStream(log));
}

MuteableLogStream(MutableOutputStream mutableOriginalStream,
ByteArrayOutputStream log, MutableOutputStream mutableLog)
throws UnsupportedEncodingException {
MuteableLogStream(MutableOutputStream muteableOriginalStream,
ByteArrayOutputStream failureLog, MutableOutputStream muteableFailureLog,
ByteArrayOutputStream log, MutableOutputStream muteableLog)
throws UnsupportedEncodingException {
super(new TeeOutputStream(
new PrintStream(mutableOriginalStream),
new PrintStream(mutableLog)),
new PrintStream(muteableOriginalStream),
new TeeOutputStream(
new PrintStream(muteableFailureLog),
new PrintStream(muteableLog))),
!AUTO_FLUSH, ENCODING);
this.failureLog = failureLog;
this.log = log;
this.mutableOriginalStream = mutableOriginalStream;
this.mutableLog = mutableLog;
this.mutableLog.mute();
this.muteableOriginalStream = muteableOriginalStream;
this.muteableFailureLog = muteableFailureLog;
this.muteableFailureLog.mute();
this.muteableLog = muteableLog;
this.muteableLog.mute();
}

void mute() {
mutableOriginalStream.mute();
muteableOriginalStream.mute();
}

void clearLog() {
log.reset();
}

void enableLog() {
mutableLog.turnOutputOn();
muteableLog.turnOutputOn();
}

String getLog() {
Expand All @@ -101,6 +125,18 @@ String getLog() {
throw new RuntimeException(e);
}
}

void enableFailureLog() {
muteableFailureLog.turnOutputOn();
}

String getFailureLog() {
try {
return failureLog.toString(ENCODING);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}

private static class MutableOutputStream extends OutputStream {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import static org.hamcrest.Matchers.isEmptyString;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
Expand Down Expand Up @@ -69,6 +70,61 @@ public void evaluate() throws Throwable {
assertThat(systemErr, hasToString(isEmptyString()));
}

@Test
public void doesNotWriteToSystemErrForSuccessfulTestIfMutedGloballyForSuccessfulTests()
throws Throwable{
ByteArrayOutputStream systemErr = useReadableSystemErr();
SystemErrRule rule = new SystemErrRule().muteForSuccessfulTests();
executeRuleWithStatement(rule, writeTextToSystemErr("arbitrary text"));
assertThat(systemErr, hasToString(isEmptyString()));
}

@Test
public void writesToSystemErrForFailingTestIfMutedGloballyForSuccessfulTests()
throws Throwable {
ByteArrayOutputStream systemErr = useReadableSystemErr();
SystemErrRule rule = new SystemErrRule().muteForSuccessfulTests();
executeRuleWithStatement(rule, new Statement() {
@Override
public void evaluate() throws Throwable {
err.print("arbitrary text");
fail();
}
});
assertThat(systemErr, hasToString("arbitrary text"));
}

@Test
public void doesNotWriteToSystemErrForSuccessfulTestIfMutedLocallyForSuccessfulTests()
throws Throwable{
ByteArrayOutputStream systemErr = useReadableSystemErr();
final SystemErrRule rule = new SystemErrRule();
executeRuleWithStatement(rule, new Statement() {
@Override
public void evaluate() throws Throwable {
rule.muteForSuccessfulTests();
err.print("arbitrary text");
}
});
assertThat(systemErr, hasToString(isEmptyString()));
}

@Test
public void writesToSystemErrForFailingTestIfMutedLocallyForSuccessfulTests()
throws Throwable{
ByteArrayOutputStream systemErr = useReadableSystemErr();
final SystemErrRule rule = new SystemErrRule();
executeRuleWithStatement(rule, new Statement() {
@Override
public void evaluate() throws Throwable {
rule.muteForSuccessfulTests();
err.print("arbitrary text");
fail();
}
});
assertThat(systemErr, hasToString("arbitrary text"));
}

@Test
public void doesNotLogByDefault() throws Throwable {
SystemErrRule rule = new SystemErrRule();
Expand Down Expand Up @@ -134,6 +190,10 @@ public void evaluate() throws Throwable {

private void executeRuleWithStatement(TestRule rule, Statement statement)
throws Throwable {
rule.apply(statement, null).evaluate();
try {
rule.apply(statement, null).evaluate();
} catch (AssertionError ignored) {
//we must ignore the exception in case of a failing statement.
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import static org.hamcrest.Matchers.isEmptyString;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
Expand Down Expand Up @@ -69,6 +70,61 @@ public void evaluate() throws Throwable {
assertThat(systemOut, hasToString(isEmptyString()));
}

@Test
public void doesNotWriteToSystemOutForSuccessfulTestIfMutedGloballyForSuccessfulTests()
throws Throwable{
ByteArrayOutputStream systemOut = useReadableSystemOut();
SystemOutRule rule = new SystemOutRule().muteForSuccessfulTests();
executeRuleWithStatement(rule, writeTextToSystemOut("arbitrary text"));
assertThat(systemOut, hasToString(isEmptyString()));
}

@Test
public void writesToSystemOutForFailingTestIfMutedGloballyForSuccessfulTests()
throws Throwable {
ByteArrayOutputStream systemOut = useReadableSystemOut();
SystemOutRule rule = new SystemOutRule().muteForSuccessfulTests();
executeRuleWithStatement(rule, new Statement() {
@Override
public void evaluate() throws Throwable {
out.print("arbitrary text");
fail();
}
});
assertThat(systemOut, hasToString("arbitrary text"));
}

@Test
public void doesNotWriteToSystemOutForSuccessfulTestIfMutedLocallyForSuccessfulTests()
throws Throwable{
ByteArrayOutputStream systemOut = useReadableSystemOut();
final SystemOutRule rule = new SystemOutRule();
executeRuleWithStatement(rule, new Statement() {
@Override
public void evaluate() throws Throwable {
rule.muteForSuccessfulTests();
out.print("arbitrary text");
}
});
assertThat(systemOut, hasToString(isEmptyString()));
}

@Test
public void writesToSystemOutForFailingTestIfMutedLocallyForSuccessfulTests()
throws Throwable{
ByteArrayOutputStream systemOut = useReadableSystemOut();
final SystemOutRule rule = new SystemOutRule();
executeRuleWithStatement(rule, new Statement() {
@Override
public void evaluate() throws Throwable {
rule.muteForSuccessfulTests();
out.print("arbitrary text");
fail();
}
});
assertThat(systemOut, hasToString("arbitrary text"));
}

@Test
public void doesNotLogByDefault() throws Throwable {
SystemOutRule rule = new SystemOutRule();
Expand Down Expand Up @@ -134,6 +190,10 @@ public void evaluate() throws Throwable {

private void executeRuleWithStatement(TestRule rule, Statement statement)
throws Throwable {
rule.apply(statement, null).evaluate();
try {
rule.apply(statement, null).evaluate();
} catch (AssertionError ignored) {
//we must ignore the exception in case of a failing statement.
}
}
}

0 comments on commit e6d3ae8

Please sign in to comment.