Skip to content

Commit

Permalink
Support breaks between multiple texts.
Browse files Browse the repository at this point in the history
Sometimes it is necessary to simulate breaks in the user input from
System.in. This can now be achieved by providing multiple texts.

    systemInMock.provide("foo\n", "bar\n");

The change has its seeds in a Stackoverflow question:
http://stackoverflow.com/questions/28505418/what-is-causing-to-junit-and-system-rules-to-fail-on-this-students-submission
  • Loading branch information
stefanbirkner committed Feb 23, 2015
1 parent 0f82a03 commit f49179e
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 8 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ System Rules is available from
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-rules</artifactId>
<version>1.8.0</version>
<version>1.9.0</version>
</dependency>

Please don't forget to add the scope `test` if you're using System
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

import static java.lang.System.in;
import static java.lang.System.setIn;
import static java.util.Arrays.asList;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.Iterator;
import java.util.List;

import org.junit.rules.ExternalResource;

Expand All @@ -28,6 +31,20 @@
* }
* }
* </pre>
*
* <h3>Multiple Texts</h3>
* You can simulate a user that stops typing and continues afterwards
* by providing multiple texts.
* <pre>
* &#064;Test
* public void readTextFromStandardInputStream() {
* systemInMock.provide("foo\n", "bar\n");
* Scanner firstScanner = new Scanner(System.in);
* scanner.nextLine();
* Scanner secondScanner = new Scanner(System.in);
* assertEquals("bar", scanner.nextLine());
* }
* </pre>
*/
public class TextFromStandardInputStream extends ExternalResource {
private final SystemInMock systemInMock = new SystemInMock();
Expand All @@ -42,15 +59,22 @@ public static TextFromStandardInputStream emptyStandardInputStream() {
* specified text.
*
* @param text this text is return by {@code System.in}.
* @deprecated use {@link #provideText(String)}
* @deprecated use {@link #provideText(String...)}
*/
@Deprecated
public TextFromStandardInputStream(String text) {
provideText(text);
}

public void provideText(String text) {
systemInMock.provideText(text);
/**
* Set the text that is returned by {@code System.in}. You can
* provide multiple texts. In that case {@code System.in.read()}
* returns -1 once when the end of a single text is reached and
* continues with the next text afterwards.
* @param texts a list of texts.
*/
public void provideText(String... texts) {
systemInMock.provideText(asList(texts));
}

@Override
Expand All @@ -65,15 +89,34 @@ protected void after() {
}

private static class SystemInMock extends InputStream {
private StringReader reader;
private Iterator<String> texts;
private StringReader currentReader;

public void provideText(String text) {
reader = new StringReader(text);
public void provideText(List<String> texts) {
this.texts = texts.iterator();
optionallyCreateReaderForNextText();
}

@Override
public int read() throws IOException {
return reader.read();
if (currentReader == null)
return -1;
else
return readFromExistingReader();
}

private int readFromExistingReader() throws IOException {
int character = currentReader.read();
if (character == -1)
optionallyCreateReaderForNextText();
return character;
}

private void optionallyCreateReaderForNextText() {
if (texts.hasNext())
currentReader = new StringReader(texts.next());
else
currentReader = null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,33 @@ public void provideText() throws Throwable {
assertThat(statement.textFromSystemIn, is(equalTo(ARBITRARY_TEXT)));
}

@Test
public void providesMultipleTexts() throws Throwable {
executeRuleWithStatement(new Statement() {
@Override
public void evaluate() throws Throwable {
systemInMock.provideText("first text\n", "second text\n");
Scanner firstScanner = new Scanner(System.in);
firstScanner.nextLine();
Scanner secondScanner = new Scanner(System.in);
String textFromSystemIn = secondScanner.nextLine();
assertThat(textFromSystemIn, is(equalTo("second text")));
}
});
}

@Test
public void doesNotFailForNoProvidedText() throws Throwable {
executeRuleWithStatement(new Statement() {
@Override
public void evaluate() throws Throwable {
systemInMock.provideText();
int character = System.in.read();
assertThat(character, is(-1));
}
});
}

@Test
public void restoreSystemIn() throws Throwable {
InputStream originalSystemIn = System.in;
Expand Down

0 comments on commit f49179e

Please sign in to comment.