diff --git a/pom.xml b/pom.xml index 1f8b5dd..9bb5691 100644 --- a/pom.xml +++ b/pom.xml @@ -14,13 +14,19 @@ RELEASE test + + com.github.stefanbirkner + system-lambda + 1.2.1 + test + 11 11 UTF-8 - com.github.dtschust.zork.Zork + com.github.dtschust.zork.original.Zork diff --git a/short.txt b/short.txt deleted file mode 100644 index 4e2605d..0000000 --- a/short.txt +++ /dev/null @@ -1,9 +0,0 @@ -You find yourself at the mouth of a cave and decide that in spite of common sense and any sense of self preservation that you're going to go exploring north into it. It's a little dark, but luckily there are some torches on the wall. ->e -Can't go that way. ->N -Error ->n -*stumble* need some light... ->i -Inventory: empty diff --git a/src/test/java/com/github/dtschust/zork/ZorkTest.java b/src/test/java/com/github/dtschust/zork/ZorkTest.java index 09e8e35..b11f745 100644 --- a/src/test/java/com/github/dtschust/zork/ZorkTest.java +++ b/src/test/java/com/github/dtschust/zork/ZorkTest.java @@ -1,138 +1,42 @@ package com.github.dtschust.zork; +import com.github.dtschust.zork.utils.CommandReader; +import com.github.dtschust.zork.utils.IOWrapper; import org.junit.jupiter.api.Test; -import java.io.*; -import java.util.Scanner; - +import static com.github.stefanbirkner.systemlambda.SystemLambda.catchSystemExit; import static org.junit.jupiter.api.Assertions.assertEquals; -/** - * Not really nice but works - * TODO: The test result should be success instead of terminated ?WHY? - * TODO: when looking at inventory (i) we are relying on the HashMap order, so the test may fail !UNSAFE! - */ class ZorkTest { + /** Test the game interacting as a real player + * WARNING: when looking at inventory (i) we are relying on the HashMap order, so the test may be unsafe + */ @Test - public void testRunThroughResults() { - CommandReader run = new CommandReader("RunThroughResults.txt"); - GamePlayer game = new GamePlayer("sampleGame.xml", false); + public void testSampleGame() { + String gameConfig = "sampleGame.xml"; + String gameExecution = "RunThroughResults.txt"; + + CommandReader run = new CommandReader(gameExecution); + IOWrapper io = new IOWrapper(false); + new Thread(() -> { + try { + catchSystemExit(() -> new Zork(gameConfig)); + } catch (Exception ignored) {} + }).start(); while(true){ switch(run.getInstructionType()) { case SEND: - game.write(run.getInstruction()); + io.write(run.getInstruction()); break; case RECV: - assertEquals(run.getInstruction(), game.read()); + assertEquals(run.getInstruction(), io.read()); break; default: + io.restore(); return; } } } - - /** - * CommandReader reads the .txt file containing expected input and output - */ - static class CommandReader{ - private String instruction; - private static Scanner scanner; - - public enum Type{ SEND, RECV, END } - - /** CommandReader Constructor - * @param filename file containing command sent (with leading ">") and expected responses - */ - CommandReader(String filename) { - try { - scanner = new Scanner(new File(filename)); - } catch (FileNotFoundException e){ - e.printStackTrace(); - } - } - - /** - * @return Type of the next instruction: - * - END if the game ended - * - SEND if it's th command to send - * - RECV if it's a game output - */ - public Type getInstructionType(){ - if(!scanner.hasNextLine()) - return Type.END; - instruction = scanner.nextLine(); - if(instruction.startsWith(">")) { - instruction = instruction.substring(1); - return Type.SEND; - } - - return Type.RECV; - } - - /** Returns a text line (can be both an input or output depending on the Type) - * @return The next text line - */ - public String getInstruction() { - return instruction; - } - } - - /** - * GamePlayer start the game and holds a communication interface to interact to it - */ - static class GamePlayer { - public final PrintStream console; - private PrintStream printer; - private BufferedReader reader; - private final boolean verbose; - - - /** GamePlayer Constructor - * @param filename name of the game configuration .xml file - * @param verbose should log on the console all command sent to / received by the game - */ - public GamePlayer(String filename, boolean verbose) { - this.verbose = verbose; - console = System.out; - try{ - final PipedOutputStream testInput = new PipedOutputStream(); - final PipedOutputStream out = new PipedOutputStream(); - final PipedInputStream testOutput = new PipedInputStream(out); - System.setIn(new PipedInputStream(testInput)); - System.setOut(new PrintStream(out)); - printer = new PrintStream(testInput); - reader = new BufferedReader(new InputStreamReader(testOutput)); - } catch (IOException e) { - e.printStackTrace(console); - } - - new Thread(() -> new Zork(filename)).start(); - } - - /** Sends a command to the game (and print it if verbose) - * @param line text to send to the game - */ - public void write(String line) { - printer.println(line); - if(verbose) - console.println("> " + line); - } - - /** Receive a command from the game (and print it if verbose) - * @return line of text sent by the game - */ - public String read() { - String line = null; - try{ - line = reader.readLine(); - if(verbose) - console.println("< " + line); - } catch (IOException e) { - e.printStackTrace(console); - } - return line; - } - } } \ No newline at end of file diff --git a/src/test/java/com/github/dtschust/zork/utils/CommandReader.java b/src/test/java/com/github/dtschust/zork/utils/CommandReader.java new file mode 100644 index 0000000..bc86d84 --- /dev/null +++ b/src/test/java/com/github/dtschust/zork/utils/CommandReader.java @@ -0,0 +1,51 @@ +package com.github.dtschust.zork.utils; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Scanner; + +/** + * CommandReader reads the .txt file containing expected input and output + */ +public class CommandReader{ + private String instruction; + private static Scanner scanner; + + public enum Type{ SEND, RECV, END } + + /** CommandReader Constructor + * @param filename file containing command sent (with leading ">") and expected responses + */ + public CommandReader(String filename) { + try { + scanner = new Scanner(new File(filename)); + } catch (FileNotFoundException e){ + e.printStackTrace(); + } + } + + /** Load the next instruction (overwrite current instruction) and detect its type + * @return Type of the next instruction: + * - END if the game ended + * - SEND if it's th command to send + * - RECV if it's a game output + */ + public Type getInstructionType(){ + if(!scanner.hasNextLine()) + return Type.END; + instruction = scanner.nextLine(); + if(instruction.startsWith(">")) { + instruction = instruction.substring(1); + return Type.SEND; + } + + return Type.RECV; + } + + /** Returns a text line (can be both an input or output depending on the Type) + * @return The next text line + */ + public String getInstruction() { + return instruction; + } +} diff --git a/src/test/java/com/github/dtschust/zork/utils/IOWrapper.java b/src/test/java/com/github/dtschust/zork/utils/IOWrapper.java new file mode 100644 index 0000000..ee30bdb --- /dev/null +++ b/src/test/java/com/github/dtschust/zork/utils/IOWrapper.java @@ -0,0 +1,67 @@ +package com.github.dtschust.zork.utils; + + +import java.io.*; + +/** + * IOWrapper allows to automatize in/out communication + */ +public class IOWrapper { + public final PrintStream console; + public final InputStream input; + private PrintStream printer; + private BufferedReader reader; + private final boolean verbose; + + /** IOWrapper Constructor + * @param verbose should log on the console all command sent to / received by the game + */ + public IOWrapper(boolean verbose) { + this.verbose = verbose; + console = System.out; + input = System.in; + try{ + final PipedOutputStream testInput = new PipedOutputStream(); + final PipedOutputStream out = new PipedOutputStream(); + final PipedInputStream testOutput = new PipedInputStream(out); + System.setIn(new PipedInputStream(testInput)); + System.setOut(new PrintStream(out)); + printer = new PrintStream(testInput); + reader = new BufferedReader(new InputStreamReader(testOutput)); + } catch (IOException e) { + e.printStackTrace(console); + } + } + + /** Sends a command to the game (and print it if verbose) + * @param line text to send to the game + */ + public void write(String line) { + printer.println(line); + if(verbose) + console.println("> " + line); + } + + /** Receive a command from the game (and print it if verbose) + * @return line of text sent by the game + */ + public String read() { + String line = null; + try{ + line = reader.readLine(); + if(verbose) + console.println("< " + line); + } catch (IOException e) { + e.printStackTrace(console); + } + return line; + } + + /** Restore the default System IO + * + */ + public void restore(){ + System.setIn(input); + System.setOut(console); + } +}