All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.junit.contrib.java.lang.system.TextFromStandardInputStream Maven / Gradle / Ivy

package org.junit.contrib.java.lang.system;

import static java.lang.System.getProperty;
import static java.lang.System.in;
import static java.lang.System.setIn;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;

import org.junit.rules.ExternalResource;

/**
 * The {@code TextFromStandardInputStream} rule replaces {@code System.in} with
 * another {@code InputStream}, which provides an arbitrary text. The original
 * {@code System.in} is restored after the test.
 *
 * 
 *   public void MyTest {
 *     @Rule
 *     public final TextFromStandardInputStream systemInMock
 *       = emptyStandardInputStream();
 *
 *     @Test
 *     public void readTextFromStandardInputStream() {
 *       systemInMock.provideLines("foo", "bar");
 *       Scanner scanner = new Scanner(System.in);
 *       scanner.nextLine();
 *       assertEquals("bar", scanner.nextLine());
 *     }
 *   }
 * 
* *

Throwing Exceptions

*

{@code TextFromStandardInputStream} can also simulate a {@code System.in} * that throws an {@code IOException} or {@code RuntimeException}. Use *

   systemInMock.{@link #throwExceptionOnInputEnd(IOException)}
*

or *

   systemInMock.{@link #throwExceptionOnInputEnd(RuntimeException)}
*

If you call {@link #provideLines(String...)} in addition then the * exception is thrown after the text has been read from {@code System.in}. */ public class TextFromStandardInputStream extends ExternalResource { private final SystemInMock systemInMock = new SystemInMock(); private InputStream originalIn; public static TextFromStandardInputStream emptyStandardInputStream() { return new TextFromStandardInputStream(""); } /** * Create a new {@code TextFromStandardInputStream}, which provides the * specified text. * * @param text this text is return by {@code System.in}. * @deprecated use {@link #provideLines(String...)} */ @Deprecated public TextFromStandardInputStream(String text) { provideText(text); } /** * Set the text that is returned by {@code System.in}. You can * provide multiple texts. In that case the texts are concatenated. * * @param texts a list of texts. * @deprecated please use {@link #provideLines(String...)} */ @Deprecated public void provideText(String... texts) { systemInMock.provideText(join(texts)); } /** * Set the lines that are returned by {@code System.in}. * {@code System.getProperty("line.separator")} is used for the end * of line. * * @param lines a list of lines. */ public void provideLines(String... lines) { systemInMock.provideText(joinLines(lines)); } /** * Specify an {@code IOException} that is thrown by {@code System.in}. If * you call {@link #provideLines(String...)} or * {@link #provideText(String...)} in addition then the exception is thrown * after the text has been read from {@code System.in}. * * @param exception the {@code IOException} that is thrown. * @see #throwExceptionOnInputEnd(RuntimeException) * @throws IllegalStateException if * {@link #throwExceptionOnInputEnd(RuntimeException)} has been called before. */ public void throwExceptionOnInputEnd(IOException exception) { systemInMock.throwExceptionOnInputEnd(exception); } /** * Specify a {@code RuntimeException} that is thrown by {@code System.in}. * If you call {@link #provideLines(String...)} or * {@link #provideText(String...)} in addition then the exception is thrown * after the text has been read from {@code System.in}. * * @param exception the {@code RuntimeException} that is thrown. * @see #throwExceptionOnInputEnd(IOException) * @throws IllegalStateException if * {@link #throwExceptionOnInputEnd(IOException)} has been called before. */ public void throwExceptionOnInputEnd(RuntimeException exception) { systemInMock.throwExceptionOnInputEnd(exception); } private String join(String[] texts) { StringBuilder sb = new StringBuilder(); for (String text: texts) sb.append(text); return sb.toString(); } private String joinLines(String[] lines) { StringBuilder sb = new StringBuilder(); for (String line: lines) sb.append(line).append(getProperty("line.separator")); return sb.toString(); } @Override protected void before() throws Throwable { originalIn = in; setIn(systemInMock); } @Override protected void after() { setIn(originalIn); } private static class SystemInMock extends InputStream { private StringReader currentReader; private IOException ioException; private RuntimeException runtimeException; void provideText(String text) { currentReader = new StringReader(text); } void throwExceptionOnInputEnd(IOException exception) { if (runtimeException != null) throw new IllegalStateException("You cannot call" + " throwExceptionOnInputEnd(IOException) because" + " throwExceptionOnInputEnd(RuntimeException) has already" + " been called."); ioException = exception; } void throwExceptionOnInputEnd(RuntimeException exception) { if (ioException != null) throw new IllegalStateException("You cannot call" + " throwExceptionOnInputEnd(RuntimeException) because" + " throwExceptionOnInputEnd(IOException) has already" + " been called."); runtimeException = exception; } @Override public int read() throws IOException { int character = currentReader.read(); if (character == -1) handleEmptyReader(); return character; } private void handleEmptyReader() throws IOException { if (ioException != null) throw ioException; else if (runtimeException != null) throw runtimeException; } @Override public int read(byte[] buffer, int offset, int len) throws IOException { if (buffer == null) throw new NullPointerException(); else if (offset < 0 || len < 0 || len > buffer.length - offset) throw new IndexOutOfBoundsException(); else if (len == 0) return 0; else return readNextLine(buffer, offset, len); } private int readNextLine(byte[] buffer, int offset, int len) throws IOException { int c = read(); if (c == -1) return -1; buffer[offset] = (byte) c; int i = 1; for (; (i < len) && !isCompleteLineWritten(buffer, i - 1); ++i) { byte read = (byte) read(); if (read == -1) break; else buffer[offset + i] = read; } return i; } private boolean isCompleteLineWritten(byte[] buffer, int indexLastByteWritten) { byte[] separator = getProperty("line.separator").getBytes(); int indexFirstByteOfSeparator = indexLastByteWritten - separator.length + 1; return indexFirstByteOfSeparator >= 0 && contains(buffer, separator, indexFirstByteOfSeparator); } private boolean contains(byte[] array, byte[] pattern, int indexStart) { for (int i = 0; i < pattern.length; ++i) if (array[indexStart + i] != pattern[i]) return false; return true; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy