args;
+ try {
+ commandAndArgument = splitCommandTerm(userInput);
+ } catch (IncompleteCommandException e) {
+ return new IncorrectCommand(MISSING_COMMAND_WORD_DELIMITER_MESSAGE);
+ }
+
+ // only arguments is trimmed because commandWord is split on the first space
+ String commandWord = commandAndArgument.get(0);
+ String arguments = commandAndArgument.get(1);
+ if (arguments != null) {
+ arguments = arguments.trim();
+ }
+
+ switch (commandWord) {
+ case AddCommand.COMMAND_WORD:
+ try {
+ args = extractArguments(arguments);
+ return new AddCommand(args);
+ } catch (IncompleteCommandException e) {
+ return new IncorrectCommand(AddCommand.COMMAND_WORD + AddCommand.COMMAND_DESCRIPTION);
+ } catch (NumberFormatException e) {
+ return new IncorrectCommand(Command.INCORRECT_COST_FORMAT);
+ } catch (IllegalArgumentException e) {
+ return new IncorrectCommand(Command.INCORRECT_ENUM_TYPE);
+ } catch (MissingAttributeException e) {
+ return new IncorrectCommand(e.getMessage()
+ + System.lineSeparator()
+ + AddCommand.COMMAND_WORD
+ + AddCommand.COMMAND_DESCRIPTION);
+ } catch (DateTimeParseException e) {
+ return new IncorrectCommand(Command.INVALID_DATE_MESSAGE);
+ }
+ case CheckCommand.COMMAND_WORD:
+ try {
+ args = prepareCheck(arguments);
+ return new CheckCommand(args);
+ } catch (IncompleteCommandException e) {
+ return new IncorrectCommand(CheckCommand.COMMAND_WORD + CheckCommand.COMMAND_DESCRIPTION);
+ }
+ case DeleteCommand.COMMAND_WORD:
+ try {
+ args = prepareDelete(arguments);
+ return new DeleteCommand(args);
+ } catch (IncompleteCommandException e) {
+ return new IncorrectCommand(DeleteCommand.COMMAND_WORD + DeleteCommand.COMMAND_DESCRIPTION);
+ }
+ case UpdateCommand.COMMAND_WORD:
+ try {
+ args = extractArguments(arguments);
+ return new UpdateCommand(args);
+ } catch (IncompleteCommandException e) {
+ return new IncorrectCommand(UpdateCommand.COMMAND_WORD + UpdateCommand.COMMAND_DESCRIPTION);
+ } catch (NumberFormatException e) {
+ return new IncorrectCommand(Command.INCORRECT_COST_FORMAT);
+ } catch (IllegalArgumentException e) {
+ return new IncorrectCommand(Command.INCORRECT_ENUM_TYPE);
+ } catch (DateTimeParseException e) {
+ return new IncorrectCommand(Command.INVALID_DATE_MESSAGE);
+ }
+ case ListCommand.COMMAND_WORD:
+ return new ListCommand();
+ case HelpCommand.COMMAND_WORD:
+ return new HelpCommand();
+ case SaveCommand.COMMAND_WORD:
+ return new SaveCommand();
+ case ByeCommand.COMMAND_WORD:
+ return new ByeCommand();
+ default:
+ return new IncorrectCommand(UNRECOGNISED_COMMAND_MESSAGE);
+ }
+
+ }
+
+ /**
+ * Break down a command into the command term to be parsed and the remainder of the arguments.
+ * Assumes command term and remainder arguments are delimited by minimally one space.
+ *
+ * If first element is list, help, save or bye,
+ * remainder arguments can be empty, in which case a null second object will be passed in.
+ * If there exists a second element in such a case, it is split as per normal, but it will be ignored in
+ * {@link Parser#parseCommand(String)}.
+ *
+ * @param userInput String to be split into substrings
+ * @return ArrayList of 2 String, first element command term and second element arguments
+ * @throws IncompleteCommandException if no space is found
+ */
+ public ArrayList splitCommandTerm(String userInput) throws IncompleteCommandException {
+ ArrayList resultArrayList = new ArrayList<>();
+ userInput = userInput.trim();
+
+ // Checks for list/help/save/bye command word first
+ switch (userInput.toLowerCase(Locale.ROOT)) {
+ case ListCommand.COMMAND_WORD:
+ resultArrayList.add(ListCommand.COMMAND_WORD);
+ resultArrayList.add(null);
+ return resultArrayList;
+ case HelpCommand.COMMAND_WORD:
+ resultArrayList.add(HelpCommand.COMMAND_WORD);
+ resultArrayList.add(null);
+ return resultArrayList;
+ case SaveCommand.COMMAND_WORD:
+ resultArrayList.add(SaveCommand.COMMAND_WORD);
+ resultArrayList.add(null);
+ return resultArrayList;
+ case ByeCommand.COMMAND_WORD:
+ resultArrayList.add(ByeCommand.COMMAND_WORD);
+ resultArrayList.add(null);
+ return resultArrayList;
+ default:
+ break;
+ }
+
+ // Match terms against syntax
+ final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput);
+ // Guard against no match
+ if (!matcher.matches()) {
+ throw new IncompleteCommandException("Could not find space delimiter between command and arguments!");
+ }
+ // Match and return ArrayList appropriately
+ resultArrayList.add(matcher.group("commandWord").toLowerCase(Locale.ROOT));
+ resultArrayList.add(matcher.group("arguments"));
+ return resultArrayList;
+ }
+
+ /**
+ * Prepare argument for CheckCommand by matching the preceding "n/" prefix, setting the prefix to lowercase,
+ * remove backticks and verifying that there are no additional tags.
+ *
+ * @param args String to be split into substrings
+ * @return ArrayList of one element (assumes rest of string is item name)
+ * @throws IncompleteCommandException if no match found
+ */
+ protected ArrayList prepareCheck(String args) throws IncompleteCommandException {
+ final Matcher matcher = CHECK_COMMAND_FORMAT.matcher(args);
+ if (!matcher.matches()) {
+ throw new IncompleteCommandException("Check command values are incomplete or missing!");
+ }
+ String argumentPair = reformatArgumentPair(matcher.group("itemName"));
+ return new ArrayList<>(Collections.singleton(argumentPair));
+ }
+
+ /**
+ * Prepare argument for DeleteCommand by matching the preceding "s/" prefix, setting the prefix to lowercase,
+ * remove backticks and verifying that there are no additional tags.
+ *
+ * @param args String to be split into substrings
+ * @return ArrayList of one element (assumes rest of string is serial number)
+ * @throws IncompleteCommandException if no match found
+ */
+ protected ArrayList prepareDelete(String args) throws IncompleteCommandException {
+ final Matcher matcher = DELETE_COMMAND_FORMAT.matcher(args);
+ if (!matcher.matches()) {
+ throw new IncompleteCommandException("Delete command values are incomplete or missing!");
+ }
+ String argumentPair = reformatArgumentPair(matcher.group("serialNumber"));
+ return new ArrayList<>(Collections.singleton(argumentPair));
+ }
+
+ /**
+ * Splits main arguments into split tags with each substring by setting the prefix to lowercase
+ * and removing backticks.
+ *
+ * @param args String to be split into substrings
+ * @return ArrayList of two elements
+ * @throws IncompleteCommandException if no parameters found
+ */
+ protected ArrayList extractArguments(String args) throws IncompleteCommandException {
+ int lastIndex = 0;
+ String argumentToAdd;
+ String argument;
+ ArrayList splitArguments = new ArrayList<>();
+ try {
+ Matcher matcher = MODIFICATION_ARGUMENT_FORMAT.matcher(args);
+ while (matcher.find()) {
+ argument = matcher.group();
+ argumentToAdd = reformatArgumentPair(argument.trim());
+ splitArguments.add(argumentToAdd);
+ lastIndex = matcher.end();
+ }
+ matcher.usePattern(MODIFICATION_ARGUMENT_TRAILING_FORMAT);
+ matcher.find(lastIndex);
+ argument = matcher.group();
+ argumentToAdd = reformatArgumentPair(argument.trim());
+ splitArguments.add(argumentToAdd);
+ } catch (IllegalStateException e) {
+ throw new IncompleteCommandException(IncompleteCommandException.NO_PARAMETERS_FOUND);
+ }
+
+ return splitArguments;
+ }
+
+ private static String reformatArgumentPair(String argument) {
+ int slashIndex = argument.indexOf("/");
+ String newString = argument.substring(0, slashIndex).toLowerCase(Locale.ROOT) + argument.substring(slashIndex);
+ return newString.replace("`", "");
+ }
+
+}
diff --git a/src/main/java/seedu/storage/LocalDateAdapter.java b/src/main/java/seedu/storage/LocalDateAdapter.java
new file mode 100644
index 0000000000..6f4a1ed389
--- /dev/null
+++ b/src/main/java/seedu/storage/LocalDateAdapter.java
@@ -0,0 +1,44 @@
+package seedu.storage;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+
+import java.io.IOException;
+import java.time.LocalDate;
+
+class LocalDateAdapter extends TypeAdapter {
+ /**
+ * Write a LocalDate to a JsonWriter.
+ * Source: https://stackoverflow.com/questions/39192945/serialize-java-8-localdate-as-yyyy-mm-dd-with-gson
+ * @param jsonWriter the JsonWriter to write to.
+ * @param localDate the LocalDate to write.
+ * @throws IOException if an error occurs while writing.
+ */
+ @Override
+ public void write(final JsonWriter jsonWriter, final LocalDate localDate) throws IOException {
+ if (localDate == null) {
+ jsonWriter.nullValue();
+ } else {
+ jsonWriter.value(localDate.toString());
+ }
+ }
+
+ /**
+ * Read a LocalDate from a JsonReader.
+ * Source: https://stackoverflow.com/questions/39192945/serialize-java-8-localdate-as-yyyy-mm-dd-with-gson
+ * @param jsonReader the JsonReader to read from.
+ * @return the LocalDate read.
+ * @throws IOException if an error occurs while reading.
+ */
+ @Override
+ public LocalDate read(final JsonReader jsonReader) throws IOException {
+ if (jsonReader.peek() == JsonToken.NULL) {
+ jsonReader.nextNull();
+ return null;
+ } else {
+ return LocalDate.parse(jsonReader.nextString());
+ }
+ }
+}
diff --git a/src/main/java/seedu/storage/Storage.java b/src/main/java/seedu/storage/Storage.java
new file mode 100644
index 0000000000..ed2feeeb4e
--- /dev/null
+++ b/src/main/java/seedu/storage/Storage.java
@@ -0,0 +1,72 @@
+package seedu.storage;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.reflect.TypeToken;
+import seedu.equipment.DuplicateSerialNumberException;
+import seedu.equipment.Equipment;
+import seedu.equipment.EquipmentManager;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class Storage {
+ public static final String FILE_NOT_FOUND_ERROR_MESSAGE = "Save file not found: "
+ + "a new file will be created after this session.";
+ public static final String SAVE_ERROR_MESSAGE = "An error occurred while saving!";
+ public static final String DUPLICATE_SERIAL_NUMBER_ERROR = "Duplicate serial number found!";
+ public static final String path = "./equipments.json";
+ private static final String EMPTY_FILE_ERROR_MESSAGE = "File is empty. Added Equipments will be saved in the file.";
+ private static final String INVALID_DATE_ERROR_MESSAGE = "Invalid date format found in the file. "
+ + "Please check the file and try again. Do not proceed unless you want to rewrite the file.";
+ private final Gson gson = new GsonBuilder()
+ .setPrettyPrinting()
+ .registerTypeAdapter(LocalDate.class, new LocalDateAdapter())
+ .create();
+
+ /**
+ * Loads data from ./equipments.json
+ *
+ * @param equipmentManager EquipmentManager object to put all the Equipments in ./equipments.json.
+ */
+ public void loadData(EquipmentManager equipmentManager) {
+ try {
+ Reader reader = Files.newBufferedReader(Path.of(path));
+ List equipments = gson.fromJson(reader, new TypeToken>() {}.getType());
+ for (Equipment equipment : equipments) {
+ equipmentManager.addEquipment(equipment);
+ }
+ } catch (IOException e) {
+ System.out.println(FILE_NOT_FOUND_ERROR_MESSAGE);
+ } catch (DuplicateSerialNumberException e) {
+ System.out.println(DUPLICATE_SERIAL_NUMBER_ERROR);
+ } catch (NullPointerException e) {
+ System.out.println(EMPTY_FILE_ERROR_MESSAGE);
+ } catch (DateTimeException e) {
+ System.out.println(INVALID_DATE_ERROR_MESSAGE);
+ }
+ }
+
+ /**
+ * Saves the Equipments in equipmentManager into a json file.
+ *
+ * @param equipmentManager EquipmentManager object with Equipments that will be saved to the json file.
+ */
+ public void saveData(EquipmentManager equipmentManager) {
+ List equipments = new ArrayList<>(equipmentManager.getEquipmentList().values());
+ try {
+ Writer writer = Files.newBufferedWriter(Path.of(path));
+ gson.toJson(equipments, writer);
+ writer.close();
+ } catch (IOException e) {
+ System.out.println(SAVE_ERROR_MESSAGE);
+ }
+ }
+}
diff --git a/src/main/java/seedu/ui/TextUi.java b/src/main/java/seedu/ui/TextUi.java
new file mode 100644
index 0000000000..34275719da
--- /dev/null
+++ b/src/main/java/seedu/ui/TextUi.java
@@ -0,0 +1,44 @@
+package seedu.ui;
+
+import seedu.command.CommandResult;
+import seedu.equipment.Equipment;
+
+/**
+ * Text UI for the application, referenced from
+ * https://github.com/se-edu/addressbook-level2/blob/master/src/seedu/addressbook/ui/TextUi.java
+ */
+public class TextUi {
+ private static final String LOGO = " _ _"
+ + " \n"
+ + " (_) | | \n"
+ + " ___ __ _ _ _ _ _ __ _ __ ___ ___ _ __ | |_ _ __ ___ __ _ _ __ __ _ __ _ ___ _ __ \n"
+ + " / _ \\/ _` | | | | | '_ \\| '_ ` _ \\ / _ \\ '_ \\| __| '_ ` _ \\ / _` "
+ + "| '_ \\ / _` |/ _` |/ _ \\ '__|\n"
+ + " | __/ (_| | |_| | | |_) | | | | | | __/ | | | |_| | | | | | (_| | | | | (_| | (_| | __/ | \n"
+ + " \\___|\\__, |\\__,_|_| .__/|_| |_| |_|\\___|_| "
+ + "|_|\\__|_| |_| |_|\\__,_|_| |_|\\__,_|\\__, |\\___|_| \n"
+ + " | | | | __/ | \n"
+ + " |_| |_| |___/";
+
+ public void showWelcomeMessage() {
+ System.out.println("Hello from" + System.lineSeparator() + LOGO);
+ System.out.println("What do you want to do? Enter `help` to see what you can do.");
+ }
+
+ /**
+ * Shows the result of command execution to user.
+ * @param result CommandResult returned from the execution of a command.
+ */
+ public void showResultToUser(CommandResult result) {
+ System.out.println(result.getResultToShow());
+ int indexShown = 1;
+ if (result.getRelevantEquipment() != null) {
+ for (Equipment equipment : result.getRelevantEquipment()) {
+ System.out.print(indexShown + ". ");
+ System.out.println(equipment);
+ indexShown++;
+ }
+ }
+ }
+
+}
diff --git a/src/test/java/seedu/command/AddCommandTest.java b/src/test/java/seedu/command/AddCommandTest.java
new file mode 100644
index 0000000000..c4d3a1491b
--- /dev/null
+++ b/src/test/java/seedu/command/AddCommandTest.java
@@ -0,0 +1,113 @@
+package seedu.command;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.equipment.DuplicateSerialNumberException;
+import seedu.equipment.Equipment;
+import seedu.equipment.EquipmentManager;
+import seedu.equipment.EquipmentType;
+import seedu.parser.IncompleteCommandException;
+import seedu.parser.MissingAttributeException;
+import seedu.parser.Parser;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+
+class AddCommandTest {
+ AddCommand addCommand;
+ ArrayList userInput = new ArrayList<>(
+ Arrays.asList(
+ "n/Speaker B",
+ "s/S1404115ASF",
+ "t/SPEAKER",
+ "c/1000",
+ "pf/Loud Technologies",
+ "pd/2022-02-23")
+ );
+
+ @Test
+ void execute_duplicateSerialNumber_exceptionThrown() throws DuplicateSerialNumberException,
+ MissingAttributeException {
+ addCommand = new AddCommand(userInput);
+ addCommand.setEquipmentManager(new EquipmentManager());
+ EquipmentManager equipmentManager = addCommand.equipmentManager;
+ equipmentManager.addEquipment("Speaker B",
+ "S1404115ASF",
+ EquipmentType.valueOf("SPEAKER"),
+ 1000,
+ "Loud Technologies",
+ LocalDate.parse("2022-02-23"));
+
+ CommandResult expectedResult =
+ new CommandResult("There is already an item with this serial number: S1404115ASF");
+ CommandResult actualResult = addCommand.execute();
+ assertEquals(expectedResult, actualResult);
+ }
+
+ @Test
+ void execute_incorrectCostFormat_exceptionThrown() {
+ assertThrows(NumberFormatException.class, () -> new AddCommand(new ArrayList<>(
+ Arrays.asList("n/Speaker B",
+ "s/S1404115ASF",
+ "t/SPEAKER",
+ "c/$1000",
+ "pf/Loud Technologies",
+ "pd/2022-02-23")
+ )));
+ }
+
+ @Test
+ void execute_incorrectEnumType_exceptionThrown() {
+ assertThrows(IllegalArgumentException.class, () -> new AddCommand(new ArrayList<>(
+ Arrays.asList("n/Speaker B",
+ "s/S1404115ASF",
+ "t/SPEAKERS",
+ "c/1000",
+ "pf/Loud Technologies",
+ "pd/2022-02-23")
+ )));
+ }
+
+ @Test
+ void addEquipment_validArrayListString_success() throws DuplicateSerialNumberException, MissingAttributeException {
+ addCommand = new AddCommand(userInput);
+ addCommand.setEquipmentManager(new EquipmentManager());
+ EquipmentManager equipmentManager = addCommand.equipmentManager;
+ int equipmentListOriginalSize = equipmentManager.getEquipmentList().size();
+ Equipment expectedEquipment = new Equipment("Speaker B",
+ "S1404115ASF",
+ EquipmentType.valueOf("SPEAKER"),
+ 1000,
+ "Loud Technologies",
+ LocalDate.parse("2022-02-23"));
+
+ addCommand.addEquipment(userInput);
+ Equipment actualEquipment = equipmentManager.listEquipment().get(equipmentListOriginalSize);
+
+ assertEquals(equipmentListOriginalSize + 1, equipmentManager.getEquipmentList().size());
+ assertEquals(expectedEquipment, actualEquipment);
+ }
+
+ @Test
+ void checkAttributes_allAttributesSet_true() throws MissingAttributeException {
+ addCommand = new AddCommand(userInput);
+ boolean actualResult = addCommand.checkAttributes();
+
+ assertTrue(actualResult);
+ }
+
+ @Test
+ void checkAttributes_oneOrMoreNulls_false_exceptionThrown() {
+ assertThrows(MissingAttributeException.class, () -> new AddCommand(new ArrayList<>(
+ Arrays.asList("n/Speaker B", "s/S1404115ASF", "t/SPEAKER", "pf/Loud Technologies")
+ )));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/seedu/command/CheckCommandTest.java b/src/test/java/seedu/command/CheckCommandTest.java
new file mode 100644
index 0000000000..c37b630546
--- /dev/null
+++ b/src/test/java/seedu/command/CheckCommandTest.java
@@ -0,0 +1,87 @@
+package seedu.command;
+
+import org.junit.jupiter.api.Test;
+import seedu.equipment.DuplicateSerialNumberException;
+import seedu.equipment.Equipment;
+import seedu.equipment.EquipmentManager;
+import seedu.equipment.EquipmentType;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+class CheckCommandTest {
+ CheckCommand checkCommand;
+
+ @Test
+ void execute_validEquipmentName_success() {
+ checkCommand = new CheckCommand(new ArrayList<>(
+ Arrays.asList("n/Speaker B")
+ ));
+ checkCommand.setEquipmentManager(new EquipmentManager());
+ EquipmentManager equipmentManager = checkCommand.equipmentManager;
+ try {
+ equipmentManager.addEquipment("Speaker B",
+ "S1404115ASF",
+ EquipmentType.valueOf("SPEAKER"),
+ 1000,
+ "Loud Technologies",
+ LocalDate.parse("2022-02-23"));
+ } catch (DuplicateSerialNumberException e) {
+ fail();
+ }
+
+ ArrayList listOfEquipments = new ArrayList<>();
+ for (Equipment equipment : equipmentManager.getEquipmentList().values()) {
+ if (equipment.getItemName().equals("Speaker B")) {
+ listOfEquipments.add(equipment);
+ }
+ }
+
+ CommandResult actualResult = checkCommand.execute();
+ CommandResult expectedResult = new CommandResult(
+ "Here are the equipment matching to 'n/Speaker B':" + System.lineSeparator(),
+ listOfEquipments);
+
+ assertEquals(expectedResult, actualResult);
+ }
+
+ @Test
+ void execute_invalidEquipmentType_fail() {
+ checkCommand = new CheckCommand(new ArrayList<>(
+ Arrays.asList("t/hello")
+ ));
+
+ CommandResult actualResult = checkCommand.execute();
+ CommandResult expectedResult = new CommandResult(Command.INCORRECT_ENUM_TYPE);
+
+ assertEquals(expectedResult, actualResult);
+ }
+
+ @Test
+ void execute_invalidCost_fail() {
+ checkCommand = new CheckCommand(new ArrayList<>(
+ Arrays.asList("c/something")
+ ));
+
+ CommandResult actualResult = checkCommand.execute();
+ CommandResult expectedResult = new CommandResult(Command.INCORRECT_COST_FORMAT);
+
+ assertEquals(expectedResult, actualResult);
+ }
+
+ @Test
+ void execute_invalidDateFormat_fail() {
+ checkCommand = new CheckCommand(new ArrayList<>(
+ Arrays.asList("pd/2022")
+ ));
+
+ CommandResult actualResult = checkCommand.execute();
+ CommandResult expectedResult = new CommandResult(Command.INVALID_DATE_MESSAGE);
+
+ assertEquals(expectedResult, actualResult);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/seedu/command/DeleteCommandTest.java b/src/test/java/seedu/command/DeleteCommandTest.java
new file mode 100644
index 0000000000..480cef625f
--- /dev/null
+++ b/src/test/java/seedu/command/DeleteCommandTest.java
@@ -0,0 +1,74 @@
+package seedu.command;
+
+import org.junit.jupiter.api.Test;
+import seedu.equipment.DuplicateSerialNumberException;
+import seedu.equipment.EquipmentManager;
+import seedu.equipment.EquipmentType;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+import static seedu.command.DeleteCommand.ONLY_SN_ACCEPTED;
+
+class DeleteCommandTest {
+ DeleteCommand deleteCommand;
+
+ @Test
+ void execute_validSerialNumber_success() {
+ deleteCommand = new DeleteCommand(new ArrayList<>(
+ Arrays.asList("s/S1404115ASF")
+ ));
+ deleteCommand.setEquipmentManager(new EquipmentManager());
+ EquipmentManager equipmentManager = deleteCommand.equipmentManager;
+ try {
+ equipmentManager.addEquipment("Speaker B",
+ "S1404115ASF",
+ EquipmentType.valueOf("SPEAKER"),
+ 1000,
+ "Loud Technologies",
+ LocalDate.parse("2022-02-23"));
+ } catch (DuplicateSerialNumberException e) {
+ fail();
+ }
+
+ int equipmentListSize = equipmentManager.getEquipmentList().size();
+ assertEquals(1, equipmentListSize);
+
+ CommandResult actualResult = deleteCommand.execute();
+ CommandResult expectedResult =
+ new CommandResult("Equipment successfully deleted: Speaker B, serial number S1404115ASF");
+
+ assertEquals(expectedResult, actualResult);
+ }
+
+ @Test
+ void execute_invalidSerialNumber_fail() {
+ deleteCommand = new DeleteCommand(new ArrayList<>(
+ Arrays.asList("s/S123445ASF")
+ ));
+ deleteCommand.setEquipmentManager(new EquipmentManager());
+
+ CommandResult actualResult = deleteCommand.execute();
+ CommandResult expectedResult =
+ new CommandResult(Command.INVALID_SERIAL_NUMBER);
+
+ assertEquals(expectedResult, actualResult);
+ }
+
+ @Test
+ void execute_notSerialNumber_fail() {
+ deleteCommand = new DeleteCommand(new ArrayList<>(
+ Arrays.asList("n/Speaker3")
+ ));
+ deleteCommand.setEquipmentManager(new EquipmentManager());
+
+ CommandResult actualResult = deleteCommand.execute();
+ CommandResult expectedResult =
+ new CommandResult(ONLY_SN_ACCEPTED);
+
+ assertEquals(expectedResult, actualResult);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/seedu/command/ListCommandTest.java b/src/test/java/seedu/command/ListCommandTest.java
new file mode 100644
index 0000000000..ea43d01a66
--- /dev/null
+++ b/src/test/java/seedu/command/ListCommandTest.java
@@ -0,0 +1,40 @@
+package seedu.command;
+
+import org.junit.jupiter.api.Test;
+import seedu.equipment.DuplicateSerialNumberException;
+import seedu.equipment.EquipmentManager;
+import seedu.equipment.EquipmentType;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+class ListCommandTest {
+ ListCommand listCommand;
+
+ @Test
+ void execute_noSpecifiedType_success() {
+ listCommand = new ListCommand();
+ listCommand.setEquipmentManager(new EquipmentManager());
+ EquipmentManager equipmentManager = listCommand.equipmentManager;
+ try {
+ equipmentManager.addEquipment("Speaker B",
+ "S1404115ASF",
+ EquipmentType.valueOf("SPEAKER"),
+ 1000,
+ "Loud Technologies",
+ LocalDate.parse("2022-02-23"));
+ } catch (DuplicateSerialNumberException e) {
+ fail();
+ }
+
+ CommandResult actualResult = listCommand.execute();
+ CommandResult expectedResult = new CommandResult("TOTAL QUANTITY OF EQUIPMENT: 1" + System.lineSeparator(),
+ equipmentManager.listEquipment());
+
+ assertEquals(expectedResult, actualResult);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/seedu/command/ModificationCommandTest.java b/src/test/java/seedu/command/ModificationCommandTest.java
new file mode 100644
index 0000000000..51876a64d6
--- /dev/null
+++ b/src/test/java/seedu/command/ModificationCommandTest.java
@@ -0,0 +1,63 @@
+package seedu.command;
+
+import org.junit.jupiter.api.Test;
+import seedu.parser.IncompleteCommandException;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class ModificationCommandTest {
+ ModificationCommand modificationCommand;
+
+ @Test
+ void prepareModification_missingSlashDelimiter_assertionErrorThrown() throws AssertionError {
+ ArrayList testArrayList = new ArrayList<>(Collections.singleton("thiswillnotwork"));
+ try {
+ modificationCommand = new ModificationCommand(testArrayList);
+ modificationCommand.prepareModification();
+ } catch (AssertionError error) {
+ assertEquals("Each args will need to include minimally a '/' to split arg and value upon",
+ error.getMessage());
+ }
+ }
+
+ @Test
+ void prepareModification_missingSerialNumber_exceptionThrown() throws IncompleteCommandException {
+ ArrayList testArrayList = new ArrayList<>(Arrays.asList(
+ "n/Speaker B", "t/SPEAKER", "c/1000", "pf/Loud Technologies", "pd/2022-02-23"));
+ UpdateCommand updateCommand = new UpdateCommand(testArrayList);
+ CommandResult expectedResult = new CommandResult("Serial Number is required to run this command");
+ assertEquals(expectedResult, updateCommand.execute());
+ }
+
+ @Test
+ void prepareModification_mostRecentArgValueUsed_success() throws IncompleteCommandException {
+ ArrayList testArrayList = new ArrayList<>(Arrays.asList(
+ "s/S1404115ASF", "n/Speaker B", "n/Speaker A"));
+ ModificationCommand expectedCommand = new ModificationCommand(new ArrayList<>(
+ Arrays.asList("s/S1404115ASF", "n/Speaker A")
+ ));
+ expectedCommand.prepareModification();
+ ModificationCommand actualCommand = new ModificationCommand(testArrayList);
+ actualCommand.prepareModification();
+ assertEquals(expectedCommand, actualCommand);
+ }
+
+ @Test
+ void prepareModification_typeEnumsChangedToCaps_success() throws IncompleteCommandException {
+ ArrayList testArrayList = new ArrayList<>(Arrays.asList(
+ "s/S1404115ASF", "t/sPEAker", "n/Speaker A"));
+ ModificationCommand expectedCommand = new ModificationCommand(new ArrayList<>(
+ Arrays.asList("s/S1404115ASF", "t/SPEAKER", "n/Speaker A")
+ ));
+ expectedCommand.prepareModification();
+ ModificationCommand actualCommand = new ModificationCommand(testArrayList);
+ expectedCommand.prepareModification();
+ actualCommand.prepareModification();
+ assertEquals(expectedCommand, actualCommand);
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/seedu/command/UpdateCommandTest.java b/src/test/java/seedu/command/UpdateCommandTest.java
new file mode 100644
index 0000000000..8fb60a67ab
--- /dev/null
+++ b/src/test/java/seedu/command/UpdateCommandTest.java
@@ -0,0 +1,68 @@
+package seedu.command;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.Pair;
+import seedu.equipment.DuplicateSerialNumberException;
+import seedu.equipment.EquipmentManager;
+import seedu.equipment.EquipmentType;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+class UpdateCommandTest {
+ EquipmentManager equipmentManager = new EquipmentManager();
+ UpdateCommand updateCommand;
+
+ @BeforeEach
+ void setup() {
+ try {
+ equipmentManager.addEquipment("Speaker B",
+ "S1404115ASF",
+ EquipmentType.valueOf("SPEAKER"),
+ 1000,
+ "Loud Technologies",
+ LocalDate.parse("2022-02-23"));
+ } catch (DuplicateSerialNumberException e) {
+ fail();
+ }
+
+ updateCommand = new UpdateCommand(new ArrayList<>(
+ Arrays.asList("s/S1404115ASF", "n/Speaker C", "c/2000", "pd/2022-01-26")
+ ));
+ updateCommand.setEquipmentManager(equipmentManager);
+ }
+
+ @Test
+ void execute_validSerialNumber_success() {
+ CommandResult expectedResult = new CommandResult("Equipment successfully updated for serial number S1404115ASF,"
+ + System.lineSeparator()
+ + "Updated details are: "
+ + System.lineSeparator()
+ + "New name: Speaker C"
+ + System.lineSeparator()
+ + "New cost: 2000.0"
+ + System.lineSeparator()
+ + "New purchase date: 2022-01-26");
+
+ CommandResult actualResult = updateCommand.execute();
+
+ assertEquals(expectedResult, actualResult);
+ }
+
+ @Test
+ void generateUpdatePairs_nonNullUpdates_success() {
+ ArrayList> expectedResult = new ArrayList<>();
+ expectedResult.add(new Pair<>("itemName", "Speaker C"));
+ expectedResult.add(new Pair<>("cost", 2000.0));
+ expectedResult.add(new Pair<>("purchasedDate", LocalDate.parse("2022-01-26")));
+
+ ArrayList> actualResult = updateCommand.generateUpdatePairs();
+
+ assertEquals(expectedResult, actualResult);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/seedu/equipment/EquipmentManagerTest.java b/src/test/java/seedu/equipment/EquipmentManagerTest.java
new file mode 100644
index 0000000000..47ef843a9d
--- /dev/null
+++ b/src/test/java/seedu/equipment/EquipmentManagerTest.java
@@ -0,0 +1,51 @@
+package seedu.equipment;
+
+import org.junit.jupiter.api.Test;
+import seedu.Pair;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+public class EquipmentManagerTest {
+ @Test
+ public void updateEquipment_success() throws DuplicateSerialNumberException {
+ EquipmentManager equipmentManager = new EquipmentManager();
+ equipmentManager.addEquipment("Speaker B",
+ "S1404115ASF",
+ EquipmentType.valueOf("SPEAKER"),
+ 1000,
+ "Loud Technologies",
+ LocalDate.parse("2022-02-23"));
+ ArrayList> updates = new ArrayList<>();
+ updates.add(new Pair<>("itemName", "Speaker A"));
+ updates.add(new Pair<>("type", EquipmentType.STAND));
+ updates.add(new Pair<>("cost", 2000.0));
+ updates.add(new Pair<>("purchasedDate", LocalDate.parse("2022-03-17")));
+ updates.add(new Pair<>("purchasedFrom", "Louder Technologies"));
+ equipmentManager.updateEquipment("S1404115ASF", updates);
+ HashMap equipments = equipmentManager.getEquipmentList();
+ Equipment expectedEquipment = new Equipment("Speaker A",
+ "S1404115ASF",
+ EquipmentType.valueOf("STAND"),
+ 2000,
+ "Louder Technologies",
+ LocalDate.parse("2022-03-17"));
+ assertEquals(expectedEquipment, equipments.get("S1404115ASF".toLowerCase()));
+ }
+
+ @Test
+ public void updateEquipment_keyNotFound() {
+ ArrayList> updates = new ArrayList<>();
+ updates.add(new Pair<>("itemName", "Speaker A"));
+ updates.add(new Pair<>("type", "STAND"));
+ updates.add(new Pair<>("cost", "2000"));
+ updates.add(new Pair<>("purchaseDate", LocalDate.parse("2022-03-17")));
+ updates.add(new Pair<>("purchaseFrom", "Louder Technologies"));
+ EquipmentManager equipmentManager = new EquipmentManager();
+ assertFalse(equipmentManager.updateEquipment("WRONG SERIAL NUMBER", updates));
+ }
+}
diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java
new file mode 100644
index 0000000000..af6423b0e3
--- /dev/null
+++ b/src/test/java/seedu/parser/ParserTest.java
@@ -0,0 +1,261 @@
+package seedu.parser;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import seedu.command.AddCommand;
+import seedu.command.Command;
+import seedu.command.DeleteCommand;
+import seedu.command.IncorrectCommand;
+import seedu.command.ListCommand;
+import seedu.command.UpdateCommand;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.fail;
+
+class ParserTest {
+
+ Parser parser;
+
+ @BeforeEach
+ void setup() {
+ parser = new Parser();
+ }
+
+ @Test
+ void splitCommandTerm_validCommand_success() throws IncompleteCommandException {
+ ArrayList expectedResult = new ArrayList<>(
+ Arrays.asList("add", "n/`ITEM_NAME` s/`SERIAL_NUMBER` t/`TYPE` c/`COST` pf/`PURCHASED_FROM` "
+ + "pd/`PURCHASED_DATE`")
+ );
+ ArrayList actualResult = parser.splitCommandTerm(
+ "add n/`ITEM_NAME` s/`SERIAL_NUMBER` t/`TYPE` c/`COST` pf/`PURCHASED_FROM` "
+ + "pd/`PURCHASED_DATE`");
+ assertEquals(expectedResult, actualResult);
+ }
+
+ @Test
+ void splitCommandTerm_listCommandOnly_success() throws IncompleteCommandException {
+ ArrayList expectedResult = new ArrayList<>(
+ Arrays.asList("list", null)
+ );
+ ArrayList actualResult = parser.splitCommandTerm(
+ "list");
+ assertEquals(expectedResult, actualResult);
+ }
+
+ @Test
+ void splitCommandTerm_listCommandExtraWordsRetained_success() throws IncompleteCommandException {
+ ArrayList expectedResult = new ArrayList<>(
+ Arrays.asList("list", "t/`SPEAKER`")
+ );
+ ArrayList actualResult = parser.splitCommandTerm(
+ "list t/`SPEAKER`");
+ assertEquals(expectedResult, actualResult);
+ }
+
+ @Test
+ void splitCommandTerm_noSpaceDelimiter_exceptionThrown() {
+ ArrayList unexpectedResult = new ArrayList<>(
+ Arrays.asList("add", "n/`ITEM_NAME`s/`SERIAL_NUMBER`t/`TYPE`c/`COST`pf/`PURCHASED_FROM`"
+ + "pd/`PURCHASED_DATE`")
+ );
+ try {
+ ArrayList actualResult = parser.splitCommandTerm(
+ "addn/`ITEM_NAME`s/`SERIAL_NUMBER`t/`TYPE`c/`COST`pf/`PURCHASED_FROM`pd/`PURCHASED_DATE`");
+ assertEquals(unexpectedResult, actualResult);
+ fail();
+ } catch (IncompleteCommandException e) {
+ assertEquals("Could not find space delimiter between command and arguments!", e.getMessage());
+ }
+ }
+
+ @Test
+ void prepareCheck_viewStringWithSpaces_success() throws IncompleteCommandException {
+ ArrayList expectedResult = new ArrayList<>(
+ Arrays.asList("n/Speaker B")
+ );
+ ArrayList actualResult = parser.prepareCheck(
+ "n/`Speaker B`");
+ assertEquals(expectedResult, actualResult);
+ }
+
+ @Test
+ void prepareCheck_checkUsingSerialNum_success() throws IncompleteCommandException {
+ ArrayList expectedResult = new ArrayList<>(
+ Arrays.asList("s/Speaker B")
+ );
+ ArrayList actualResult = parser.prepareCheck(
+ "s/`Speaker B`");
+ assertEquals(expectedResult, actualResult);
+ }
+
+ @Test
+ void prepareCheck_missingFrontBackTick_exceptionThrown() {
+ ArrayList expectedResult = new ArrayList<>(
+ Arrays.asList("n/Speaker B")
+ );
+ try {
+ ArrayList actualResult = parser.prepareCheck(
+ "n/`Speaker B");
+ assertEquals(expectedResult, actualResult);
+ fail();
+ } catch (IncompleteCommandException e) {
+ assertEquals("Check command values are incomplete or missing!", e.getMessage());
+ }
+ }
+
+ @Test
+ void prepareCheck_missingBackBackTick_exceptionThrown() {
+ ArrayList expectedResult = new ArrayList<>(
+ Arrays.asList("n/Speaker B")
+ );
+ try {
+ ArrayList actualResult = parser.prepareCheck(
+ "n/Speaker B`");
+ assertEquals(expectedResult, actualResult);
+ fail();
+ } catch (IncompleteCommandException e) {
+ assertEquals("Check command values are incomplete or missing!", e.getMessage());
+ }
+ }
+
+ @Test
+ void prepareDelete_deleteStringWithSpaces_success() throws IncompleteCommandException {
+ ArrayList expectedResult = new ArrayList<>(
+ Arrays.asList("s/SM58 - 1")
+ );
+ ArrayList actualResult = parser.prepareDelete(
+ "s/`SM58 - 1`");
+ assertEquals(expectedResult, actualResult);
+ }
+
+ @Test
+ void prepareDelete_wrongArgumentTag_exceptionThrown() {
+ ArrayList expectedResult = new ArrayList<>(
+ Arrays.asList("n/Speaker B")
+ );
+ try {
+ ArrayList actualResult = parser.prepareDelete(
+ "n/Speaker B");
+ assertEquals(expectedResult, actualResult);
+ fail();
+ } catch (IncompleteCommandException e) {
+ assertEquals("Delete command values are incomplete or missing!", e.getMessage());
+ }
+ }
+
+ @Test
+ void prepareDelete_missingFrontBackTick_exceptionThrown() {
+ ArrayList expectedResult = new ArrayList<>(
+ Arrays.asList("s/Speaker B")
+ );
+ try {
+ ArrayList actualResult = parser.prepareDelete(
+ "s/`Speaker B");
+ assertEquals(expectedResult, actualResult);
+ fail();
+ } catch (IncompleteCommandException e) {
+ assertEquals("Delete command values are incomplete or missing!", e.getMessage());
+ }
+ }
+
+ @Test
+ void prepareDelete_missingBackBackTick_exceptionThrown() {
+ ArrayList expectedResult = new ArrayList<>(
+ Arrays.asList("s/Speaker B")
+ );
+ try {
+ ArrayList actualResult = parser.prepareDelete(
+ "s/Speaker B`");
+ assertEquals(expectedResult, actualResult);
+ fail();
+ } catch (IncompleteCommandException e) {
+ assertEquals("Delete command values are incomplete or missing!", e.getMessage());
+ }
+ }
+
+ @Test
+ void extractArguments_noSpaceBeforeTypeSlashDelimiterFound_exceptionThrown() {
+ ArrayList expectedResult = new ArrayList<>(Arrays.asList(
+ "n/Speaker B", "t/Speaker", "c/1000", "pf/Loud Technologies", "pd/2022-02-23"));
+ try {
+ ArrayList actualResult = parser.extractArguments(
+ "n/`Speaker B`t/`Speaker`c/`1000`pf/`Loud Technologies`pd/`2022-02-23`");
+ assertEquals(expectedResult, actualResult);
+ fail();
+ } catch (IncompleteCommandException e) {
+ assertEquals(IncompleteCommandException.NO_PARAMETERS_FOUND, e.getMessage());
+ }
+ }
+
+ @Test
+ void extractArguments_idealArgumentPairs_success() throws IncompleteCommandException {
+ ArrayList actualResult = parser.extractArguments("S/`S1404115Ax` n/`Speaker B` "
+ + "c/`1000` Pf/`Loud Technologies` PD/`2022-02-23` t/`Speaker`");
+ ArrayList expectedResult = new ArrayList<>(Arrays.asList("s/S1404115Ax",
+ "n/Speaker B", "c/1000", "pf/Loud Technologies", "pd/2022-02-23", "t/Speaker"));
+ assertEquals(actualResult, expectedResult);
+ }
+
+ @Test
+ void extractArguments_wrongArgTypesIgnored_success() throws IncompleteCommandException {
+ ArrayList actualResult = parser.extractArguments("s/`S1404115ASF` rand/`SpeakerC` "
+ + "c/`2510` name/`blahblah` pd/`2022-08-21`");
+ ArrayList expectedResult = new ArrayList<>(Arrays.asList("s/S1404115ASF",
+ "c/2510", "pd/2022-08-21"));
+ assertEquals(actualResult, expectedResult);
+ }
+
+ @Test
+ void extractArguments_noCorrectArgTypes_exceptionThrown() {
+ Throwable exception = assertThrows(IncompleteCommandException.class, () -> parser.extractArguments(
+ "x/`Speaker B` a/`Speaker` b/`1000` d/`Loud Technologies` e/`2022-02-23`"));
+ assertEquals(IncompleteCommandException.NO_PARAMETERS_FOUND, exception.getMessage());
+ }
+
+ @Test
+ void parseCommand_deleteCommand_success() {
+ Command testCommand = parser.parseCommand("delete s/`S1234567E`");
+ Command expectedCommand = new DeleteCommand(new ArrayList<>(Collections.singleton("s/S1234567E")));
+ assertEquals(expectedCommand, testCommand);
+ }
+
+ @Test
+ void parseCommand_trailingWhiteSpace_success() {
+ Command testCommand = parser.parseCommand("delete s/`S1234567E` ");
+ Command expectedCommand = new DeleteCommand(new ArrayList<>(Collections.singleton("s/S1234567E")));
+ assertEquals(expectedCommand, testCommand);
+ }
+
+ @Test
+ void parseCommand_deleteCommandWrongArgType_exceptionCaught() {
+ Command expectedCommand = new IncorrectCommand(DeleteCommand.COMMAND_WORD
+ + DeleteCommand.COMMAND_DESCRIPTION);
+ Command testCommand = parser.parseCommand("delete x/`S1234567E`");
+ assertEquals(expectedCommand, testCommand);
+ }
+
+ @Test
+ void parseCommand_updateCommandIncorrectDateFormat_exceptionCaught() {
+ Command expectedCommand = new IncorrectCommand(UpdateCommand.COMMAND_WORD
+ + UpdateCommand.COMMAND_DESCRIPTION);
+ Command testCommand = parser.parseCommand("update s/`S1234567E` pd `2022-13-23`");
+ assertEquals(expectedCommand, testCommand);
+ }
+
+ @Test
+ void parseCommand_dollarSignAccepted_exceptionThrown() throws MissingAttributeException {
+ Command testCommand = parser.parseCommand("add n/`SpeakerB` s/`S1404115ASF` t/`Speaker` c/`$200.20` "
+ + "pf/`Loud_Technologies` pd/`2022-02-23`");
+ Command expectedCommand = new IncorrectCommand(Command.INCORRECT_COST_FORMAT);
+ assertEquals(expectedCommand, testCommand);
+ }
+
+}
\ No newline at end of file