Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- GuessTheNumber.java = simple “guess the number” game
- RandomNumberGenerator.java = wrapper for random number generation
- GuessTheNumberTest.java = JUnit test for the game
- MockRandomNumberGenerator.java = mock implementation for single-use random number
- SystemInputOutputTester.java = Builder for console I/O testing
- MockStandardOutputStream.java = Capture Standard Output (or Error)
- MockInputStream.java = Provide input when needed. Calls back to SystemInputOutputTester to validate intervening output and to provide the input data.
- ExpectedInputOutputStepBase.java = common base class for input/output expectations
- ExpectedTextOutputStep.java = Expect that the given text output is written to Standard Output (or Error).
- ProvideLineInputStep.java = Provide line of Console Input at that point in the expectations list.
- */
- //
- // File Name: GuessTheNumber.java
- //
- import java.util.Scanner;
- public class GuessTheNumber {
- protected static RandomNumberGenerator _randomNumberGenerator = new RandomNumberGenerator();
- public static void main(final String[] args) {
- System.out.println("Welcome to the number guessing program.");
- System.out.println("I am thinking of a number in the range of 1 to 100, inclusive.");
- System.out.println("You need to guess this number, with a minimum number of guesses.");
- System.out.println("Each time you guess, I will tell you if my number is HIGHER or LOWER than your guess.");
- final int numberToGuess = _randomNumberGenerator.nextInt(100);
- final var scanner = new Scanner(System.in);
- while (true) {
- System.out.println("What is your guess?");
- final var userGuess = scanner.nextInt();
- if (userGuess < numberToGuess) {
- System.out.println("Your guess of " + userGuess + " is TOO LOW.");
- } else if (userGuess > numberToGuess) {
- System.out.println("Your guess of " + userGuess + " is TOO HIGH.");
- } else {
- System.out.println("Your guess of " + userGuess + " is CORRECT!");
- break;
- }
- }
- }
- }
- //
- // File Name: RandomNumberGenerator.java
- //
- import java.util.Random;
- public class RandomNumberGenerator {
- private final Random _randomNumberGenerator = new Random();
- public int nextInt(final int bound) {
- return _randomNumberGenerator.nextInt(bound);
- }
- }
- //
- // File Name: GuessTheNumberTest.java
- //
- import org.junit.Test;
- public class GuessTheNumberTest {
- @Test
- public void test() {
- final var oldRandomNumberGenerator = GuessTheNumber._randomNumberGenerator;
- GuessTheNumber._randomNumberGenerator = new MockRandomNumberGenerator(33);
- try {
- SystemInputOutputTester
- .whenCallingThisMethod(() -> {GuessTheNumber.main(null);})
- .assertTextOutput("Welcome to the number guessing program.")
- //
- .assertTextOutput("I am thinking of a number in the range of 1 to 100, inclusive.")
- .assertTextOutput("You need to guess this number, with a minimum number of guesses.")
- .assertTextOutput("Each time you guess, I will tell you if my number is HIGHER or LOWER than your guess.")
- //
- .assertTextOutput("What is your guess?")
- .provideLineInput("50")
- .assertTextOutput("Your guess of 50 is TOO HIGH.")
- //
- .assertTextOutput("What is your guess?")
- .provideLineInput("25")
- .assertTextOutput("Your guess of 25 is TOO LOW.")
- //
- .assertTextOutput("What is your guess?")
- .provideLineInput("37")
- .assertTextOutput("Your guess of 37 is TOO HIGH.")
- //
- .assertTextOutput("What is your guess?")
- .provideLineInput("31")
- .assertTextOutput("Your guess of 31 is TOO LOW.")
- //
- .assertTextOutput("What is your guess?")
- .provideLineInput("34")
- .assertTextOutput("Your guess of 34 is TOO HIGH.")
- //
- .assertTextOutput("What is your guess?")
- .provideLineInput("32")
- .assertTextOutput("Your guess of 32 is TOO LOW.")
- //
- .assertTextOutput("What is your guess?")
- .provideLineInput("33")
- .assertTextOutput("Your guess of 33 is CORRECT!")
- //
- .assertThatTheMethodReturnsHere();
- } finally {
- GuessTheNumber._randomNumberGenerator = oldRandomNumberGenerator;
- }
- }
- }
- //
- // File Name: MockRandomNumberGenerator.java
- //
- public class MockRandomNumberGenerator extends RandomNumberGenerator {
- private int _theFixedRandomNumberValue;
- public MockRandomNumberGenerator(final int theFixedRandomNumberValue) {
- _theFixedRandomNumberValue = theFixedRandomNumberValue;
- }
- @Override
- public int nextInt(final int bound) {
- final var returnValue = _theFixedRandomNumberValue;
- _theFixedRandomNumberValue = -1; // Clear value, as it's only good for one use.
- return returnValue;
- }
- }
- //
- // File Name: SystemInputOutputTester.java
- //
- import junit.framework.AssertionFailedError;
- import java.io.PrintStream;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.List;
- public class SystemInputOutputTester {
- private final Runnable _callback;
- private final List<ExpectedInputOutputStepBase> _expectedInputOutputSteps = new ArrayList<ExpectedInputOutputStepBase>();
- private Iterator<ExpectedInputOutputStepBase> _expectedInputOutputStepIterator = null;
- protected final MockInputStream _mockInputStream = new MockInputStream(this);
- protected final MockStandardOutputStream _mockStandardOutputStream = new MockStandardOutputStream();
- //protected final MockStandardOutputStream _mockStandardErrorStream = new MockStandardOutputStream(this);
- public SystemInputOutputTester(final Runnable callback) {
- _callback = callback;
- }
- public static SystemInputOutputTester whenCallingThisMethod(final Runnable callback) {
- return new SystemInputOutputTester(callback);
- }
- public SystemInputOutputTester assertTextOutput(final String expectedOutputMessage) {
- _expectedInputOutputSteps.add(new ExpectedTextOutputStep(expectedOutputMessage));
- return this;
- }
- public SystemInputOutputTester provideLineInput(final String lineOfInputText) {
- _expectedInputOutputSteps.add(new ProvideLineInputStep(lineOfInputText));
- return this;
- }
- public void assertThatTheMethodReturnsHere() {
- final var oldInput = System.in;
- final var oldOutput = System.out;
- //final var oldError = System.err;
- try {
- System.setIn(_mockInputStream);
- System.setOut(new PrintStream(_mockStandardOutputStream));
- //System.setErr(new PrintStream(_mockStandardErrorStream));
- _expectedInputOutputStepIterator = _expectedInputOutputSteps.iterator();
- _callback.run();
- System.out.flush();
- System.err.flush();
- while (_expectedInputOutputStepIterator.hasNext()) {
- final var step = _expectedInputOutputStepIterator.next();
- final var isAfterExit = true;
- final var didProvideNewUserInput = step.validate(this);
- if (didProvideNewUserInput) {
- throw new AssertionFailedError("Program has exited, but the tests say that we should further input: <" + ((ProvideLineInputStep) step)._lineOfInputText + ">.");
- }
- }
- } finally {
- System.setIn(oldInput);
- System.setOut(oldOutput);
- //System.setErr(oldError);
- }
- }
- public void validateToAndIncludingNextInput() {
- System.out.flush();
- System.err.flush();
- while (_expectedInputOutputStepIterator.hasNext()) {
- final var step = _expectedInputOutputStepIterator.next();
- final var isAfterExit = false;
- final var didProvideNewUserInput = step.validate(this);
- if (didProvideNewUserInput) {
- break;
- }
- }
- }
- }
- //
- // File Name: MockStandardOutputStream.java
- //
- import org.jetbrains.annotations.NotNull;
- import org.junit.Assert;
- import java.io.IOException;
- import java.io.OutputStream;
- public class MockStandardOutputStream extends OutputStream {
- private final StringBuilder _sequenceOfByteValues = new StringBuilder();
- private final StringBuilder _accumulatedOutput = new StringBuilder();
- @Override
- public void write(final int byteValue) throws IOException {
- _sequenceOfByteValues.append((char) byteValue);
- }
- public StringBuilder getUpdatedStringBuilder() {
- if (_sequenceOfByteValues.length() > 0) {
- final String stringValue = getStringValue();
- _accumulatedOutput.append(stringValue);
- }
- return _accumulatedOutput;
- }
- @NotNull
- private String getStringValue() {
- final var bytes = new byte[_sequenceOfByteValues.length()];
- final var charArray = _sequenceOfByteValues.toString().toCharArray();
- Assert.assertEquals(bytes.length, charArray.length);
- for (int idx = 0; idx < bytes.length; ++idx) {
- bytes[idx] = (byte) charArray[idx];
- }
- _sequenceOfByteValues.setLength(0);
- final var stringValue = new String(bytes);
- return stringValue;
- }
- }
- //
- // File Name: MockInputStream.java
- //
- import java.io.IOException;
- import java.io.InputStream;
- public class MockInputStream extends InputStream {
- private final SystemInputOutputTester _systemInputOutputTester;
- private final StringBuilder _inputToProvide = new StringBuilder();
- public MockInputStream(final SystemInputOutputTester systemInputOutputTester) {
- _systemInputOutputTester = systemInputOutputTester;
- }
- @Override
- public int read() throws IOException {
- if (_inputToProvide.length() == 0) {
- _systemInputOutputTester.validateToAndIncludingNextInput();
- }
- if (_inputToProvide.length() == 0) {
- return -1; // = End Of File
- } else {
- final var firstCharacter = _inputToProvide.charAt(0);
- _inputToProvide.delete(0, 1);
- return firstCharacter;
- }
- }
- @Override
- public int read(final byte byteArray[], final int offset, final int length) throws IOException {
- if (_inputToProvide.length() == 0) {
- _systemInputOutputTester.validateToAndIncludingNextInput();
- }
- if (_inputToProvide.length() == 0) {
- return -1; // = End Of File
- } else {
- int charsRead = 0;
- for (; charsRead < length && _inputToProvide.length() > 0; ++charsRead) {
- final var firstCharacter = _inputToProvide.charAt(0);
- _inputToProvide.delete(0, 1);
- byteArray[offset + charsRead] = (byte) firstCharacter;
- }
- return charsRead;
- }
- }
- public void provideLineOfInput(final String lineOfInputText) {
- _inputToProvide.append(lineOfInputText);
- _inputToProvide.append('\n');
- }
- }
- //
- // File Name: ExpectedInputOutputStepBase.java
- //
- import junit.framework.AssertionFailedError;
- abstract public class ExpectedInputOutputStepBase {
- protected final AssertionFailedError _locationOfAssertionInitialization = new AssertionFailedError(
- "Location of assertion initialization. [Look up in the Test's chained method calls.]");
- protected ExpectedInputOutputStepBase() {
- }
- public abstract boolean validate(final SystemInputOutputTester systemInputOutputTester);
- }
- //
- // File Name: ExpectedTextOutputStep.java
- //
- import junit.framework.AssertionFailedError;
- public class ExpectedTextOutputStep extends ExpectedInputOutputStepBase {
- private final String _expectedOutputMessage;
- public ExpectedTextOutputStep(final String expectedOutputMessage) {
- _expectedOutputMessage = expectedOutputMessage;
- }
- @Override
- public boolean validate(final SystemInputOutputTester systemInputOutputTester) {
- final var stringBuilder = systemInputOutputTester._mockStandardOutputStream.getUpdatedStringBuilder();
- final var currentStringValue = stringBuilder.toString();
- final var foundAtIndex = currentStringValue.indexOf(_expectedOutputMessage);
- if (foundAtIndex >= 0) {
- stringBuilder.delete(0, foundAtIndex + _expectedOutputMessage.length());
- return false; // Did NOT provide new *input* data.
- } else {
- final var remainingOutputWithNewlinesVisible = currentStringValue
- .replace("\r\n", "[NL]")
- .replace("\r", "\\r")
- .replace("\n", "\\n")
- ;
- final var failEx = new AssertionFailedError("Failed to find <" + _expectedOutputMessage + "> in <" + remainingOutputWithNewlinesVisible + ">");
- failEx.initCause(super._locationOfAssertionInitialization);
- throw failEx;
- }
- }
- }
- //
- // File Name: ProvideLineInputStep.java
- //
- public class ProvideLineInputStep extends ExpectedInputOutputStepBase {
- protected final String _lineOfInputText;
- public ProvideLineInputStep(final String lineOfInputText) {
- _lineOfInputText = lineOfInputText;
- }
- @Override
- public boolean validate(final SystemInputOutputTester systemInputOutputTester) {
- systemInputOutputTester._mockInputStream.provideLineOfInput(_lineOfInputText);
- return true; // *DID* provide new *input* data.
- }
- }
Add Comment
Please, Sign In to add comment