Skip to content

System in can use less home-made code #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -220,7 +220,7 @@ void Scanner_reads_text_from_System_in(
withTextFromSystemIn("first line", "second line")
.execute(() -> {
Scanner scanner = new Scanner(System.in);
scanner.nextLine();
assertEquals("first line", scanner.nextLine());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Increase clarity of the second assert

assertEquals("second line", scanner.nextLine());
});
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.github.stefanbirkner.systemlambda;

import javax.print.DocFlavor;
import java.io.*;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.security.Permission;
import java.util.*;
import java.util.concurrent.Callable;
@@ -913,96 +915,45 @@ public void execute(


private static class ReplacementInputStream extends InputStream {
private final StringReader reader;
private final IOException ioException;
private final RuntimeException runtimeException;
private final ByteArrayInputStream byteArrayInputStream;

ReplacementInputStream(
String text,
IOException ioException,
RuntimeException runtimeException
) {
this.reader = new StringReader(text);
this.byteArrayInputStream = new ByteArrayInputStream(text.getBytes(defaultCharset()));
this.ioException = ioException;
this.runtimeException = runtimeException;
}

@Override
public int read(
) throws IOException {
int character = reader.read();
int character = byteArrayInputStream.read();
if (character == -1)
handleEmptyReader();
return character;
}

@Override
public int read(byte[] b, int off, int len) throws IOException {
int bytesRead = byteArrayInputStream.read(b, off, len);
if (len > 0 && bytesRead < 0)
handleEmptyReader();

return bytesRead;
}

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(defaultCharset());
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;
}
}
}

Original file line number Diff line number Diff line change
@@ -37,18 +37,19 @@ static void checkArrayConstants() {
@Test
void provided_text_is_available_from_system_in(
) throws Exception {
AtomicReference<String> firstLineCapture = new AtomicReference<>();
AtomicReference<String> secondLineCapture = new AtomicReference<>();

withTextFromSystemIn(
"first line",
"second line"
).execute(() -> {
Scanner firstScanner = new Scanner(in);
firstScanner.nextLine();
Scanner secondScanner = new Scanner(in);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first scanner may cache more than just the first line, so the second scanner is unable to pick up the second line.

secondLineCapture.set(secondScanner.nextLine());
Scanner scanner = new Scanner(in);
firstLineCapture.set(scanner.nextLine());
secondLineCapture.set(scanner.nextLine());
});

assertThat(firstLineCapture).hasValue("first line");
assertThat(secondLineCapture).hasValue("second line");
}

@@ -201,24 +202,24 @@ void system_in_throws_IndexOutOfBoundsException_when_read_is_called_with_oversiz
}

@Test
void system_in_reads_zero_bytes_even_if_mock_should_throw_IOException_on_input_end(
void system_in_reads_no_bytes_even_if_mock_should_throw_IOException_on_input_end(
) throws Exception {
withTextFromSystemIn()
.andExceptionThrownOnInputEnd(DUMMY_IO_EXCEPTION)
.execute(() -> {
int numBytesRead = System.in.read(DUMMY_ARRAY, VALID_OFFSET, 0);
assertThat(numBytesRead).isZero();
assertThat(numBytesRead).isEqualTo(-1);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

read should return -1 at the end of the stream.

});
}

@Test
void system_in_reads_zero_bytes_even_if_mock_should_throw_RuntimeException_on_input_end(
void system_in_reads_no_bytes_even_if_mock_should_throw_RuntimeException_on_input_end(
) throws Exception {
withTextFromSystemIn()
.andExceptionThrownOnInputEnd(DUMMY_RUNTIME_EXCEPTION)
.execute(() -> {
int numBytesRead = System.in.read(DUMMY_ARRAY, VALID_OFFSET, 0);
assertThat(numBytesRead).isZero();
assertThat(numBytesRead).isEqualTo(-1);
});
}