package dslab; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; /** * Simulates reading lines from an {@link InputStream}. * * Internally, the lines read from the underlying {@link InputStream} are buffered and can be retrieved on demand for * verification purposes. */ public class TestInputStream extends InputStream { private volatile BlockingQueue lines = new LinkedBlockingQueue<>(); private InputStream in; @Override public synchronized int read() throws IOException { if (in == null) { if ((in = nextLine()) == null) { return -1; } } else if (in.available() <= 0) { try { return -1; } finally { in = null; } } return in != null ? in.read() : -1; } /** * Returns a copy of the lines available for reading. * * @return the available lines * @throws IOException if the stream is closed */ public List getLines() throws IOException { List copy = new ArrayList<>(); do { try { copy.add(lines.take()); } catch (InterruptedException e) { throw new IOException(e); } } while (lines.size() > 0); return copy; } /** * Adds the given line to the input queue. * * @param line the line to add */ public void addLine(String line) { if (lines != null) { lines.add(line); } } /** * Prepares the next line available for reading from it. *

* This method blocks until a line is available or the stream becomes closed. * * @return the {@link InputStream} holding the line * @throws IOException if the stream is closed */ private InputStream nextLine() throws IOException { try { String line = null; while (lines != null && line == null) { line = lines.poll(500L, TimeUnit.MILLISECONDS); } if (line != null) { return new ByteArrayInputStream((line.endsWith("\n") ? line : line + '\n').getBytes()); } else { return new ByteArrayInputStream("".getBytes()); } } catch (InterruptedException e) { throw new IOException(e); } } @Override public void close() throws IOException { if (in != System.in) { super.close(); } lines = null; Thread.currentThread().interrupt(); } }