diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/Link.java b/src/main/java/edu/ntnu/idatt2001/group_30/Link.java index 64804272c2efdb57658952b52d7873c120b73949..5b62790b8dc10ee87a2b03dba6c57428d737387a 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/Link.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/Link.java @@ -15,7 +15,7 @@ import java.util.Objects; public class Link { private final String text; private final String reference; - private final List<Action> actions; + private final List<Action<?>> actions; /** * This constructor creates a Link object, which contains information surrounding a linking point in the story. @@ -36,7 +36,7 @@ public class Link { * Adds an action to the list of actions * @param action, the action to be added to the list */ - public void addAction(Action action) { + public void addAction(Action<?> action) { this.actions.add(action); } @@ -60,7 +60,7 @@ public class Link { * This method retrieves the list of actions attached to the Link object. * @return The actions of the Link object, given as a List{@code <Action>}. */ - public List<Action> getActions() { + public List<Action<?>> getActions() { return this.actions; } @@ -79,6 +79,13 @@ public class Link { @Override public String toString() { - return "[" + text + "](" + reference + ")"; + StringBuilder sb = new StringBuilder(); + sb.append("[").append(text).append("](").append(reference).append(")\n"); + + for(Action<?> action : actions) { + sb.append("<").append(action.getClass().getSimpleName()).append(">\\").append(action.getActionValue()).append("/\n"); + } + + return sb.toString(); } } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/Passage.java b/src/main/java/edu/ntnu/idatt2001/group_30/Passage.java index e4c2d88e7faa2e578634bb963081e86956354677..924cb4fca502e7bdd05ee34c72d452a6bad142dc 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/Passage.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/Passage.java @@ -79,7 +79,7 @@ public class Passage { sb.append("::").append(title).append("\n") .append(content).append("\n"); - links.forEach(link -> sb.append(link.toString()).append("\n")); + links.forEach(link -> sb.append(link.toString())); return sb.toString(); } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/Story.java b/src/main/java/edu/ntnu/idatt2001/group_30/Story.java index 93bf57b59d44052731974ad9546ed056c7712bd9..08379f01cba59831e486dc2cdaacd0f84b79c2d8 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/Story.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/Story.java @@ -4,6 +4,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Stream; /** @@ -32,6 +33,7 @@ public class Story { if (openingPassage == null) throw new IllegalArgumentException("Opening passage cannot be null"); this.openingPassage = openingPassage; this.passages = new HashMap<>(); + addPassage(this.openingPassage); } /** @@ -103,7 +105,7 @@ public class Story { /** * This method retrieves all the passages of a story. - * @return All the pages of the Story as a {@code Collection<Passages>}. + * @return All the passages of the Story as a {@code Collection<Passages>}. */ public Collection<Passage> getPassages() { return this.passages.values(); @@ -122,8 +124,28 @@ public class Story { sb.append(this.title).append("\n\n"); sb.append(this.openingPassage.toString()).append("\n"); - this.passages.values().forEach(passage -> sb.append(passage.toString()).append("\n")); + this.passages.values().forEach(passage -> { + if(!passage.equals(openingPassage)) sb.append(passage.toString()).append("\n"); + }); return sb.toString(); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Story story)) return false; + + if (!Objects.equals(title, story.title)) return false; + if (!Objects.equals(passages, story.passages)) return false; + return Objects.equals(openingPassage, story.openingPassage); + } + + @Override + public int hashCode() { + int result = title != null ? title.hashCode() : 0; + result = 31 * result + (passages != null ? passages.hashCode() : 0); + result = 31 * result + (openingPassage != null ? openingPassage.hashCode() : 0); + return result; + } } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/actions/Action.java b/src/main/java/edu/ntnu/idatt2001/group_30/actions/Action.java index 0ab4177629d2965bfc56facc15ae4d6e25fe54a3..8714a90830a37b3673eb9552a0c32a8f2d2e1cc9 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/actions/Action.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/actions/Action.java @@ -3,13 +3,12 @@ package edu.ntnu.idatt2001.group_30.actions; import edu.ntnu.idatt2001.group_30.Player; /** - * The functional interface Action provides the method signature for executing an attribute + * The Action interface provides the method signature for executing an attribute * action on the player. * * @author Trym Hamer Gudvangen */ -@FunctionalInterface -public interface Action { +public interface Action<T> { /** * This method changes a given player's attribute: @@ -17,4 +16,17 @@ public interface Action { */ void execute(Player player); + /** + * This method retrieves the action value of a given action. + * @return Action value, given as an Object. + */ + T getActionValue(); + + /** + * This method ensures that all action implementations has a way to check if two action objects are equal. + * @param o Object being compared + * @return Boolean representing {@code true} if the actions are equal, otherwise {@code false} + */ + boolean equals(Object o); + } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/actions/ActionFactory.java b/src/main/java/edu/ntnu/idatt2001/group_30/actions/ActionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..cfa8198f39564195645e1e8f1416586c67799377 --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2001/group_30/actions/ActionFactory.java @@ -0,0 +1,27 @@ +package edu.ntnu.idatt2001.group_30.actions; + +/** + * This class represents a factory for producing Action objects. It, therefore, has methods for instantiating a single + * object from the information provided. + * + * @author Trym Hamer Gudvangen + */ +public class ActionFactory { + + /** + * This method takes in an ActionType and the action value in order to create an Action object. + * + * @param actionType The type of action, represented as a ActionType enumeration + * @param actionValue The action value, given as a String. + * @return An action object with the information specified + */ + public static Action<?> getAction(ActionType actionType, String actionValue) throws IllegalArgumentException{ + return switch (actionType) { + case GOLD_ACTION -> new GoldAction(Integer.parseInt(actionValue)); + case HEALTH_ACTION -> new HealthAction(Integer.parseInt(actionValue)); + case INVENTORY_ACTION -> new InventoryAction(actionValue); + case SCORE_ACTION -> new ScoreAction(Integer.parseInt(actionValue)); + }; + } + +} diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/actions/ActionType.java b/src/main/java/edu/ntnu/idatt2001/group_30/actions/ActionType.java new file mode 100644 index 0000000000000000000000000000000000000000..41f56dfa967e73e3495876c607d94c75274ffa48 --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2001/group_30/actions/ActionType.java @@ -0,0 +1,13 @@ +package edu.ntnu.idatt2001.group_30.actions; + +/** + * This enumeration represents the different types of actions that exist: gold, health, inventory, and score. + * + * @author Trym Hamer Gudvangen + */ +public enum ActionType { + GOLD_ACTION, + HEALTH_ACTION, + INVENTORY_ACTION, + SCORE_ACTION +} diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/actions/GoldAction.java b/src/main/java/edu/ntnu/idatt2001/group_30/actions/GoldAction.java index d788b51efb976e232ff28e37eae22f8a28b6b052..43e6f8b475da7ca4b0ac04bf29a104ee2bfcbb7c 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/actions/GoldAction.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/actions/GoldAction.java @@ -8,7 +8,7 @@ import java.util.Objects; * * @author Trym Hamer Gudvangen */ -public class GoldAction implements Action { +public class GoldAction implements Action<Integer> { private final int gold; @@ -31,4 +31,26 @@ public class GoldAction implements Action { Objects.requireNonNull(player); player.addGold(this.gold); } + + /** + * This method retrieves the gold value. + * @return Gold value, given as an int. + */ + @Override + public Integer getActionValue() { + return gold; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof GoldAction that)) return false; + + return gold == that.gold; + } + + @Override + public int hashCode() { + return gold; + } } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/actions/HealthAction.java b/src/main/java/edu/ntnu/idatt2001/group_30/actions/HealthAction.java index f7fb16f021d336015be95a63dec5b2c09712902b..97dae448955ac2e3943a2ae94551c3e6c1a0652b 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/actions/HealthAction.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/actions/HealthAction.java @@ -9,7 +9,7 @@ import java.util.Objects; * * @author Trym Hamer Gudvangen */ -public class HealthAction implements Action { +public class HealthAction implements Action<Integer> { private final int health; @@ -31,4 +31,26 @@ public class HealthAction implements Action { Objects.requireNonNull(player); player.addHealth(this.health); } + + /** + * This method retrieves the health value; + * @return Health value, given as an int. + */ + @Override + public Integer getActionValue() { + return health; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof HealthAction that)) return false; + + return health == that.health; + } + + @Override + public int hashCode() { + return health; + } } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/actions/InventoryAction.java b/src/main/java/edu/ntnu/idatt2001/group_30/actions/InventoryAction.java index e82df09415ce831eb3427d9abf87a91d2526955c..35da920a66ed7047bd5589e32facfef25bd72f8b 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/actions/InventoryAction.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/actions/InventoryAction.java @@ -9,7 +9,7 @@ import java.util.Objects; * * @author Trym Hamer Gudvangen */ -public class InventoryAction implements Action { +public class InventoryAction implements Action<String> { private final String item; @@ -31,4 +31,26 @@ public class InventoryAction implements Action { Objects.requireNonNull(player); player.addToInventory(this.item); } + + /** + * This method retrieves the item value. + * @return Item value, given as a String. + */ + @Override + public String getActionValue() { + return this.item; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof InventoryAction that)) return false; + + return Objects.equals(item, that.item); + } + + @Override + public int hashCode() { + return item != null ? item.hashCode() : 0; + } } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/actions/ScoreAction.java b/src/main/java/edu/ntnu/idatt2001/group_30/actions/ScoreAction.java index a76d05d6c91d02402fb9e03b11ceb22f8405de0e..9d20b1b2044f96877b7a9d3c4a9f603bd991cbc5 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/actions/ScoreAction.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/actions/ScoreAction.java @@ -9,7 +9,7 @@ import java.util.Objects; * * @author Trym Hamer Gudvangen */ -public class ScoreAction implements Action { +public class ScoreAction implements Action<Integer> { private final int points; @@ -31,4 +31,26 @@ public class ScoreAction implements Action { Objects.requireNonNull(player); player.addScore(this.points); } + + /** + * This method retrieves the point value. + * @return Point value, given as an int. + */ + @Override + public Integer getActionValue() { + return this.points; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ScoreAction that)) return false; + + return points == that.points; + } + + @Override + public int hashCode() { + return points; + } } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/exceptions/CorruptFileException.java b/src/main/java/edu/ntnu/idatt2001/group_30/exceptions/CorruptFileException.java new file mode 100644 index 0000000000000000000000000000000000000000..f3897248fe64034ad6ce4d034f89e456a279514f --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2001/group_30/exceptions/CorruptFileException.java @@ -0,0 +1,43 @@ +package edu.ntnu.idatt2001.group_30.exceptions; + +/** + * An exception that is thrown when Link information a paths file has been corrupted. + */ +public class CorruptFileException extends RuntimeException{ + + /** + * Constructs a new CorruptFileException with no detail message. + */ + public CorruptFileException() { + + } + + /** + * Constructs a new CorruptFileException with the specified detail message. + * + * @param message The detail message, given as a String. + */ + public CorruptFileException(String message) { + super(message); + } + + /** + * Constructs a new CorruptFileException with the specified detail message and cause. + * + * @param message The detail message, given as a String + * @param cause The cause, given as a Throwable Object. + */ + public CorruptFileException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new CorruptFileException with the specified cause and a detail message of + * {@code cause == null ? null : cause.toString()} (which usually contains the class and detail message of cause). + * + * @param cause The cause, given as a Throwable Object. + */ + public CorruptFileException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/exceptions/CorruptLinkException.java b/src/main/java/edu/ntnu/idatt2001/group_30/exceptions/CorruptLinkException.java new file mode 100644 index 0000000000000000000000000000000000000000..5a247bb5f01e964d97de8656f71527249cd32b67 --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2001/group_30/exceptions/CorruptLinkException.java @@ -0,0 +1,43 @@ +package edu.ntnu.idatt2001.group_30.exceptions; + +/** + * An exception that is thrown when Link information a paths file has been corrupted. + */ +public class CorruptLinkException extends RuntimeException{ + + /** + * Constructs a new CorruptLinkException with no detail message. + */ + public CorruptLinkException() { + } + + /** + * Constructs a new CorruptLinkException with the specified detail message. + * + * @param message The detail message, given as a String. + */ + public CorruptLinkException(String message) { + super(message); + } + + /** + * Constructs a new CorruptLinkException with the specified detail message and cause. + * + * @param message The detail message, given as a String + * @param cause The cause, given as a Throwable Object. + */ + public CorruptLinkException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new CorruptLinkException with the specified cause and a detail message of + * {@code cause == null ? null : cause.toString()} (which usually contains the class and detail message of cause). + * + * @param cause The cause, given as a Throwable Object. + */ + public CorruptLinkException(Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/exceptions/InvalidExtensionException.java b/src/main/java/edu/ntnu/idatt2001/group_30/exceptions/InvalidExtensionException.java new file mode 100644 index 0000000000000000000000000000000000000000..093521ec6b636c665775b23f4f6673e65af0fc49 --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2001/group_30/exceptions/InvalidExtensionException.java @@ -0,0 +1,43 @@ +package edu.ntnu.idatt2001.group_30.exceptions; + +/** + * An exception that is thrown when an invalid file extension is used. + */ +public class InvalidExtensionException extends IllegalArgumentException{ + + /** + * Constructs a new InvalidExtensionException with no detail message. + */ + public InvalidExtensionException() { + } + + /** + * Constructs a new InvalidExtensionException with the specified detail message. + * + * @param message The detail message, given as a String. + */ + public InvalidExtensionException(String message) { + super(message); + } + + /** + * Constructs a new InvalidExtensionException with the specified detail message and cause. + * + * @param message The detail message, given as a String + * @param cause The cause, given as a Throwable Object. + */ + public InvalidExtensionException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new InvalidExtensionException with the specified cause and a detail message of + * {@code cause == null ? null : cause.toString()} (which usually contains the class and detail message of cause). + * + * @param cause The cause, given as a Throwable Object. + */ + public InvalidExtensionException(Throwable cause) { + super(cause); + } +} + diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/filehandling/FileHandler.java b/src/main/java/edu/ntnu/idatt2001/group_30/filehandling/FileHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..fdcc1b244a01d653a0a4661479c32ac69df31116 --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2001/group_30/filehandling/FileHandler.java @@ -0,0 +1,84 @@ +package edu.ntnu.idatt2001.group_30.filehandling; + +import edu.ntnu.idatt2001.group_30.exceptions.InvalidExtensionException; + +import java.io.File; +import java.nio.file.FileSystems; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * This class contains general-use methods for handling files such as file creation and name and path validation. + * + * @author Trym Hamer Gudvangen + */ +public class FileHandler { + + private static final Pattern VALID_CHAR = Pattern.compile("[^<>:\"/*|?\\\\]*"); + private static final Pattern VALID_EXTENSION = Pattern.compile(".*\\.paths$"); + private static String defaultPath = "src/main/resources/story-files"; + + + /** + * This method checks whether the given file name is valid. + * @param fileName Name of the given file, given as a String. + * @return {@code true} if the file name is valid. + * @throws IllegalArgumentException This exception is thrown if given file name is blank or has invalid characters. + */ + public static boolean isFileNameValid(String fileName) throws IllegalArgumentException{ + if(fileName.isBlank()) throw new IllegalArgumentException("File name cannot be blank"); + Matcher matcher = VALID_CHAR.matcher(fileName); + if(!matcher.matches()) throw new IllegalArgumentException("File name contains invalid characters"); + return true; + } + + /** + * This method checks whether the given file contains .paths as the extension. + * @param fileName Name of the file including extension, given as a String + * @return {@code true} if file name contains .paths, else {@code false} + * @throws InvalidExtensionException This exception is thrown if the file name does not contain .paths at the end + */ + public static boolean isFileExtensionValid(String fileName) throws InvalidExtensionException{ + Matcher matcher = VALID_EXTENSION.matcher(fileName); + if(!matcher.matches()) throw new InvalidExtensionException("File name contains invalid characters"); + return true; + } + + /** + * This method checks if a file exists with a given directory path and whether it contains any information. + * @param file The file to be checked, given as a File object + * @return If the file contains no information, {@code false} is returned. Else, {@code true} is returned + */ + public static boolean fileExists(File file) { + return file.length() > 0; + } + + /** + * This method takes a file name. It, then, checks whether the name is valid and if so, it creates a file for it. + * @param fileName Name of the file, given as a String. + * @return The file with the given name, represented using a File object. + * @throws IllegalArgumentException This exception is thrown if the file name is invalid. + */ + public static File createFile(String fileName) throws IllegalArgumentException{ + isFileNameValid(fileName); + return new File(getFileSourcePath(fileName)); + } + + /** + * This method retrieves the file source path of a story file with the file name given. + * @param fileName Name of the desired file, represented as a String + * @return The source path to the file, represented as a String + */ + public static String getFileSourcePath(String fileName){ + return FileSystems.getDefault().getPath(defaultPath, fileName) + ".paths"; + } + //TODO: test for different OS + + /** + * This method changes the default path used to create files. This may, for example, be used for testing purposes. + * @param newPath New default path, given as a String + */ + public static void changeDefaultPath(String newPath) { + defaultPath = newPath; + } +} diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/filehandling/StoryFileHandler.java b/src/main/java/edu/ntnu/idatt2001/group_30/filehandling/StoryFileHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..715be06a6117936c30ecfbf2762205074de902bd --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2001/group_30/filehandling/StoryFileHandler.java @@ -0,0 +1,158 @@ +package edu.ntnu.idatt2001.group_30.filehandling; + +import edu.ntnu.idatt2001.group_30.Link; +import edu.ntnu.idatt2001.group_30.Passage; +import edu.ntnu.idatt2001.group_30.Story; +import edu.ntnu.idatt2001.group_30.actions.Action; +import edu.ntnu.idatt2001.group_30.actions.ActionFactory; +import edu.ntnu.idatt2001.group_30.actions.ActionType; +import edu.ntnu.idatt2001.group_30.exceptions.CorruptFileException; +import edu.ntnu.idatt2001.group_30.exceptions.CorruptLinkException; + +import java.io.*; +import java.util.*; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * This class maintains the storage and retrieval of a Story file. This is done through a Buffered + * writer and reader. + */ +public class StoryFileHandler { + + private final Pattern LINK_PATTERN = Pattern.compile("\\[.*]\\(.*\\)"); + private final Pattern ACTION_PATTERN = Pattern.compile("<.*>\\\\.*/"); + + /** + * This method takes a story and writes its contents to a .paths file. The story information is transcribed + * in the given format: + * <pre> + * Story title + * + * ::Opening Passage Title + * Opening Passage Content + * [Link Text](Link Reference) + * + * ::Another Passage Title + * Passage Content + * [Link Text](Link Reference) + * {@code <Action Type>}\Action Value/ + * [Link Text](Link Reference) + * + * ... + * </pre> + * @param story The story to be saved, given as a Story object. + * @param fileName The name of the file the story will be saved to, given as a String. + * @throws IOException This exception is thrown if an I/O error occurs with the writer. + */ + public void createStoryFile(Story story, String fileName) throws IOException { + Objects.requireNonNull(story, "Story cannot be null"); + Objects.requireNonNull(fileName, "File name cannot be null"); + File file = FileHandler.createFile(fileName); + if(FileHandler.fileExists(file)) throw new IllegalArgumentException("You cannot overwrite a pre-existing story file"); + try(BufferedWriter storyBufferedWriter = new BufferedWriter(new FileWriter(file))){ + storyBufferedWriter.write(story.toString()); + } + } + + /** + * This method takes a story file and parses it to create a story object. + * @param fileName The name of the story file, given as a String. + * @return The story from the file, given as a Story object. + * @throws IOException This exception is thrown if an I/O error occurs with the reader. + */ + public Story readStoryFromFile(String fileName) throws IOException, InstantiationException { + Objects.requireNonNull(fileName, "File name cannot be null"); + File file = new File(FileHandler.getFileSourcePath(fileName)); + if(!FileHandler.fileExists(file)) throw new IllegalArgumentException("There is no story file with that name!"); + Story story; + + try(BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) { + + String storyTitle = bufferedReader.readLine(); + + List<String> passageInfo = new ArrayList<>(List.of(bufferedReader.lines() + .collect(Collectors.joining("\n")).split("\n::"))); + + if(passageInfo.size() == 1) throw new CorruptFileException(storyTitle); + passageInfo.remove(0); + + Passage openingPassage = parseStringToPassage(passageInfo.remove(0)); + + story = new Story(storyTitle, openingPassage); + + for(String passage : passageInfo) { + story.addPassage(parseStringToPassage(passage)); + } + } + + return story; + } + + /** + * This method takes a String containing the information that is vital for a Passage. It, then, parses the + * string into the title, content, and links of the passage. The Links are added to the passage through the + * {@link Passage#addLink(Link)} method. + * @param passageInfo Info of the passage, given as a String. + * @return The passage, given as a Passage object. + */ + private Passage parseStringToPassage(String passageInfo) throws InstantiationException { + String[] splitPassageInfo = passageInfo.split("\n"); + Passage passage = new Passage(splitPassageInfo[0], splitPassageInfo[1]); + for(int i = 2; i < splitPassageInfo.length; i++) { + Link link = parseStringToLink(splitPassageInfo[i]); + passage.addLink(link); + while(i + 1 < splitPassageInfo.length && ACTION_PATTERN.matcher(splitPassageInfo[i+1]).matches()){ + link.addAction(parseStringToAction(splitPassageInfo[++i])); + } + } + + return passage; + } + + /** + * This method takes a String containing the information that is vital for a Link. It, then, parses the + * string into the text and reference of the Link. + * @param linkInfo The information of the link, given as a String. + * @return The link, given as a Link object. + */ + private Link parseStringToLink(String linkInfo){ + if(!LINK_PATTERN.matcher(linkInfo).matches()) throw new CorruptLinkException(linkInfo); + String text = linkInfo.substring(linkInfo.indexOf("[") + 1, linkInfo.indexOf("]") ); + String reference = linkInfo.substring(linkInfo.indexOf("(") + 1, linkInfo.indexOf(")")); + + return new Link(text, reference); + } + + /** + * This method takes a String containing the information that is vital for an Action. It, then, parses the + * string into the implementation and value. + * @param actionInfo The information of the Action, given as a String. + * @return The action implementation, given as an Action object. + */ + private Action<?> parseStringToAction(String actionInfo) throws InstantiationException { + String className = actionInfo.substring(actionInfo.indexOf("<") + 1, actionInfo.indexOf(">")); + String value = actionInfo.substring(actionInfo.indexOf("\\") + 1, actionInfo.indexOf("/")); + + ActionType actionType = extractActionTypeFromInfo(className); + return ActionFactory.getAction(actionType, value); + } + + /** + * This method takes in the Action Class info, given as a String. This method checks what ActionType the information + * belongs to. + * @param actionTypeInfo Information of an action's class from a paths File, represented as a String + * @return The type of Action extracted from the String, given as a ActionType enumeration + * @throws InstantiationException This exception is thrown if the action type information is corrupt + */ + private ActionType extractActionTypeFromInfo(String actionTypeInfo) throws InstantiationException{ + return switch(actionTypeInfo) { + case "GoldAction" -> ActionType.GOLD_ACTION; + case "HealthAction" -> ActionType.HEALTH_ACTION; + case "InventoryAction" -> ActionType.INVENTORY_ACTION; + case "ScoreAction" -> ActionType.SCORE_ACTION; + default -> throw new InstantiationException("The Action type information is corrupt"); + }; + } + +} \ No newline at end of file diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/goals/Goal.java b/src/main/java/edu/ntnu/idatt2001/group_30/goals/Goal.java index f37482fd8b808c1a5df813d0ffe578672eee89de..398acf28e6a2bd57a75812a5b3fc2bb2f84e7140 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/goals/Goal.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/goals/Goal.java @@ -8,6 +8,7 @@ import edu.ntnu.idatt2001.group_30.Player; * * @author Trym Hamer Gudvangen */ +@FunctionalInterface public interface Goal { /** diff --git a/src/test/java/edu/ntnu/idatt2001/group_30/StoryTest.java b/src/test/java/edu/ntnu/idatt2001/group_30/StoryTest.java index a926487ba724a2094ae373d49f1b04579827ae72..3889af3ddde2bdcc54bac211a2e5e67fef85d25d 100644 --- a/src/test/java/edu/ntnu/idatt2001/group_30/StoryTest.java +++ b/src/test/java/edu/ntnu/idatt2001/group_30/StoryTest.java @@ -42,7 +42,7 @@ public class StoryTest { Passage passage2 = new Passage("Befriend Eilor", "You befriend Eilor"); story.addPassage(passage); story.addPassage(passage2); - assertEquals(2, story.getPassages().size()); + assertEquals(3, story.getPassages().size()); } @Test diff --git a/src/test/java/edu/ntnu/idatt2001/group_30/actions/ActionFactoryTest.java b/src/test/java/edu/ntnu/idatt2001/group_30/actions/ActionFactoryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5ee99bc6c32055335f078c5e4320685892abd126 --- /dev/null +++ b/src/test/java/edu/ntnu/idatt2001/group_30/actions/ActionFactoryTest.java @@ -0,0 +1,78 @@ +package edu.ntnu.idatt2001.group_30.actions; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class ActionFactoryTest { + + @Nested + public class ActionFactory_with_valid_value { + + @Test + void can_get_GoldAction(){ + ActionType goldAction = ActionType.GOLD_ACTION; + String value = "5"; + Action<Integer> expectedAction = new GoldAction(5); + + Action<?> actualAction = ActionFactory.getAction(goldAction, value); + + Assertions.assertTrue(actualAction instanceof GoldAction); + Assertions.assertEquals(expectedAction, actualAction); + } + + @Test + void can_get_HealthAction(){ + ActionType healthAction = ActionType.HEALTH_ACTION; + String value = "5"; + Action<Integer> expectedAction = new HealthAction(5); + + Action<?> actualAction = ActionFactory.getAction(healthAction, value); + + Assertions.assertTrue(actualAction instanceof HealthAction); + Assertions.assertEquals(expectedAction, actualAction); + } + + @Test + void can_get_InventoryAction(){ + ActionType inventoryAction = ActionType.INVENTORY_ACTION; + String value = "Sword"; + Action<String> expectedAction = new InventoryAction("Sword"); + + Action<?> actualAction = ActionFactory.getAction(inventoryAction, value); + + Assertions.assertTrue(actualAction instanceof InventoryAction); + Assertions.assertEquals(expectedAction, actualAction); + } + + @Test + void can_get_ScoreAction(){ + ActionType scoreAction = ActionType.SCORE_ACTION; + String value = "5"; + Action<Integer> expectedAction = new ScoreAction(5); + + Action<?> actualAction = ActionFactory.getAction(scoreAction, value); + + Assertions.assertTrue(actualAction instanceof ScoreAction); + Assertions.assertEquals(expectedAction, actualAction); + } + + } + + @Nested + public class ActionFactory_with_invalid_value_such_as { + @Test + void null_action_type_throws_NullPointerException() { + Assertions.assertThrows(NullPointerException.class, () -> { + Action<?> action = ActionFactory.getAction(null, "5"); + }); + } + + @Test + void value_throws_NumberFormatException() { + Assertions.assertThrows(IllegalArgumentException.class, () -> { + Action<?> action = ActionFactory.getAction(ActionType.GOLD_ACTION, "Invalid value"); + }); + } + } +} \ No newline at end of file diff --git a/src/test/java/edu/ntnu/idatt2001/group_30/filehandling/FileHandlerTest.java b/src/test/java/edu/ntnu/idatt2001/group_30/filehandling/FileHandlerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e67958924bc2323105672d43e1e48ee73954edb9 --- /dev/null +++ b/src/test/java/edu/ntnu/idatt2001/group_30/filehandling/FileHandlerTest.java @@ -0,0 +1,133 @@ +package edu.ntnu.idatt2001.group_30.filehandling; + +import edu.ntnu.idatt2001.group_30.exceptions.InvalidExtensionException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.File; +import java.nio.file.FileSystems; +import java.util.concurrent.atomic.AtomicReference; + +class FileHandlerTest { + + @BeforeAll + static void setFileHandlerPath() { + FileHandler.changeDefaultPath("src/test/resources/storytestfiles"); + } + + @Nested + public class The_FileHandler_makes_sure_a_file_name { + + @ParameterizedTest(name = "{index}. File name: {0}") + @ValueSource(strings = {"$123test", "50%Off", "***Story***", "LOTR?", "Winnie the Pooh!", + "LOTR > Hobbit", "The/Hobbit", "[LOTF]", "{LOTR}", "Trym's : Adventure", "Story.paths"}) + void does_not_contain_special_characters(String fileName) { + String expectedExceptionMessage = "File name contains invalid characters"; + + try { + FileHandler.isFileNameValid(fileName); + } catch (IllegalArgumentException e) { + Assertions.assertEquals(expectedExceptionMessage, e.getMessage()); + } + } + + @ParameterizedTest(name = "{index}. File name: {0}") + @ValueSource(strings = {"", " "}) + void is_not_empty_or_blank(String fileName){ + String expectedExceptionMessage = "File name cannot be blank"; + + try { + FileHandler.isFileNameValid(fileName); + } catch (IllegalArgumentException e) { + Assertions.assertEquals(expectedExceptionMessage, e.getMessage()); + } + } + + @ParameterizedTest(name = "{index}. File name: {0}") + @ValueSource(strings = {"Winnie the Pooh", "L.O.T.R", "The-Bible", "Story123"}) + void only_contains_valid_characters(String fileName) { + boolean expectedStatus = true; + + boolean actualStatusOfFile = FileHandler.isFileNameValid(fileName); + + Assertions.assertEquals(expectedStatus, actualStatusOfFile); + } + } + + @Nested + public class The_FileHandler_can_check { + @Test + void if_a_file_exists(){ + boolean expectedStatus = true; + File validFile = new File(FileSystems.getDefault() + .getPath("src", "test", "resources", "storytestfiles", "Bones") + ".paths"); + + boolean actualStatusOfFile = FileHandler.fileExists(validFile); + + Assertions.assertEquals(expectedStatus, actualStatusOfFile); + } + + @Test + void if_a_file_does_not_exist(){ + boolean expectedStatus = false; + File validFile = new File(FileSystems.getDefault() + .getPath("src", "test", "resources", "storytestfiles", "Fairy tale") + ".paths"); + + boolean actualStatusOfFile = FileHandler.fileExists(validFile); + + Assertions.assertEquals(expectedStatus, actualStatusOfFile); + } + + @Test + void the_file_source_path(){ + String expectedFileSourcePath = "src/test/resources/storytestfiles/story.paths"; + String fileName = "story"; + + String actualFileSourcePath = FileHandler.getFileSourcePath(fileName); + + Assertions.assertEquals(expectedFileSourcePath, actualFileSourcePath); + } + + @Test + void if_file_extension_is_valid() { + String validPath = "The Hobbit.paths"; + + boolean isPathValid = FileHandler.isFileExtensionValid(validPath); + + Assertions.assertTrue(isPathValid); + + } + + @ParameterizedTest(name = "{index}. File path: {0}") + @ValueSource(strings = {"Winnie the Pooh.exe", "78924378.doc", "The-Bible.txt", "Story123.csv"}) + void if_file_extension_is_invalid(String filePath) { + + Assertions.assertThrows(InvalidExtensionException.class, () -> { + FileHandler.isFileExtensionValid(filePath); + }); + } + } + + @Nested + public class The_FileHandler_can_create { + @ParameterizedTest(name = "{index}. File name: {0}") + @ValueSource(strings = {"Winnie the Pooh", "L.O.T.R", "The-Bible", "Story123"}) + void new_files_with_valid_names(String fileName) { + try { + File file = FileHandler.createFile(fileName); + file.createNewFile(); + Assertions.assertTrue(file.isFile()); + Assertions.assertTrue(file.exists()); + + file.delete(); + } catch (Exception e) { + Assertions.fail(e.getMessage()); + } + } + } + +} \ No newline at end of file diff --git a/src/test/java/edu/ntnu/idatt2001/group_30/filehandling/StoryFileHandlerTest.java b/src/test/java/edu/ntnu/idatt2001/group_30/filehandling/StoryFileHandlerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..08dc95b5455492b4c28e81ec8160aafebd625a0b --- /dev/null +++ b/src/test/java/edu/ntnu/idatt2001/group_30/filehandling/StoryFileHandlerTest.java @@ -0,0 +1,289 @@ +package edu.ntnu.idatt2001.group_30.filehandling; + +import edu.ntnu.idatt2001.group_30.Link; +import edu.ntnu.idatt2001.group_30.Passage; +import edu.ntnu.idatt2001.group_30.Story; +import edu.ntnu.idatt2001.group_30.actions.*; +import edu.ntnu.idatt2001.group_30.exceptions.CorruptFileException; +import edu.ntnu.idatt2001.group_30.exceptions.CorruptLinkException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.*; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class StoryFileHandlerTest { + + @BeforeAll + static void setFileHandlerPath() { + FileHandler.changeDefaultPath("src/test/resources/storytestfiles"); + } + + StoryFileHandler storyFileHandler = new StoryFileHandler(); + + public File getValidFile(String fileName) { + return FileHandler.createFile(fileName); + } + + static Story validStory(){ + Story story = new Story("The Hobbit", new Passage("Beginning", "Once upon a time...")); + Passage secondChapter = new Passage("The Great Barrier", "After having completed the arduous..."); + story.addPassage(secondChapter); + story.getOpeningPassage().addLink(new Link(secondChapter.getTitle(), secondChapter.getTitle())); + story.getOpeningPassage().getLinks().forEach(link -> link.addAction(new GoldAction(5))); + story.getOpeningPassage().getLinks().get(0).addAction(new ScoreAction(5)); + story.getOpeningPassage().getLinks().get(0).addAction(new HealthAction(6)); + story.getOpeningPassage().getLinks().get(0).addAction(new InventoryAction("Sword")); + return story; + } + + @Nested + public class A_StoryFile_is_valid_if { + + @ParameterizedTest(name = "{index}. File name: {0}") + @ValueSource(strings = {"Winnie the Pooh", "L.O.T.R", "The-Bible", "Story123"}) + void a_file_has_a_valid_name(String fileName) { + Story story = validStory(); + + try { + storyFileHandler.createStoryFile(story, fileName); + } catch (Exception e) { + if(!e.getMessage().equals("You cannot overwrite a pre-existing story file")){ + System.out.println(e.getMessage()); + fail("An exception was thrown when it shouldn't have."); + } + } + + File expectedFileCreated = getValidFile(fileName); + + Assertions.assertTrue(expectedFileCreated.isFile()); + expectedFileCreated.delete(); + } + + @ParameterizedTest (name = "{index}. File name: {0}") + @ValueSource (strings = {"Winnie the Pooh", "L.O.T.R", "The-Bible", "Story123"}) + void files_created_can_be_accessed_and_read(String fileName) { + Story story = validStory(); + + try{ + storyFileHandler.createStoryFile(story, fileName); + }catch (Exception e){ + fail("An exception was thrown when it shouldn't have. " + e.getMessage()); + } + + File expectedFileCreated = getValidFile(fileName); + + Assertions.assertTrue(expectedFileCreated.canRead()); + expectedFileCreated.delete(); + } + + @ParameterizedTest (name = "{index}. File name: {0}") + @ValueSource (strings = {"Winnie the Pooh", "L.O.T.R", "The-Bible", "Story123"}) + void the_pathing_is_correctly_set(String fileName) { + Story story = validStory(); + boolean fileDoesNotExistAtStart = !getValidFile(fileName).exists(); + + try{ + storyFileHandler.createStoryFile(story, fileName); + }catch (Exception e){ + fail("An exception was thrown when it shouldn't have."); + } + + File expectedFileCreated = getValidFile(fileName); + boolean fileDoesExistAfterWrite = expectedFileCreated.exists(); + + //Then/Assert + Assertions.assertTrue(fileDoesNotExistAtStart); + Assertions.assertTrue(fileDoesExistAfterWrite); + expectedFileCreated.delete(); + } + + @Test + void it_cannot_create_new_file_with_preexisting_file_name() { + Story story = validStory(); + String fileName = "Bones"; + + File preexistingFile = getValidFile(fileName); + if(getValidFile(fileName).isFile()) { + Assertions.assertThrows(IllegalArgumentException.class, () -> storyFileHandler.createStoryFile(story, fileName)); + } + else fail("The file check for doesn't exist, so this test is invalid"); + } + + } + + @Nested + public class A_StoryFile_properly_writes_a_story_to_new_file_if_it { + + @ParameterizedTest (name = "{index}. File name: {0}") + @ValueSource (strings = {"Winnie the Pooh", "L.O.T.R", "The-Bible", "Story123"}) + void saves_the_story_title_correctly(String fileName) throws IOException, InstantiationException { + Story story = validStory(); + String expectedTitle = story.getTitle(); + + storyFileHandler.createStoryFile(story, fileName); + Story storyReadFromFile = storyFileHandler.readStoryFromFile(fileName); + String actualTitle = storyReadFromFile.getTitle(); + + Assertions.assertEquals(expectedTitle, actualTitle); + + File file = getValidFile(fileName); + file.delete(); + } + + @ParameterizedTest (name = "{index}. File name: {0}") + @ValueSource (strings = {"Winnie the Pooh", "L.O.T.R", "The-Bible", "Story123"}) + void saves_the_opening_passage_after_title(String fileName) throws IOException, InstantiationException { + Story story = validStory(); + Passage expectedOpeningPassage = story.getOpeningPassage(); + + storyFileHandler.createStoryFile(story, fileName); + Story storyReadFromFile = storyFileHandler.readStoryFromFile(fileName); + Passage actualOpeningPassage = storyReadFromFile.getOpeningPassage(); + + Assertions.assertEquals(expectedOpeningPassage, actualOpeningPassage); + + File file = getValidFile(fileName); + file.delete(); + } + + @ParameterizedTest (name = "{index}. File name: {0}") + @ValueSource (strings = {"Winnie the Pooh", "L.O.T.R", "The-Bible", "Story123"}) + void saves_all_the_links_of_passage_correctly(String fileName) throws IOException, InstantiationException { + Story story = validStory(); + List<Link> expectedOpeningPassageLinks = story.getOpeningPassage().getLinks(); + + storyFileHandler.createStoryFile(story, fileName); + Story storyReadFromFile = storyFileHandler.readStoryFromFile(fileName); + List<Link> actualOpeningPassageLinks = storyReadFromFile.getOpeningPassage().getLinks(); + + Assertions.assertEquals(expectedOpeningPassageLinks, actualOpeningPassageLinks); + + File file = getValidFile(fileName); + file.delete(); + } + + @ParameterizedTest (name = "{index}. File name: {0}") + @ValueSource (strings = {"Winnie the Pooh", "L.O.T.R", "The-Bible", "Story123"}) + void saves_all_the_actions_of_links_correctly(String fileName) throws IOException, InstantiationException { + Story story = validStory(); + List<Action<?>> expectedOpeningPassageActions = story.getOpeningPassage().getLinks().get(0).getActions(); + + storyFileHandler.createStoryFile(story, fileName); + Story storyReadFromFile = storyFileHandler.readStoryFromFile(fileName); + List<Action<?>> actualOpeningPassageActions = storyReadFromFile.getOpeningPassage().getLinks().get(0).getActions(); + + Assertions.assertEquals(expectedOpeningPassageActions, actualOpeningPassageActions); + + File file = getValidFile(fileName); + file.delete(); + } + + } + + @Nested + public class A_StoryFile_properly_reads_a_story_if_it { + @Test + void constructs_a_Story_correctly_when_read() throws IOException, InstantiationException { + Story expectedStory = validStory(); + + Story actualStory = storyFileHandler.readStoryFromFile("The Hobbit"); + + assertEquals(expectedStory, actualStory); + } + + } + + @Nested + public class A_StoryFile_with_invalid_information_such_as { + @Test + void a_null_story_when_creating_new_file_will_throw_NullPointerException(){ + Story story = null; + + Assertions.assertThrows(NullPointerException.class, () ->{ + storyFileHandler.createStoryFile(story, "Null story test"); + }); + } + + @Test + void a_null_file_name_when_creating_new_file_will_throw_NullPointerException(){ + Story story = validStory(); + + Assertions.assertThrows(NullPointerException.class, () ->{ + storyFileHandler.createStoryFile(story, null); + }); + } + + @Test + void a_null_file_name_when_reading_file_will_throw_NullPointerException(){ + Assertions.assertThrows(NullPointerException.class, () ->{ + Story story = storyFileHandler.readStoryFromFile(null); + }); + } + + //TODO: change this actually test the link information + @Test + void corrupt_link_information_throws_CorruptLinkException_when_read(){ + Story expectedStory = validStory(); + + Assertions.assertThrows(CorruptLinkException.class, () -> { + Story actualStory = storyFileHandler.readStoryFromFile("Corrupt Link File"); + assertNotEquals(expectedStory, actualStory); + }); + + } + + @Test + void file_with_improper_format_throws_CorruptFileException() { + Story expectedStory = validStory(); + + Assertions.assertThrows(CorruptFileException.class, () ->{ + Story actualStory = storyFileHandler.readStoryFromFile("Corrupt .paths Format"); + }); + } + + @Test + void not_existing_throws_IllegalArgumentException() { + Story expectedStory = validStory(); + + Assertions.assertThrows(IllegalArgumentException.class, () ->{ + Story actualStory = storyFileHandler.readStoryFromFile("File that does not exist"); + }); + } + + @Test + void action_class_throws_InstantiationException() { + Story expectedStory = validStory(); + + Assertions.assertThrows(InstantiationException.class, () -> { + Story actualStory = storyFileHandler.readStoryFromFile("Corrupt Action Class"); + }); + } + + @Test + void corrupt_action_format_throws_CorruptLinkException() { + Story expectedStory = validStory(); + + Assertions.assertThrows(CorruptLinkException.class, () -> { + Story actualStory = storyFileHandler.readStoryFromFile("Corrupt Action"); + }); + } + + @Test + void valid_action_class_but_invalid_value_throws_IllegalArgumentException() { + Story expectedStory = validStory(); + + Assertions.assertThrows(IllegalArgumentException.class, () -> { + Story actualStory = storyFileHandler.readStoryFromFile("Corrupt Action Value"); + }); + } + + } + +} diff --git a/src/test/resources/storytestfiles/Bones.paths b/src/test/resources/storytestfiles/Bones.paths new file mode 100644 index 0000000000000000000000000000000000000000..59af36f46e6ff1e582aa3b0cf503a5ec7b374fe2 --- /dev/null +++ b/src/test/resources/storytestfiles/Bones.paths @@ -0,0 +1,10 @@ +Haunted House + +::Beginnings +You are in a small, dimly lit room. There is a door in front of you. +[Try to open the door](Another room) + +::Another room +The door opens to another room. You see a desk with a large, dusty book. +[Open the book](The book of spells) +[Go back](Beginnings) \ No newline at end of file diff --git a/src/test/resources/storytestfiles/Corrupt .paths Format.paths b/src/test/resources/storytestfiles/Corrupt .paths Format.paths new file mode 100644 index 0000000000000000000000000000000000000000..021a79ea01300abbaa023777a96d089b858f828d --- /dev/null +++ b/src/test/resources/storytestfiles/Corrupt .paths Format.paths @@ -0,0 +1,4 @@ +Title goes here + +Passage not starting with two colons +Content of passage here diff --git a/src/test/resources/storytestfiles/Corrupt Action Class.paths b/src/test/resources/storytestfiles/Corrupt Action Class.paths new file mode 100644 index 0000000000000000000000000000000000000000..96b396b42e4749e2ca01f270b2cba5e6eb9b267f --- /dev/null +++ b/src/test/resources/storytestfiles/Corrupt Action Class.paths @@ -0,0 +1,9 @@ +The Hobbit + +::Beginning +Once upon a time... +[The Great Barrier](The Great Barrier) +<Invalid class>\5/ + +::The Great Barrier +After having completed the arduous... \ No newline at end of file diff --git a/src/test/resources/storytestfiles/Corrupt Action Value.paths b/src/test/resources/storytestfiles/Corrupt Action Value.paths new file mode 100644 index 0000000000000000000000000000000000000000..a51c2c4785bea1fc13283626a0f7bb8548ff69bd --- /dev/null +++ b/src/test/resources/storytestfiles/Corrupt Action Value.paths @@ -0,0 +1,10 @@ +The Hobbit + +::Beginning +Once upon a time... +[The Great Barrier](The Great Barrier) +<GoldAction>\Hello/ + +::The Great Barrier +After having completed the arduous... + diff --git a/src/test/resources/storytestfiles/Corrupt Action.paths b/src/test/resources/storytestfiles/Corrupt Action.paths new file mode 100644 index 0000000000000000000000000000000000000000..2998dbd99aac7b747ffb0a6ccebe3af09f258bdf --- /dev/null +++ b/src/test/resources/storytestfiles/Corrupt Action.paths @@ -0,0 +1,10 @@ +The Hobbit + +::Beginning +Once upon a time... +[The Great Barrier](The Great Barrier) +-GoldAction-\5/ + +::The Great Barrier +After having completed the arduous... + diff --git a/src/test/resources/storytestfiles/Corrupt Link File.paths b/src/test/resources/storytestfiles/Corrupt Link File.paths new file mode 100644 index 0000000000000000000000000000000000000000..b65dac173633e19696a487ee38ba793560a9aa93 --- /dev/null +++ b/src/test/resources/storytestfiles/Corrupt Link File.paths @@ -0,0 +1,5 @@ +The Hobbit + +::Beginning +Once upon a time... +[link name (broken because of no end bracket) \ No newline at end of file diff --git a/src/test/resources/storytestfiles/The Hobbit.paths b/src/test/resources/storytestfiles/The Hobbit.paths new file mode 100644 index 0000000000000000000000000000000000000000..51531969e0ba640f31514f0485bf262f1d2b2502 --- /dev/null +++ b/src/test/resources/storytestfiles/The Hobbit.paths @@ -0,0 +1,13 @@ +The Hobbit + +::Beginning +Once upon a time... +[The Great Barrier](The Great Barrier) +<GoldAction>\5/ +<ScoreAction>\5/ +<HealthAction>\6/ +<InventoryAction>\Sword/ + +::The Great Barrier +After having completed the arduous... +