From ba089638ccbb3bcd5ee4ad5da70ef72bf30dc6bd Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Fri, 4 Mar 2022 10:09:34 +0800 Subject: [PATCH 001/229] Set theme jekyll-theme-slate --- docs/_config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/_config.yml diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000000..c741881743 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-slate \ No newline at end of file From bd2c0a106a28841304605950fcda294a29a1b8ba Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Fri, 4 Mar 2022 10:42:55 +0800 Subject: [PATCH 002/229] Edit AboutUs.md and create new personal portfolio. --- docs/AboutUs.md | 14 +++++++------- docs/team/bryanchristopher.md | 6 ++++++ 2 files changed, 13 insertions(+), 7 deletions(-) create mode 100644 docs/team/bryanchristopher.md diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..eec8fb3eff 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,9 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:----:|:--------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +Display | Name | Github Profile | Portfolio +--------|:-----------------:|:------------------------------------:|:---------: +![](https://via.placeholder.com/100.png?text=Photo) | Bryan Christopher | [Github](https://github.com/Bryan-BC) | [Portfolio](docs/team/bryanchristopher.md) +![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) diff --git a/docs/team/bryanchristopher.md b/docs/team/bryanchristopher.md new file mode 100644 index 0000000000..3d1def5983 --- /dev/null +++ b/docs/team/bryanchristopher.md @@ -0,0 +1,6 @@ +# Bryan Christopher - Project Portfolio Page + +## Overview + + +### Summary of Contributions From 5cfaf312835961fc2d5b32b8ec27c0fba930e108 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Fri, 4 Mar 2022 18:11:05 +0800 Subject: [PATCH 003/229] Add AboutUs for Shun Yao --- docs/AboutUs.md | 13 ++++++------- docs/team/shunyao.md | 6 ++++++ 2 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 docs/team/shunyao.md diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..340c3d36f6 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,8 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:----:|:--------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +Display | Name | Github Profile | Portfolio +--------|:------------:|:---------------------------------------:|:---------: +![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Bai Shun Yao | [Github](https://github.com/shunyao643) | [Portfolio](docs/team/shunyao.md) +![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) + diff --git a/docs/team/shunyao.md b/docs/team/shunyao.md new file mode 100644 index 0000000000..ae8473018a --- /dev/null +++ b/docs/team/shunyao.md @@ -0,0 +1,6 @@ +# Bai Shun Yao - Project Portfolio Page + +## Overview + + +### Summary of Contributions From f979a5f3a7ac0cfb85add11fd289bbe81e88098b Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Fri, 4 Mar 2022 18:12:53 +0800 Subject: [PATCH 004/229] Add AboutUs for yuhao --- docs/AboutUs.md | 2 +- docs/team/yuhao.md | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 docs/team/yuhao.md diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..87cd827b35 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -4,6 +4,6 @@ Display | Name | Github Profile | Portfolio --------|:----:|:--------------:|:---------: ![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) ![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Yu Hao | [Github](https://github.com/yuhaochua) | [Portfolio](docs/team/yuhao.md) ![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) ![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) diff --git a/docs/team/yuhao.md b/docs/team/yuhao.md new file mode 100644 index 0000000000..8b5397fb64 --- /dev/null +++ b/docs/team/yuhao.md @@ -0,0 +1,6 @@ +# Yu Hao - Project Portfolio Page + +## Overview + + +### Summary of Contributions From 572099e05c8d9169b0325e7be38638d6ae58a126 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sun, 6 Mar 2022 17:43:39 +0800 Subject: [PATCH 005/229] Add Command and CommandResult classes Fixes #22 Fixes #23 --- src/main/java/seedu/command/Command.java | 13 ++++++++ .../java/seedu/command/CommandResult.java | 31 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/main/java/seedu/command/Command.java create mode 100644 src/main/java/seedu/command/CommandResult.java diff --git a/src/main/java/seedu/command/Command.java b/src/main/java/seedu/command/Command.java new file mode 100644 index 0000000000..32617cc8cd --- /dev/null +++ b/src/main/java/seedu/command/Command.java @@ -0,0 +1,13 @@ +package seedu.command; + +/** + * Abstract parent class for all types of commands + */ +// The Command class as well as all of its subclasses was created with reference to +// https://github.com/nus-cs2113-AY2122S2/personbook/tree/master/src/main/java/seedu/personbook/commands +public abstract class Command { + private String successMessage; + private String usageReminder; + + public abstract CommandResult execute(); +} diff --git a/src/main/java/seedu/command/CommandResult.java b/src/main/java/seedu/command/CommandResult.java new file mode 100644 index 0000000000..9a9f937c90 --- /dev/null +++ b/src/main/java/seedu/command/CommandResult.java @@ -0,0 +1,31 @@ +package seedu.command; + +import java.util.ArrayList; + +/** + * Represents the result of a command execution. + */ +// Created with reference to +// https://github.com/nus-cs2113-AY2122S2/personbook/tree/master/src/main/java/seedu/personbook/commands +public class CommandResult { + private final String RESULT_TO_SHOW; + private final ArrayList RELEVANT_EQUIPMENT; + + public CommandResult(String result){ + RESULT_TO_SHOW = result; + RELEVANT_EQUIPMENT = null; + } + + public CommandResult(String result, ArrayList equipmentList){ + RESULT_TO_SHOW = result; + RELEVANT_EQUIPMENT = null; + } + + public String getResultToShow(){ + return RESULT_TO_SHOW; + } + + public ArrayList getRelevantEquipment(){ + return RELEVANT_EQUIPMENT; + } +} From 124ccc8e055f659ffdd36f986f188e608db595f5 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Mon, 7 Mar 2022 01:30:54 +0800 Subject: [PATCH 006/229] Add AddCommand class to handle adding equipment Update Command and CommandResult Fixes #18 --- src/main/java/seedu/command/AddCommand.java | 45 +++++++++++++++++++ src/main/java/seedu/command/Command.java | 11 ++++- .../java/seedu/command/CommandResult.java | 2 +- 3 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 src/main/java/seedu/command/AddCommand.java diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java new file mode 100644 index 0000000000..7b3c0bdf4e --- /dev/null +++ b/src/main/java/seedu/command/AddCommand.java @@ -0,0 +1,45 @@ +package seedu.command; + +import java.util.ArrayList; + +/** + * Subclass of Command. Handles adding of equipment to equipmentInventory. + */ +public class AddCommand extends Command { + private final ArrayList COMMAND_STRINGS; + + /** + * constructor for AddCommand. Initialises successMessage and usageReminder from Command + * @param commandStrings parsed user input which contains details of equipment to be added + */ + public AddCommand(ArrayList commandStrings){ + this.COMMAND_STRINGS = commandStrings; + successMessage = "Equipment successfully added: %1$s, serial number %2$s" ; + usageReminder = ": Adds a Equipment to the equipmentInventory. " + + "Parameters: n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE\n" + + "Example: " + + "add n/SpeakerB sn/S1404115ASF t/Speaker c/1000 pf/Loud_Technologies pd/2022-02-23"; + } + + public CommandResult execute(){ + addEquipment(COMMAND_STRINGS); + + return new CommandResult(String.format(successMessage, COMMAND_STRINGS.get(0), COMMAND_STRINGS.get(1)), equipmentInventory.getEquipmentList()); + } + + /** + * Uses information from the ArrayList to create a new Equipment and add it to the inventory. + * @param userInput ArrayList of String which contains the individual attributes of the equipment to be added + */ + public void addEquipment(ArrayList userInput){ + String equipmentName = userInput.get(0); + String serialNumber = userInput.get(1); + EquipmentType type = userInput.get(2); + double cost = Double.parseDouble(userInput.get(3)); + String purchasedFrom = userInput.get(4); + String purchasedDate = userInput.get(5); + Equipment equipment = new Equipment(equipmentName, serialNumber, type, cost, purchasedFrom, purchasedDate); + + equipmentInventory.addEquipment(equipment); + } +} diff --git a/src/main/java/seedu/command/Command.java b/src/main/java/seedu/command/Command.java index 32617cc8cd..6c638c2c92 100644 --- a/src/main/java/seedu/command/Command.java +++ b/src/main/java/seedu/command/Command.java @@ -1,13 +1,20 @@ package seedu.command; +import java.util.HashMap; + /** * Abstract parent class for all types of commands */ // The Command class as well as all of its subclasses was created with reference to // https://github.com/nus-cs2113-AY2122S2/personbook/tree/master/src/main/java/seedu/personbook/commands public abstract class Command { - private String successMessage; - private String usageReminder; + protected String successMessage; + protected String usageReminder; + protected EquipmentManager equipmentInventory; public abstract CommandResult execute(); + + public String getUsageReminder(){ + return usageReminder; + } } diff --git a/src/main/java/seedu/command/CommandResult.java b/src/main/java/seedu/command/CommandResult.java index 9a9f937c90..8410a0f796 100644 --- a/src/main/java/seedu/command/CommandResult.java +++ b/src/main/java/seedu/command/CommandResult.java @@ -18,7 +18,7 @@ public CommandResult(String result){ public CommandResult(String result, ArrayList equipmentList){ RESULT_TO_SHOW = result; - RELEVANT_EQUIPMENT = null; + RELEVANT_EQUIPMENT = equipmentList; } public String getResultToShow(){ From 827ca553701bddcabf6848fe92995d92ede92aee Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Mon, 7 Mar 2022 12:39:10 +0800 Subject: [PATCH 007/229] Add DeleteCommand class to handle deleting of equipment Update AddCommand Fixes #20 --- src/main/java/seedu/command/AddCommand.java | 11 ++++-- .../java/seedu/command/DeleteCommand.java | 35 +++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 src/main/java/seedu/command/DeleteCommand.java diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index 7b3c0bdf4e..36a54edc8c 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -7,6 +7,7 @@ */ public class AddCommand extends Command { private final ArrayList COMMAND_STRINGS; + public final String COMMAND_WORD = "add"; /** * constructor for AddCommand. Initialises successMessage and usageReminder from Command @@ -14,17 +15,21 @@ public class AddCommand extends Command { */ public AddCommand(ArrayList commandStrings){ this.COMMAND_STRINGS = commandStrings; - successMessage = "Equipment successfully added: %1$s, serial number %2$s" ; - usageReminder = ": Adds a Equipment to the equipmentInventory. " + successMessage = "Equipment successfully added: %1$s, serial number %2$s"; + usageReminder = COMMAND_WORD + ": Adds a Equipment to the equipmentInventory. " + "Parameters: n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE\n" + "Example: " + "add n/SpeakerB sn/S1404115ASF t/Speaker c/1000 pf/Loud_Technologies pd/2022-02-23"; } + /** + * Adds equipment with details given in COMMAND_STRINGS + * @return CommandResult with message from execution of this command + */ public CommandResult execute(){ addEquipment(COMMAND_STRINGS); - return new CommandResult(String.format(successMessage, COMMAND_STRINGS.get(0), COMMAND_STRINGS.get(1)), equipmentInventory.getEquipmentList()); + return new CommandResult(String.format(successMessage, COMMAND_STRINGS.get(0), COMMAND_STRINGS.get(1))); } /** diff --git a/src/main/java/seedu/command/DeleteCommand.java b/src/main/java/seedu/command/DeleteCommand.java new file mode 100644 index 0000000000..0c87c63d80 --- /dev/null +++ b/src/main/java/seedu/command/DeleteCommand.java @@ -0,0 +1,35 @@ +package seedu.command; + +import java.util.ArrayList; + +/** + * Subclass of Command. Handles deleting of equipment from equipmentInventory. + */ +public class DeleteCommand extends Command { + private final ArrayList COMMAND_STRINGS; + public final String COMMAND_WORD = "delete"; + + /** + * constructor for DeleteCommand. Initialises successMessage and usageReminder from Command + * @param commandStrings parsed user input which contains details of equipment to be deleted + */ + public DeleteCommand(ArrayList commandStrings){ + COMMAND_STRINGS = commandStrings; + successMessage = "Equipment successfully deleted: %1$s, serial number %2$s"; + usageReminder = COMMAND_WORD + ": Deletes the equipment with the specified serial number. " + + "Parameters: s/SERIAL_NUMBER\n" + + "Example: " + + "delete s/SM57-1"; + } + + /** + * Deletes equipment specified by serial number + * @return CommandResult with message from execution of this command + */ + public CommandResult execute(){ + String equipmentName = equipmentInventory.getEquipmentList().get(COMMAND_STRINGS.get(0)); + equipmentInventory.deleteEquipment(COMMAND_STRINGS.get(0)); + + return new CommandResult(String.format(successMessage, equipmentName,COMMAND_STRINGS.get(1))); + } +} From d6f3aeaed641fdb2f3fcfffc53fc348142a01f6e Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Mon, 7 Mar 2022 13:06:18 +0800 Subject: [PATCH 008/229] Add CheckCommand to handle checking of an equipment specified by name Fixes #25 --- src/main/java/seedu/command/CheckCommand.java | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/main/java/seedu/command/CheckCommand.java diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java new file mode 100644 index 0000000000..72e47847cb --- /dev/null +++ b/src/main/java/seedu/command/CheckCommand.java @@ -0,0 +1,48 @@ +package seedu.command; + +import java.util.ArrayList; + +/** + * Subclass of Command. Handles checking of details of a specified equipment from equipmentInventory. + */ +public class CheckCommand extends Command { + private final ArrayList COMMAND_STRINGS; + public final String COMMAND_WORD = "check"; + + /** + * constructor for CheckCommand. Initialises successMessage and usageReminder from Command + * @param commandStrings parsed user input which contains details of equipment to be viewed + */ + public CheckCommand(ArrayList commandStrings){ + COMMAND_STRINGS = commandStrings; + successMessage = "Name: %1$s\n" + + "Type: %2$s\n" + + "Cost: %3$f\n" + + "S/N: %4$s\n" + + "Purchased From: %5$s\n" + + "Purchase Date: %6$s\n"; + usageReminder = COMMAND_WORD + ": Gives details of the equipment with the specified name. " + + "Parameters: n/ITEM_NAME\n" + + "Example: " + + "check n/MixerC"; + } + + /** + * Gives details of equipment specified by name + * @return CommandResult with message from execution of this command + */ + public CommandResult execute(){ + String name, type, sn, purchasedFrom, purchasedDate; + double cost; + + Equipment equipment = equipmentInventory.checkEquipment(COMMAND_STRINGS.get(0)); + name = equipment.getItemName(); + type = equipment.getType(); + sn = equipment.getSerialNumber(); + purchasedFrom = equipment.getPurchasedFrom(); + purchasedDate = equipment.getPurchasedDate(); + cost = equipment.getCost(); + + return new CommandResult(String.format(successMessage, name, type, cost, sn, purchasedFrom, purchasedDate)); + } +} From a752cfa65d48ed3ff8350bf88eb6b5c9573812cf Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Mon, 7 Mar 2022 13:35:15 +0800 Subject: [PATCH 009/229] Add ListCommand to handle listing of equipment Fixes #26 --- src/main/java/seedu/command/ListCommand.java | 64 ++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/main/java/seedu/command/ListCommand.java diff --git a/src/main/java/seedu/command/ListCommand.java b/src/main/java/seedu/command/ListCommand.java new file mode 100644 index 0000000000..2226364464 --- /dev/null +++ b/src/main/java/seedu/command/ListCommand.java @@ -0,0 +1,64 @@ +package seedu.command; + +import java.util.ArrayList; + +/** + * Subclass of Command. Handles listing of all equipment or listing of equipment of specified type. + */ +public class ListCommand extends Command { + private final ArrayList COMMAND_STRINGS; + public final String COMMAND_WORD = "list"; + + /** + * constructor for ListCommand with NO specified type. Initialises successMessage and usageReminder from Command + * @param commandStrings parsed user input which contains details of equipment to be viewed + */ + public ListCommand(){ + COMMAND_STRINGS = null; + successMessage = "TOTAL QUANTITY OF EQUIPMENT: %1$d\n"; + usageReminder = COMMAND_WORD + ": print a list of all equipment in the inventory. " + + "Parameters: NIL" + + "Example: " + + "list\n" + + COMMAND_WORD + " t/Type: print a list of all equipment in the inventory of the specified type" + + "Parameters: t/Type" + + "Example: " + + "list Microphone"; + } + + /** + * constructor for ListCommand with specified type. Initialises successMessage and usageReminder from Command + * @param commandStrings parsed user input which contains details of equipment to be viewed + */ + public ListCommand(ArrayList commandStrings){ + COMMAND_STRINGS = commandStrings; + successMessage = "TOTAL QUANTITY OF %1$s: %2$d\n"; + usageReminder = COMMAND_WORD + ": print a list of all equipment in the inventory. " + + "Parameters: NIL" + + "Example: " + + "list\n" + + COMMAND_WORD + " t/Type: print a list of all equipment in the inventory of the specified type" + + "Parameters: t/Type" + + "Example: " + + "list Microphone"; + } + + /** + * List all equipment or list equipment of specified type + * @return CommandResult with message from execution of this command + */ + public CommandResult execute(){ + int listSize; + ArrayList equipmentArrayList; + if(COMMAND_STRINGS == null){ + equipmentArrayList = equipmentInventory.listEquipment(); + listSize = equipmentArrayList.size(); + return new CommandResult(String.format(successMessage, listSize), equipmentArrayList); + } + + String typeToList = COMMAND_STRINGS.get(0); + equipmentArrayList = equipmentInventory.listEquipment(typeToList); + listSize = equipmentArrayList.size(); + return new CommandResult(String.format(successMessage, typeToList, listSize), equipmentArrayList); + } +} From fc13b74524bc41bba3bd957e342cfb6fa481cee6 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 10 Mar 2022 01:59:58 +0800 Subject: [PATCH 010/229] Add basic command parser --- src/main/java/parser/Parser.java | 2 ++ src/test/java/parser/ParserTest.java | 4 ++++ 2 files changed, 6 insertions(+) create mode 100644 src/main/java/parser/Parser.java create mode 100644 src/test/java/parser/ParserTest.java diff --git a/src/main/java/parser/Parser.java b/src/main/java/parser/Parser.java new file mode 100644 index 0000000000..4326797f33 --- /dev/null +++ b/src/main/java/parser/Parser.java @@ -0,0 +1,2 @@ +package parser;public class Parser { +} diff --git a/src/test/java/parser/ParserTest.java b/src/test/java/parser/ParserTest.java new file mode 100644 index 0000000000..7b7c6c0c93 --- /dev/null +++ b/src/test/java/parser/ParserTest.java @@ -0,0 +1,4 @@ +import static org.junit.jupiter.api.Assertions.*; +class ParserTest { + +} \ No newline at end of file From ed79dc8155bd666c0d30443aae31bc669bd462a1 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 10 Mar 2022 02:02:11 +0800 Subject: [PATCH 011/229] Revise basic structure for Parser --- src/main/java/parser/Parser.java | 33 +++++++++++++++++++++++++++- src/test/java/parser/ParserTest.java | 30 ++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/main/java/parser/Parser.java b/src/main/java/parser/Parser.java index 4326797f33..6221af273c 100644 --- a/src/main/java/parser/Parser.java +++ b/src/main/java/parser/Parser.java @@ -1,2 +1,33 @@ -package parser;public class Parser { +package parser; + +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Parse user input + * Referenced https://github.com/se-edu/addressbook-level2/blob/master/src/seedu/addressbook/parser/Parser.java + */ +public class Parser { + + /** + * Format to parse command by breaking it up into two segments: command and arguments: these can then be separately + * passed into arguments. + */ + public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s*(?.*)"); + + + public ArrayList parseCommand(String userInput){ + ArrayList resultArrayList = new ArrayList<>(); + final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); + // guard against no match + if (!matcher.matches()){ + System.out.println("Invalid input"); // print correct command + return resultArrayList; + } + resultArrayList.add(matcher.group("commandWord")); + resultArrayList.add(matcher.group("arguments")); + return resultArrayList; + } + } diff --git a/src/test/java/parser/ParserTest.java b/src/test/java/parser/ParserTest.java index 7b7c6c0c93..b3a2a658a6 100644 --- a/src/test/java/parser/ParserTest.java +++ b/src/test/java/parser/ParserTest.java @@ -1,4 +1,32 @@ +package parser; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; + import static org.junit.jupiter.api.Assertions.*; + +import parser.Parser; + class ParserTest { - + + Parser parser; + + @BeforeEach + void setup(){ + parser = new Parser(); + } + + @Test + void parseCommand_validCommand_splitArrayList() { + ArrayList desiredResult = new ArrayList<>( + Arrays.asList("add", "n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE") + ); + ArrayList actualResult = parser.parseCommand("add n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE"); + assertEquals(desiredResult, actualResult); + assertEquals(desiredResult.get(0), actualResult.get(0)); + assertEquals(desiredResult.get(1), actualResult.get(1)); + } } \ No newline at end of file From 4549139d9a699d90917dc5b96a588cbbaf6edf1d Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 10 Mar 2022 14:54:08 +0800 Subject: [PATCH 012/229] Reformat code to comply with coding standards --- src/main/java/parser/Parser.java | 4 ++-- src/test/java/parser/ParserTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/parser/Parser.java b/src/main/java/parser/Parser.java index 6221af273c..daa95efa89 100644 --- a/src/main/java/parser/Parser.java +++ b/src/main/java/parser/Parser.java @@ -17,11 +17,11 @@ public class Parser { public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s*(?.*)"); - public ArrayList parseCommand(String userInput){ + public ArrayList parseCommand(String userInput) { ArrayList resultArrayList = new ArrayList<>(); final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); // guard against no match - if (!matcher.matches()){ + if (!matcher.matches()) { System.out.println("Invalid input"); // print correct command return resultArrayList; } diff --git a/src/test/java/parser/ParserTest.java b/src/test/java/parser/ParserTest.java index b3a2a658a6..1e179e72a0 100644 --- a/src/test/java/parser/ParserTest.java +++ b/src/test/java/parser/ParserTest.java @@ -15,7 +15,7 @@ class ParserTest { Parser parser; @BeforeEach - void setup(){ + void setup() { parser = new Parser(); } From c74ddbd2d736f5347bde1d0dc9e421c38891f552 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 10 Mar 2022 14:57:08 +0800 Subject: [PATCH 013/229] Re-reformat code in ParserTest.java --- src/test/java/parser/ParserTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/java/parser/ParserTest.java b/src/test/java/parser/ParserTest.java index 1e179e72a0..2c5873d6e2 100644 --- a/src/test/java/parser/ParserTest.java +++ b/src/test/java/parser/ParserTest.java @@ -6,7 +6,7 @@ import java.util.ArrayList; import java.util.Arrays; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; import parser.Parser; @@ -24,7 +24,8 @@ void parseCommand_validCommand_splitArrayList() { ArrayList desiredResult = new ArrayList<>( Arrays.asList("add", "n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE") ); - ArrayList actualResult = parser.parseCommand("add n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE"); + ArrayList actualResult = parser.parseCommand( + "add n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE"); assertEquals(desiredResult, actualResult); assertEquals(desiredResult.get(0), actualResult.get(0)); assertEquals(desiredResult.get(1), actualResult.get(1)); From 7479fd330184f5e79812e4d6f9f8a72112e9468b Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 10 Mar 2022 15:13:54 +0800 Subject: [PATCH 014/229] Add javadoc for Parser's parseCommand --- src/main/java/parser/Parser.java | 14 ++++++++++---- src/test/java/parser/ParserTest.java | 8 +++++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main/java/parser/Parser.java b/src/main/java/parser/Parser.java index 6221af273c..ff31a3bdf8 100644 --- a/src/main/java/parser/Parser.java +++ b/src/main/java/parser/Parser.java @@ -14,15 +14,21 @@ public class Parser { * Format to parse command by breaking it up into two segments: command and arguments: these can then be separately * passed into arguments. */ - public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s*(?.*)"); + public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s+(?.*)"); - public ArrayList parseCommand(String userInput){ + /** + * 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. + * @param userInput + * @return ArrayList of String, first element being the command term and the second element being arguments + */ + public ArrayList parseCommand(String userInput) { ArrayList resultArrayList = new ArrayList<>(); final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); // guard against no match - if (!matcher.matches()){ - System.out.println("Invalid input"); // print correct command + if (!matcher.matches()) { + System.out.println("Invalid input"); // TODO: print correct command return resultArrayList; } resultArrayList.add(matcher.group("commandWord")); diff --git a/src/test/java/parser/ParserTest.java b/src/test/java/parser/ParserTest.java index b3a2a658a6..f2d1fcb864 100644 --- a/src/test/java/parser/ParserTest.java +++ b/src/test/java/parser/ParserTest.java @@ -20,7 +20,7 @@ void setup(){ } @Test - void parseCommand_validCommand_splitArrayList() { + void parseCommand_validCommand_success() { ArrayList desiredResult = new ArrayList<>( Arrays.asList("add", "n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE") ); @@ -29,4 +29,10 @@ void parseCommand_validCommand_splitArrayList() { assertEquals(desiredResult.get(0), actualResult.get(0)); assertEquals(desiredResult.get(1), actualResult.get(1)); } + + @Test + void parseCommand_incompleteCommand_exceptionThrown(){ + + } + } \ No newline at end of file From efff9cb713a2d64d7067226c61c5935a4d826d17 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 10 Mar 2022 16:52:38 +0800 Subject: [PATCH 015/229] Define pattern for Add Command --- .../parser/IncompleteCommandException.java | 14 ++++++ src/main/java/parser/Parser.java | 49 +++++++++++++++++-- src/test/java/parser/ParserTest.java | 29 +++++++---- 3 files changed, 79 insertions(+), 13 deletions(-) create mode 100644 src/main/java/parser/IncompleteCommandException.java diff --git a/src/main/java/parser/IncompleteCommandException.java b/src/main/java/parser/IncompleteCommandException.java new file mode 100644 index 0000000000..77910deae5 --- /dev/null +++ b/src/main/java/parser/IncompleteCommandException.java @@ -0,0 +1,14 @@ +package parser; + +/** + * Signal that given data does not include necessary arguments + * Adapted from: https://github.com/se-edu/addressbook-level2/blob/master/src/seedu/addressbook/data/exception/ + */ +public class IncompleteCommandException extends Exception{ + /** + * @param message contains information on failed constraints + */ + public IncompleteCommandException(String message){ + super(message); + } +} diff --git a/src/main/java/parser/Parser.java b/src/main/java/parser/Parser.java index ff31a3bdf8..5715223571 100644 --- a/src/main/java/parser/Parser.java +++ b/src/main/java/parser/Parser.java @@ -1,6 +1,7 @@ package parser; import java.util.ArrayList; +import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -16,24 +17,66 @@ public class Parser { */ public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s+(?.*)"); + public static final Pattern ADD_COMMAND_FORMAT = Pattern.compile( + "n/(?.+)" + "\\s+" + + "sn/(?.+)" + "\\s+" + + "t/(?.+)" + "\\s+" + + "c/\\$?(?[\\d,\\.]+)" + "\\s+" + // TODO: maybe have error checking formula separately? + "pf/(?.+)" + "\\s+" + + "pd/(?.+)" + ); + + public static final String MESSAGE_INCOMPLETECOMMAND_MISSING_DELIMITER = + "Please split your command into arguments with each argument seperated by spaces!"; + + public void parseCommand(String userInput) { + // TODO: replace void with Command + ArrayList commandAndArgument; + try { + commandAndArgument = splitCommandTerm(userInput); + } catch (IncompleteCommandException e) { + System.out.println(MESSAGE_INCOMPLETECOMMAND_MISSING_DELIMITER); + return; + } + + switch (commandAndArgument.get(0)) { + + case "add": + // TODO: replace "add" with constant as defined in AddCommand + prepareAdd(commandAndArgument.get(1)); + + } + + } + + private void prepareAdd(String args) { + final Matcher matcher = ADD_COMMAND_FORMAT.matcher(args.trim()); + // validate arg string format + if (!matcher.matches()) { + + return; + } + } /** * 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. + * * @param userInput * @return ArrayList of String, first element being the command term and the second element being arguments + * @throws IncompleteCommandException if no space is found */ - public ArrayList parseCommand(String userInput) { + public ArrayList splitCommandTerm(String userInput) throws IncompleteCommandException { ArrayList resultArrayList = new ArrayList<>(); final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); // guard against no match if (!matcher.matches()) { - System.out.println("Invalid input"); // TODO: print correct command - return resultArrayList; + throw new IncompleteCommandException("Could not find space delimiter between command and arguments!"); } resultArrayList.add(matcher.group("commandWord")); resultArrayList.add(matcher.group("arguments")); return resultArrayList; } + } diff --git a/src/test/java/parser/ParserTest.java b/src/test/java/parser/ParserTest.java index f2d1fcb864..54717f287b 100644 --- a/src/test/java/parser/ParserTest.java +++ b/src/test/java/parser/ParserTest.java @@ -8,8 +8,6 @@ import static org.junit.jupiter.api.Assertions.*; -import parser.Parser; - class ParserTest { Parser parser; @@ -20,19 +18,30 @@ void setup(){ } @Test - void parseCommand_validCommand_success() { - ArrayList desiredResult = new ArrayList<>( + void splitCommandTerm_validCommand_success() throws IncompleteCommandException { + ArrayList expectedResult = new ArrayList<>( Arrays.asList("add", "n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE") ); - ArrayList actualResult = parser.parseCommand("add n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE"); - assertEquals(desiredResult, actualResult); - assertEquals(desiredResult.get(0), actualResult.get(0)); - assertEquals(desiredResult.get(1), actualResult.get(1)); + ArrayList actualResult = parser.splitCommandTerm( + "add n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE"); + assertEquals(expectedResult, actualResult); + assertEquals(expectedResult.get(0), actualResult.get(0)); + assertEquals(expectedResult.get(1), actualResult.get(1)); } @Test - void parseCommand_incompleteCommand_exceptionThrown(){ - + void splitCommandTerm_incompleteCommand_exceptionThrown(){ + ArrayList unexpectedResult = new ArrayList<>( + Arrays.asList("add","n/ITEM_NAMEsn/SERIAL_NUMBERt/TYPEc/COSTpf/PURCHASED_FROMpd/PURCHASED_DATE") + ); + try { + ArrayList actualResult = parser.splitCommandTerm( + "addn/ITEM_NAMEsn/SERIAL_NUMBERt/TYPEc/COSTpf/PURCHASED_FROMpd/PURCHASED_DATE"); + assertEquals(unexpectedResult, actualResult); + fail(); + } catch (IncompleteCommandException e){ + assertEquals("Could not find space delimiter between command and arguments!", e.getMessage()); + } } } \ No newline at end of file From 4908ed8152069b161f9cfdfe97e288081547ed6e Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 10 Mar 2022 18:47:15 +0800 Subject: [PATCH 016/229] Draft Parser and ParserTest for Add command --- src/main/java/parser/Parser.java | 13 ++++++++++--- src/test/java/parser/ParserTest.java | 16 +++++++++++++--- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/main/java/parser/Parser.java b/src/main/java/parser/Parser.java index 2cced3a721..42ed37327a 100644 --- a/src/main/java/parser/Parser.java +++ b/src/main/java/parser/Parser.java @@ -1,7 +1,10 @@ package parser; +import java.lang.reflect.Array; import java.util.ArrayList; + import seedu.command.*; + import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -49,13 +52,17 @@ public void parseCommand(String userInput) { return; } - private void prepareAdd(String args) { + ArrayList prepareAdd(String args) throws IncompleteCommandException { final Matcher matcher = ADD_COMMAND_FORMAT.matcher(args.trim()); // validate arg string format if (!matcher.matches()) { - - return; + throw new IncompleteCommandException("Add command values are incomplete or missing!"); + } + ArrayList results = new ArrayList(); + for (int i = 0; i < matcher.groupCount(); i++) { + results.add(matcher.group(i)); } + return results; } /** diff --git a/src/test/java/parser/ParserTest.java b/src/test/java/parser/ParserTest.java index 1aa6e039a0..67fb848944 100644 --- a/src/test/java/parser/ParserTest.java +++ b/src/test/java/parser/ParserTest.java @@ -31,18 +31,28 @@ void splitCommandTerm_validCommand_success() throws IncompleteCommandException { } @Test - void splitCommandTerm_incompleteCommand_exceptionThrown(){ + void splitCommandTerm_incompleteCommand_exceptionThrown() { ArrayList unexpectedResult = new ArrayList<>( - Arrays.asList("add","n/ITEM_NAMEsn/SERIAL_NUMBERt/TYPEc/COSTpf/PURCHASED_FROMpd/PURCHASED_DATE") + Arrays.asList("add", "n/ITEM_NAMEsn/SERIAL_NUMBERt/TYPEc/COSTpf/PURCHASED_FROMpd/PURCHASED_DATE") ); try { ArrayList actualResult = parser.splitCommandTerm( "addn/ITEM_NAMEsn/SERIAL_NUMBERt/TYPEc/COSTpf/PURCHASED_FROMpd/PURCHASED_DATE"); assertEquals(unexpectedResult, actualResult); fail(); - } catch (IncompleteCommandException e){ + } catch (IncompleteCommandException e) { assertEquals("Could not find space delimiter between command and arguments!", e.getMessage()); } } + @Test + void prepareAdd_validAddString_success() throws IncompleteCommandException { + ArrayList expectedResult = new ArrayList<>( + Arrays.asList("Speaker B", "S1404115ASF", "Speaker", "1000", "Loud Technologies", "2022-02-23") + ); + ArrayList actualResult = parser.prepareAdd( + "n/Speaker B sn/S1404115ASF t/Speaker c/1000 pf/Loud Technologies pd/2022-02-23"); + assertEquals(expectedResult, actualResult); + } + } \ No newline at end of file From c3d58f511dd55d16b3ed95588891c4e451158b7a Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Fri, 11 Mar 2022 15:28:37 +0800 Subject: [PATCH 017/229] Add implementation for Check, Delete Command with IncorrectCommand class support --- src/main/java/parser/Parser.java | 89 ++++++++++++++++--- src/main/java/seedu/command/AddCommand.java | 11 +-- src/main/java/seedu/command/CheckCommand.java | 11 +-- src/main/java/seedu/command/Command.java | 2 +- .../java/seedu/command/DeleteCommand.java | 11 +-- .../java/seedu/command/IncorrectCommand.java | 20 +++++ 6 files changed, 116 insertions(+), 28 deletions(-) create mode 100644 src/main/java/seedu/command/IncorrectCommand.java diff --git a/src/main/java/parser/Parser.java b/src/main/java/parser/Parser.java index 42ed37327a..f9fad72fc1 100644 --- a/src/main/java/parser/Parser.java +++ b/src/main/java/parser/Parser.java @@ -5,6 +5,7 @@ import seedu.command.*; +import java.util.Collections; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -19,7 +20,6 @@ public class Parser { * passed into arguments. */ public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s+(?.*)"); - public static final Pattern ADD_COMMAND_FORMAT = Pattern.compile( "n/(?.+)" + "\\s+" + "sn/(?.+)" + "\\s+" + @@ -28,31 +28,68 @@ public class Parser { "pf/(?.+)" + "\\s+" + "pd/(?.+)" ); - + public static final Pattern VIEW_COMMAND_FORMAT = Pattern.compile("n/(?.+)"); + public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("s/(?.+)"); public static final String MESSAGE_INCOMPLETE_COMMAND_MISSING_DELIMITER = "Please split your command into arguments with each argument seperated by spaces!"; - public void parseCommand(String userInput) { + public Command parseCommand(String userInput) throws IncompleteCommandException { // TODO: replace void with Command - ArrayList commandAndArgument; + ArrayList commandAndArgument = null; + ArrayList args = null; try { commandAndArgument = splitCommandTerm(userInput); } catch (IncompleteCommandException e) { - System.out.println(MESSAGE_INCOMPLETE_COMMAND_MISSING_DELIMITER); - return; + return new IncorrectCommand(MESSAGE_INCOMPLETE_COMMAND_MISSING_DELIMITER); } switch (commandAndArgument.get(0)) { - - case "add": + case AddCommand.COMMAND_WORD: // TODO: replace "add" with constant as defined in AddCommand - prepareAdd(commandAndArgument.get(1)); + try { + args = prepareAdd(commandAndArgument.get(1)); + return new AddCommand(args); + } catch (IncompleteCommandException e) { + return new IncorrectCommand(AddCommand.COMMAND_WORD + AddCommand.COMMAND_DESCRIPTION); + } + break; + case CheckCommand.COMMAND_WORD: + try { + args = prepareView(commandAndArgument.get(1)); + return new CheckCommand(args); + } catch (IncompleteCommandException e) { + return new IncorrectCommand(CheckCommand.COMMAND_WORD + CheckCommand.COMMAND_DESCRIPTION); + } + break; + case DeleteCommand.COMMAND_WORD: + try { + args = prepareDelete(commandAndArgument.get(1)); + return new DeleteCommand(args); + } catch (IncompleteCommandException e) { + return new IncorrectCommand(DeleteCommand.COMMAND_WORD + DeleteCommand.COMMAND_DESCRIPTION); + } + } - return; + } - ArrayList prepareAdd(String args) throws IncompleteCommandException { + /** + * Prepare arguments for AddCommand by splitting up the arguments into different parts + *

+ * Index: + * 0. equipmentName : String of equipment name + * 1. serialNumber : String of unique serial number + * 2. type : String representation of enumerated class + * 3. cost : String representation of double value, "$" optional but "," delimiter forbidden + * 4. purchasedFrom : String of vendor name, suggest adhering to one consistent naming scheme + * 5. purchasedDate : String representation for now, possibility for future support + * + * @param args + * @return ArrayList of arguments + * @throws IncompleteCommandException if no match found + */ + protected ArrayList prepareAdd(String args) throws IncompleteCommandException { final Matcher matcher = ADD_COMMAND_FORMAT.matcher(args.trim()); // validate arg string format if (!matcher.matches()) { @@ -60,11 +97,39 @@ ArrayList prepareAdd(String args) throws IncompleteCommandException { } ArrayList results = new ArrayList(); for (int i = 0; i < matcher.groupCount(); i++) { - results.add(matcher.group(i)); + results.add(matcher.group()); } return results; } + /** + * Prepare argument for CheckCommand by removing the preceeding "n/" prefix + * @param args + * @return ArrayList of one element (assumes rest of string is item name) + * @throws IncompleteCommandException + */ + protected ArrayList prepareView(String args) throws IncompleteCommandException { + final Matcher matcher = VIEW_COMMAND_FORMAT.matcher(args.trim()); + if (!matcher.matches()) { + throw new IncompleteCommandException("View command values are incomplete or missing!"); + } + return new ArrayList(Collections.singleton(matcher.group())); + } + + /** + * Prepare argument for DeleteCommand by removing the preceeding "s/" prefix + * @param args + * @return ArrayList of one element (assumes rest of string is serial number) + * @throws IncompleteCommandException + */ + protected ArrayList prepareDelete(String args) throws IncompleteCommandException { + final Matcher matcher = DELETE_COMMAND_FORMAT.matcher(args.trim()); + if (!matcher.matches()) { + throw new IncompleteCommandException("Delete command values are incomplete or missing!"); + } + return new ArrayList(Collections.singleton(matcher.group())); + } + /** * 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. diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index 36a54edc8c..792bb1cfb6 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -7,7 +7,11 @@ */ public class AddCommand extends Command { private final ArrayList COMMAND_STRINGS; - public final String COMMAND_WORD = "add"; + public static final String COMMAND_WORD = "add"; + public static final String COMMAND_DESCRIPTION = ": Adds a Equipment to the equipmentInventory. " + + "Parameters: n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE\n" + + "Example: " + + "add n/SpeakerB sn/S1404115ASF t/Speaker c/1000 pf/Loud_Technologies pd/2022-02-23"; /** * constructor for AddCommand. Initialises successMessage and usageReminder from Command @@ -16,10 +20,7 @@ public class AddCommand extends Command { public AddCommand(ArrayList commandStrings){ this.COMMAND_STRINGS = commandStrings; successMessage = "Equipment successfully added: %1$s, serial number %2$s"; - usageReminder = COMMAND_WORD + ": Adds a Equipment to the equipmentInventory. " - + "Parameters: n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE\n" - + "Example: " - + "add n/SpeakerB sn/S1404115ASF t/Speaker c/1000 pf/Loud_Technologies pd/2022-02-23"; + usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; } /** diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index 72e47847cb..79ed9e1f67 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -7,7 +7,11 @@ */ public class CheckCommand extends Command { private final ArrayList COMMAND_STRINGS; - public final String COMMAND_WORD = "check"; + public static final String COMMAND_WORD = "check"; + public static final String COMMAND_DESCRIPTION = ": Gives details of the equipment with the specified name. " + + "Parameters: n/ITEM_NAME\n" + + "Example: " + + "check n/MixerC"; /** * constructor for CheckCommand. Initialises successMessage and usageReminder from Command @@ -21,10 +25,7 @@ public CheckCommand(ArrayList commandStrings){ + "S/N: %4$s\n" + "Purchased From: %5$s\n" + "Purchase Date: %6$s\n"; - usageReminder = COMMAND_WORD + ": Gives details of the equipment with the specified name. " - + "Parameters: n/ITEM_NAME\n" - + "Example: " - + "check n/MixerC"; + usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; } /** diff --git a/src/main/java/seedu/command/Command.java b/src/main/java/seedu/command/Command.java index 6c638c2c92..b3c67098b0 100644 --- a/src/main/java/seedu/command/Command.java +++ b/src/main/java/seedu/command/Command.java @@ -9,7 +9,7 @@ // https://github.com/nus-cs2113-AY2122S2/personbook/tree/master/src/main/java/seedu/personbook/commands public abstract class Command { protected String successMessage; - protected String usageReminder; + public String usageReminder; protected EquipmentManager equipmentInventory; public abstract CommandResult execute(); diff --git a/src/main/java/seedu/command/DeleteCommand.java b/src/main/java/seedu/command/DeleteCommand.java index 0c87c63d80..e16824def5 100644 --- a/src/main/java/seedu/command/DeleteCommand.java +++ b/src/main/java/seedu/command/DeleteCommand.java @@ -7,7 +7,11 @@ */ public class DeleteCommand extends Command { private final ArrayList COMMAND_STRINGS; - public final String COMMAND_WORD = "delete"; + public static final String COMMAND_WORD = "delete"; + public static final String COMMAND_DESCRIPTION = ": Deletes the equipment with the specified serial number. " + + "Parameters: s/SERIAL_NUMBER\n" + + "Example: " + + "delete s/SM57-1"; /** * constructor for DeleteCommand. Initialises successMessage and usageReminder from Command @@ -16,10 +20,7 @@ public class DeleteCommand extends Command { public DeleteCommand(ArrayList commandStrings){ COMMAND_STRINGS = commandStrings; successMessage = "Equipment successfully deleted: %1$s, serial number %2$s"; - usageReminder = COMMAND_WORD + ": Deletes the equipment with the specified serial number. " - + "Parameters: s/SERIAL_NUMBER\n" - + "Example: " - + "delete s/SM57-1"; + usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; } /** diff --git a/src/main/java/seedu/command/IncorrectCommand.java b/src/main/java/seedu/command/IncorrectCommand.java new file mode 100644 index 0000000000..efcb3d066c --- /dev/null +++ b/src/main/java/seedu/command/IncorrectCommand.java @@ -0,0 +1,20 @@ +package seedu.command; + +/** + * Represents an incorrect command. Upon execution, provide some feedback to user + * @author Shun Yao + */ +public class IncorrectCommand extends Command { + + public final String feedbackToUser; + + public IncorrectCommand(String feedbackToUser) { + this.feedbackToUser = feedbackToUser; + } + + @Override + public CommandResult execute() { + return new CommandResult(feedbackToUser); + } + +} From 5fe8882aef544439b4f7a76f87911a0a4de2c080 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Fri, 11 Mar 2022 21:07:24 +0800 Subject: [PATCH 018/229] Add Equipment, EquipmentType, and Equipment Manager --- src/main/java/seedu/Equipment/Equipment.java | 67 +++++++++++++++++++ .../seedu/Equipment/EquipmentManager.java | 39 +++++++++++ .../java/seedu/Equipment/EquipmentType.java | 5 ++ 3 files changed, 111 insertions(+) create mode 100644 src/main/java/seedu/Equipment/Equipment.java create mode 100644 src/main/java/seedu/Equipment/EquipmentManager.java create mode 100644 src/main/java/seedu/Equipment/EquipmentType.java diff --git a/src/main/java/seedu/Equipment/Equipment.java b/src/main/java/seedu/Equipment/Equipment.java new file mode 100644 index 0000000000..4d928ea36f --- /dev/null +++ b/src/main/java/seedu/Equipment/Equipment.java @@ -0,0 +1,67 @@ +package seedu.Equipment; + +public class Equipment { + private String itemName; + private String serialNumber; + private EquipmentType type; + private double cost; + private String purchasedFrom; + private String purchasedDate; + + public Equipment(String itemName, String serialNumber, EquipmentType type, double cost, String purchasedFrom, String purchasedDate) { + this.itemName = itemName; + this.serialNumber = serialNumber; + this.type = type; + this.cost = cost; + this.purchasedFrom = purchasedFrom; + this.purchasedDate = purchasedDate; + } + + public String getItemName() { + return this.itemName; + } + + public void setItemName(String itemName) { + this.itemName = itemName; + } + + public String getSerialNumber() { + return this.serialNumber; + } + + public void setSerialNumber(String serialNumber) { + this.serialNumber = serialNumber; + } + + public EquipmentType getType() { + return this.type; + } + + public void setType(EquipmentType type) { + this.type = type; + } + + public double getCost() { + return this.cost; + } + + public void setCost(double cost) { + this.cost = cost; + } + + public String getPurchasedFrom() { + return this.purchasedFrom; + } + + public void setPurchasedFrom(String purchasedFrom) { + this.purchasedFrom = purchasedFrom; + } + + public String getPurchasedDate() { + return this.purchasedDate; + } + + public void setPurchasedDate(String purchasedDate) { + this.purchasedDate = purchasedDate; + } +} diff --git a/src/main/java/seedu/Equipment/EquipmentManager.java b/src/main/java/seedu/Equipment/EquipmentManager.java new file mode 100644 index 0000000000..ecc2506632 --- /dev/null +++ b/src/main/java/seedu/Equipment/EquipmentManager.java @@ -0,0 +1,39 @@ +package seedu.Equipment; + +import java.util.ArrayList; +import java.util.HashMap; + +public class EquipmentManager { + private final HashMap equipmentList = new HashMap<>(); + + public void addEquipment(String itemName, String serialNumber, EquipmentType type, double cost, String purchasedFrom, String purchasedDate) { + Equipment equipment = new Equipment(itemName, serialNumber, type, cost, purchasedFrom, purchasedDate); + equipmentList.put(serialNumber, equipment); + } + + public Equipment checkEquipment(String serialNumber) { + return equipmentList.get(serialNumber); + } + + public ArrayList listEquipment(EquipmentType type) { + ArrayList listOfEquipments = new ArrayList<>(); + for (Equipment equipment : equipmentList.values()) { + if (equipment.getType() == type) { + listOfEquipments.add(equipment); + } + } + return listOfEquipments; + } + + public ArrayList listEquipment() { + return new ArrayList<>(equipmentList.values()); + } + + public void updateEquipment(String serialNumber) { + + } + + public void deleteEquipment(String serialNumber) { + equipmentList.remove(serialNumber); + } +} diff --git a/src/main/java/seedu/Equipment/EquipmentType.java b/src/main/java/seedu/Equipment/EquipmentType.java new file mode 100644 index 0000000000..2ec9276eba --- /dev/null +++ b/src/main/java/seedu/Equipment/EquipmentType.java @@ -0,0 +1,5 @@ +package seedu.Equipment; + +public enum EquipmentType { + MICROPHONE, SPEAKER, STAND, CABLE +} From 212eb065757fa7f081ecc88412daa84ca98323f4 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Fri, 11 Mar 2022 22:25:17 +0800 Subject: [PATCH 019/229] Update code according to pull request comments. --- .../Equipment/DuplicateSerialNumber.java | 5 ++++ .../seedu/Equipment/EquipmentManager.java | 24 +++++++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-) create mode 100644 src/main/java/seedu/Equipment/DuplicateSerialNumber.java diff --git a/src/main/java/seedu/Equipment/DuplicateSerialNumber.java b/src/main/java/seedu/Equipment/DuplicateSerialNumber.java new file mode 100644 index 0000000000..6e5ee0ad98 --- /dev/null +++ b/src/main/java/seedu/Equipment/DuplicateSerialNumber.java @@ -0,0 +1,5 @@ +package seedu.Equipment; + +public class DuplicateSerialNumber extends Exception { + public DuplicateSerialNumber() {} +} diff --git a/src/main/java/seedu/Equipment/EquipmentManager.java b/src/main/java/seedu/Equipment/EquipmentManager.java index ecc2506632..40b9b6968f 100644 --- a/src/main/java/seedu/Equipment/EquipmentManager.java +++ b/src/main/java/seedu/Equipment/EquipmentManager.java @@ -6,19 +6,29 @@ public class EquipmentManager { private final HashMap equipmentList = new HashMap<>(); - public void addEquipment(String itemName, String serialNumber, EquipmentType type, double cost, String purchasedFrom, String purchasedDate) { - Equipment equipment = new Equipment(itemName, serialNumber, type, cost, purchasedFrom, purchasedDate); - equipmentList.put(serialNumber, equipment); + public void addEquipment(String itemName, String serialNumber, EquipmentType type, double cost, String purchasedFrom, String purchasedDate) throws DuplicateSerialNumber { + if (!equipmentList.containsKey(serialNumber)) { + Equipment equipment = new Equipment(itemName, serialNumber, type, cost, purchasedFrom, purchasedDate); + equipmentList.putIfAbsent(serialNumber, equipment); + } else if (equipmentList.containsKey(serialNumber)) { + throw new DuplicateSerialNumber(); + } } - public Equipment checkEquipment(String serialNumber) { - return equipmentList.get(serialNumber); + public ArrayList checkEquipment(String itemName) { + ArrayList listOfEquipments = new ArrayList<>(); + for (Equipment equipment : equipmentList.values()) { + if (equipment.getItemName().equals(itemName)) { + listOfEquipments.add(equipment); + } + } + return listOfEquipments; } public ArrayList listEquipment(EquipmentType type) { ArrayList listOfEquipments = new ArrayList<>(); for (Equipment equipment : equipmentList.values()) { - if (equipment.getType() == type) { + if (equipment.getType().equals(type)) { listOfEquipments.add(equipment); } } @@ -30,7 +40,7 @@ public ArrayList listEquipment() { } public void updateEquipment(String serialNumber) { - + // To be updated } public void deleteEquipment(String serialNumber) { From 5221de2a347cf9fb5f42d8c1fabff09f401340da Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sat, 12 Mar 2022 00:14:24 +0800 Subject: [PATCH 020/229] Move and rename files based on 11/03/22 discussion --- src/main/java/seedu/Equipment/DuplicateSerialNumber.java | 2 +- src/main/java/seedu/Equipment/Equipment.java | 2 +- src/main/java/seedu/Equipment/EquipmentManager.java | 2 +- src/main/java/seedu/Equipment/EquipmentType.java | 2 +- .../java/{ => seedu}/parser/IncompleteCommandException.java | 2 +- src/main/java/{ => seedu}/parser/Parser.java | 5 +---- src/test/java/{ => seedu/duke}/parser/ParserTest.java | 4 +++- 7 files changed, 9 insertions(+), 10 deletions(-) rename src/main/java/{ => seedu}/parser/IncompleteCommandException.java (94%) rename src/main/java/{ => seedu}/parser/Parser.java (97%) rename src/test/java/{ => seedu/duke}/parser/ParserTest.java (95%) diff --git a/src/main/java/seedu/Equipment/DuplicateSerialNumber.java b/src/main/java/seedu/Equipment/DuplicateSerialNumber.java index 6e5ee0ad98..03aba712bd 100644 --- a/src/main/java/seedu/Equipment/DuplicateSerialNumber.java +++ b/src/main/java/seedu/Equipment/DuplicateSerialNumber.java @@ -1,4 +1,4 @@ -package seedu.Equipment; +package seedu.equipment; public class DuplicateSerialNumber extends Exception { public DuplicateSerialNumber() {} diff --git a/src/main/java/seedu/Equipment/Equipment.java b/src/main/java/seedu/Equipment/Equipment.java index 4d928ea36f..78aae7ac44 100644 --- a/src/main/java/seedu/Equipment/Equipment.java +++ b/src/main/java/seedu/Equipment/Equipment.java @@ -1,4 +1,4 @@ -package seedu.Equipment; +package seedu.equipment; public class Equipment { private String itemName; diff --git a/src/main/java/seedu/Equipment/EquipmentManager.java b/src/main/java/seedu/Equipment/EquipmentManager.java index 40b9b6968f..ce13809c54 100644 --- a/src/main/java/seedu/Equipment/EquipmentManager.java +++ b/src/main/java/seedu/Equipment/EquipmentManager.java @@ -1,4 +1,4 @@ -package seedu.Equipment; +package seedu.equipment; import java.util.ArrayList; import java.util.HashMap; diff --git a/src/main/java/seedu/Equipment/EquipmentType.java b/src/main/java/seedu/Equipment/EquipmentType.java index 2ec9276eba..6de199deb3 100644 --- a/src/main/java/seedu/Equipment/EquipmentType.java +++ b/src/main/java/seedu/Equipment/EquipmentType.java @@ -1,4 +1,4 @@ -package seedu.Equipment; +package seedu.equipment; public enum EquipmentType { MICROPHONE, SPEAKER, STAND, CABLE diff --git a/src/main/java/parser/IncompleteCommandException.java b/src/main/java/seedu/parser/IncompleteCommandException.java similarity index 94% rename from src/main/java/parser/IncompleteCommandException.java rename to src/main/java/seedu/parser/IncompleteCommandException.java index 77910deae5..c07e5d7679 100644 --- a/src/main/java/parser/IncompleteCommandException.java +++ b/src/main/java/seedu/parser/IncompleteCommandException.java @@ -1,4 +1,4 @@ -package parser; +package seedu.parser; /** * Signal that given data does not include necessary arguments diff --git a/src/main/java/parser/Parser.java b/src/main/java/seedu/parser/Parser.java similarity index 97% rename from src/main/java/parser/Parser.java rename to src/main/java/seedu/parser/Parser.java index 42ed37327a..ca52f78ef2 100644 --- a/src/main/java/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -1,10 +1,7 @@ -package parser; +package seedu.parser; -import java.lang.reflect.Array; import java.util.ArrayList; -import seedu.command.*; - import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/test/java/parser/ParserTest.java b/src/test/java/seedu/duke/parser/ParserTest.java similarity index 95% rename from src/test/java/parser/ParserTest.java rename to src/test/java/seedu/duke/parser/ParserTest.java index 67fb848944..04e3c6ec43 100644 --- a/src/test/java/parser/ParserTest.java +++ b/src/test/java/seedu/duke/parser/ParserTest.java @@ -1,7 +1,9 @@ -package parser; +package seedu.duke.parser; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import seedu.parser.IncompleteCommandException; +import seedu.parser.Parser; import java.util.ArrayList; import java.util.Arrays; From 9db6b5a88c85336f163fb2ecb89e70909a470b2c Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sat, 12 Mar 2022 00:56:15 +0800 Subject: [PATCH 021/229] Rectify Equipment folder rename --- .../seedu/{Equipment => equipment}/DuplicateSerialNumber.java | 0 src/main/java/seedu/{Equipment => equipment}/Equipment.java | 0 .../java/seedu/{Equipment => equipment}/EquipmentManager.java | 0 src/main/java/seedu/{Equipment => equipment}/EquipmentType.java | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/seedu/{Equipment => equipment}/DuplicateSerialNumber.java (100%) rename src/main/java/seedu/{Equipment => equipment}/Equipment.java (100%) rename src/main/java/seedu/{Equipment => equipment}/EquipmentManager.java (100%) rename src/main/java/seedu/{Equipment => equipment}/EquipmentType.java (100%) diff --git a/src/main/java/seedu/Equipment/DuplicateSerialNumber.java b/src/main/java/seedu/equipment/DuplicateSerialNumber.java similarity index 100% rename from src/main/java/seedu/Equipment/DuplicateSerialNumber.java rename to src/main/java/seedu/equipment/DuplicateSerialNumber.java diff --git a/src/main/java/seedu/Equipment/Equipment.java b/src/main/java/seedu/equipment/Equipment.java similarity index 100% rename from src/main/java/seedu/Equipment/Equipment.java rename to src/main/java/seedu/equipment/Equipment.java diff --git a/src/main/java/seedu/Equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java similarity index 100% rename from src/main/java/seedu/Equipment/EquipmentManager.java rename to src/main/java/seedu/equipment/EquipmentManager.java diff --git a/src/main/java/seedu/Equipment/EquipmentType.java b/src/main/java/seedu/equipment/EquipmentType.java similarity index 100% rename from src/main/java/seedu/Equipment/EquipmentType.java rename to src/main/java/seedu/equipment/EquipmentType.java From 55131dce29ee5d2490ddb22c8e8dbb40466309dc Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sat, 12 Mar 2022 03:33:49 +0800 Subject: [PATCH 022/229] Implement Parser functions to support Updates --- src/main/java/seedu/parser/Parser.java | 82 +++++++++++++++++-- .../seedu/{duke => }/parser/ParserTest.java | 2 +- 2 files changed, 75 insertions(+), 9 deletions(-) rename src/test/java/seedu/{duke => }/parser/ParserTest.java (98%) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 84f0d109e0..123a9f56b6 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -1,13 +1,11 @@ package seedu.parser; +import java.lang.reflect.Array; import java.util.ArrayList; -<<<<<<< HEAD:src/main/java/parser/Parser.java import seedu.command.*; import java.util.Collections; -======= ->>>>>>> master:src/main/java/seedu/parser/Parser.java import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -21,22 +19,29 @@ public class Parser { * Format to parse command by breaking it up into two segments: command and arguments: these can then be separately * passed into arguments. */ - public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s+(?.*)"); + public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s+(?.+)"); public static final Pattern ADD_COMMAND_FORMAT = Pattern.compile( "n/(?.+)" + "\\s+" + "sn/(?.+)" + "\\s+" + "t/(?.+)" + "\\s+" + - "c/\\$?(?[\\d,\\.]+)" + "\\s+" + // TODO: maybe have error checking formula separately? + "c/(?.+)" + "\\s+" + "pf/(?.+)" + "\\s+" + "pd/(?.+)" ); public static final Pattern VIEW_COMMAND_FORMAT = Pattern.compile("n/(?.+)"); public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("s/(?.+)"); + // Pattern extracts first n-1 tags + public static final Pattern ARGUMENT_FORMAT = Pattern.compile( + "((?:sn|n|t|c|pf|pd)\\/[\\w\\s\\-]+?)\\s+(?=sn|n|t|c|pf|pd)" + ); + // Extracts last tag + public static final Pattern ARGUMENT_TRAILING_FORMAT = Pattern.compile( + "(? commandAndArgument = null; ArrayList args = null; try { @@ -47,7 +52,6 @@ public Command parseCommand(String userInput) throws IncompleteCommandException switch (commandAndArgument.get(0)) { case AddCommand.COMMAND_WORD: - // TODO: replace "add" with constant as defined in AddCommand try { args = prepareAdd(commandAndArgument.get(1)); return new AddCommand(args); @@ -70,12 +74,71 @@ public Command parseCommand(String userInput) throws IncompleteCommandException } catch (IncompleteCommandException e) { return new IncorrectCommand(DeleteCommand.COMMAND_WORD + DeleteCommand.COMMAND_DESCRIPTION); } + break; + case UpdateCommand.COMMAND_WORD: + try { + args = extractArguments(commandAndArgument.get(1)); + UpdateCommand updateCommand = new UpdateCommand(serialNumber); + for (String s : args) { + int delimiterPos = s.indexOf('/'); + String argType = s.substring(0, delimiterPos); + String argValue = s.substring(0, delimiterPos + 1); + switch (argType) { + case 'n': + updateCommand.setUpdateName(argValue); + break; + case 'pd': + updateCommand.setPurchaseDate(argValue); + break; + case 't': + updateCommand.setType(argValue); + break; + case 'pf': + updateCommand.setPurchaseFrom(argValue); + break; + case 'c': + updateCommand.setCost(argValue); + break; + default: + System.out.println("`" + argValue + "` not updated for type " + argType +": Unrecognised Tag"); + } + } + return updateCommand; + } catch (IncompleteCommandException e) { + return new IncorrectCommand(UpdateCommand.COMMAND_WORD + UpdateCommand.COMMAND_DESCRIPTION); + } + break; + } + } + /** + * Splits main arguments into split tags with each substring + * + * @param args + * @return ArrayList of two elements + * @throws IncompleteCommandException + */ + protected ArrayList extractArguments(String args) throws IncompleteCommandException { + int lastIndex = 0; + ArrayList splitArguments = new ArrayList<>(); + try { + Matcher matcher = ARGUMENT_FORMAT.matcher(args.trim()); + while (matcher.find()) { + splitArguments.add(matcher.group()); + lastIndex = matcher.end(); + } + matcher.usePattern(ARGUMENT_TRAILING_FORMAT); + matcher.find(lastIndex); + splitArguments.add(matcher.group()); + } catch (IllegalStateException e) { + throw new IncompleteCommandException("No parameters found!"); } - + return splitArguments; } + protected ArrayList<> + /** * Prepare arguments for AddCommand by splitting up the arguments into different parts *

@@ -106,6 +169,7 @@ protected ArrayList prepareAdd(String args) throws IncompleteCommandExce /** * Prepare argument for CheckCommand by removing the preceeding "n/" prefix + * * @param args * @return ArrayList of one element (assumes rest of string is item name) * @throws IncompleteCommandException @@ -120,6 +184,7 @@ protected ArrayList prepareView(String args) throws IncompleteCommandExc /** * Prepare argument for DeleteCommand by removing the preceeding "s/" prefix + * * @param args * @return ArrayList of one element (assumes rest of string is serial number) * @throws IncompleteCommandException @@ -132,6 +197,7 @@ protected ArrayList prepareDelete(String args) throws IncompleteCommandE return new ArrayList(Collections.singleton(matcher.group())); } + /** * 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. diff --git a/src/test/java/seedu/duke/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java similarity index 98% rename from src/test/java/seedu/duke/parser/ParserTest.java rename to src/test/java/seedu/parser/ParserTest.java index 04e3c6ec43..8b877ac275 100644 --- a/src/test/java/seedu/duke/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -1,4 +1,4 @@ -package seedu.duke.parser; +package seedu.parser; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; From 706307debc110d1fe3e49e4288104c80f211f014 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sun, 13 Mar 2022 19:45:21 +0800 Subject: [PATCH 023/229] Update return types of some methods and import Equipment class in the Command classes --- src/main/java/seedu/command/AddCommand.java | 25 +++++++++++++------ src/main/java/seedu/command/CheckCommand.java | 23 ++++++----------- src/main/java/seedu/command/Command.java | 2 ++ .../java/seedu/command/CommandResult.java | 2 ++ .../java/seedu/command/DeleteCommand.java | 4 +-- src/main/java/seedu/command/ListCommand.java | 10 +++++--- .../seedu/equipment/EquipmentManager.java | 4 +++ 7 files changed, 42 insertions(+), 28 deletions(-) diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index 792bb1cfb6..890c47364a 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -1,5 +1,9 @@ package seedu.command; +import seedu.equipment.DuplicateSerialNumber; +import seedu.equipment.Equipment; +import seedu.equipment.EquipmentType; + import java.util.ArrayList; /** @@ -9,10 +13,10 @@ public class AddCommand extends Command { private final ArrayList COMMAND_STRINGS; public static final String COMMAND_WORD = "add"; public static final String COMMAND_DESCRIPTION = ": Adds a Equipment to the equipmentInventory. " - + "Parameters: n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE\n" + + "Parameters: n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE" + System.lineSeparator() + "Example: " + "add n/SpeakerB sn/S1404115ASF t/Speaker c/1000 pf/Loud_Technologies pd/2022-02-23"; - + public static final String DUPLICATE_ITEM_ERROR = "There is already an item with this serial number: %1$s"; /** * constructor for AddCommand. Initialises successMessage and usageReminder from Command * @param commandStrings parsed user input which contains details of equipment to be added @@ -28,7 +32,11 @@ public AddCommand(ArrayList commandStrings){ * @return CommandResult with message from execution of this command */ public CommandResult execute(){ - addEquipment(COMMAND_STRINGS); + try { + addEquipment(COMMAND_STRINGS); + }catch(DuplicateSerialNumber e){ + return new CommandResult(String.format(DUPLICATE_ITEM_ERROR, COMMAND_STRINGS.get(1))); + } return new CommandResult(String.format(successMessage, COMMAND_STRINGS.get(0), COMMAND_STRINGS.get(1))); } @@ -37,15 +45,18 @@ public CommandResult execute(){ * Uses information from the ArrayList to create a new Equipment and add it to the inventory. * @param userInput ArrayList of String which contains the individual attributes of the equipment to be added */ - public void addEquipment(ArrayList userInput){ + public void addEquipment(ArrayList userInput) throws DuplicateSerialNumber{ String equipmentName = userInput.get(0); String serialNumber = userInput.get(1); - EquipmentType type = userInput.get(2); + EquipmentType type = EquipmentType.valueOf(userInput.get(2)); double cost = Double.parseDouble(userInput.get(3)); String purchasedFrom = userInput.get(4); String purchasedDate = userInput.get(5); - Equipment equipment = new Equipment(equipmentName, serialNumber, type, cost, purchasedFrom, purchasedDate); - equipmentInventory.addEquipment(equipment); + try { + equipmentInventory.addEquipment(equipmentName, serialNumber, type, cost, purchasedFrom, purchasedDate); + }catch(DuplicateSerialNumber e){ + throw new DuplicateSerialNumber(); + } } } diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index 79ed9e1f67..bfc4b26599 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -1,5 +1,8 @@ package seedu.command; +import seedu.equipment.Equipment; +import seedu.equipment.EquipmentType; + import java.util.ArrayList; /** @@ -19,12 +22,7 @@ public class CheckCommand extends Command { */ public CheckCommand(ArrayList commandStrings){ COMMAND_STRINGS = commandStrings; - successMessage = "Name: %1$s\n" - + "Type: %2$s\n" - + "Cost: %3$f\n" - + "S/N: %4$s\n" - + "Purchased From: %5$s\n" - + "Purchase Date: %6$s\n"; + successMessage = "Here are the equipment matching to '%1$s':" + System.lineSeparator(); usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; } @@ -33,17 +31,12 @@ public CheckCommand(ArrayList commandStrings){ * @return CommandResult with message from execution of this command */ public CommandResult execute(){ - String name, type, sn, purchasedFrom, purchasedDate; + String name, sn, purchasedFrom, purchasedDate; + EquipmentType type; double cost; - Equipment equipment = equipmentInventory.checkEquipment(COMMAND_STRINGS.get(0)); - name = equipment.getItemName(); - type = equipment.getType(); - sn = equipment.getSerialNumber(); - purchasedFrom = equipment.getPurchasedFrom(); - purchasedDate = equipment.getPurchasedDate(); - cost = equipment.getCost(); + ArrayList equipment = equipmentInventory.checkEquipment(COMMAND_STRINGS.get(0)); - return new CommandResult(String.format(successMessage, name, type, cost, sn, purchasedFrom, purchasedDate)); + return new CommandResult(String.format(successMessage, COMMAND_STRINGS.get(0)), equipment); } } diff --git a/src/main/java/seedu/command/Command.java b/src/main/java/seedu/command/Command.java index b3c67098b0..1ee7e21ce5 100644 --- a/src/main/java/seedu/command/Command.java +++ b/src/main/java/seedu/command/Command.java @@ -1,5 +1,7 @@ package seedu.command; +import seedu.equipment.EquipmentManager; + import java.util.HashMap; /** diff --git a/src/main/java/seedu/command/CommandResult.java b/src/main/java/seedu/command/CommandResult.java index 8410a0f796..b2adfd7b02 100644 --- a/src/main/java/seedu/command/CommandResult.java +++ b/src/main/java/seedu/command/CommandResult.java @@ -1,5 +1,7 @@ package seedu.command; +import seedu.equipment.Equipment; + import java.util.ArrayList; /** diff --git a/src/main/java/seedu/command/DeleteCommand.java b/src/main/java/seedu/command/DeleteCommand.java index e16824def5..d27974d98a 100644 --- a/src/main/java/seedu/command/DeleteCommand.java +++ b/src/main/java/seedu/command/DeleteCommand.java @@ -9,7 +9,7 @@ public class DeleteCommand extends Command { private final ArrayList COMMAND_STRINGS; public static final String COMMAND_WORD = "delete"; public static final String COMMAND_DESCRIPTION = ": Deletes the equipment with the specified serial number. " - + "Parameters: s/SERIAL_NUMBER\n" + + "Parameters: s/SERIAL_NUMBER" + System.lineSeparator() + "Example: " + "delete s/SM57-1"; @@ -28,7 +28,7 @@ public DeleteCommand(ArrayList commandStrings){ * @return CommandResult with message from execution of this command */ public CommandResult execute(){ - String equipmentName = equipmentInventory.getEquipmentList().get(COMMAND_STRINGS.get(0)); + String equipmentName = equipmentInventory.getEquipmentList().get(COMMAND_STRINGS.get(0)).getItemName(); equipmentInventory.deleteEquipment(COMMAND_STRINGS.get(0)); return new CommandResult(String.format(successMessage, equipmentName,COMMAND_STRINGS.get(1))); diff --git a/src/main/java/seedu/command/ListCommand.java b/src/main/java/seedu/command/ListCommand.java index 2226364464..750badffa6 100644 --- a/src/main/java/seedu/command/ListCommand.java +++ b/src/main/java/seedu/command/ListCommand.java @@ -1,5 +1,8 @@ package seedu.command; +import seedu.equipment.Equipment; +import seedu.equipment.EquipmentType; + import java.util.ArrayList; /** @@ -11,7 +14,6 @@ public class ListCommand extends Command { /** * constructor for ListCommand with NO specified type. Initialises successMessage and usageReminder from Command - * @param commandStrings parsed user input which contains details of equipment to be viewed */ public ListCommand(){ COMMAND_STRINGS = null; @@ -32,11 +34,11 @@ public ListCommand(){ */ public ListCommand(ArrayList commandStrings){ COMMAND_STRINGS = commandStrings; - successMessage = "TOTAL QUANTITY OF %1$s: %2$d\n"; + successMessage = "TOTAL QUANTITY OF %1$s: %2$d" + System.lineSeparator(); usageReminder = COMMAND_WORD + ": print a list of all equipment in the inventory. " + "Parameters: NIL" + "Example: " - + "list\n" + + "list" + System.lineSeparator() + COMMAND_WORD + " t/Type: print a list of all equipment in the inventory of the specified type" + "Parameters: t/Type" + "Example: " @@ -56,7 +58,7 @@ public CommandResult execute(){ return new CommandResult(String.format(successMessage, listSize), equipmentArrayList); } - String typeToList = COMMAND_STRINGS.get(0); + EquipmentType typeToList = EquipmentType.valueOf(COMMAND_STRINGS.get(0)); equipmentArrayList = equipmentInventory.listEquipment(typeToList); listSize = equipmentArrayList.size(); return new CommandResult(String.format(successMessage, typeToList, listSize), equipmentArrayList); diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index ce13809c54..23c55e1b04 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -35,6 +35,10 @@ public ArrayList listEquipment(EquipmentType type) { return listOfEquipments; } + public HashMap getEquipmentList(){ + return equipmentList; + } + public ArrayList listEquipment() { return new ArrayList<>(equipmentList.values()); } From e5064645df2f91aa6290d9c505e1b754157e6ea1 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sun, 13 Mar 2022 21:32:38 +0800 Subject: [PATCH 024/229] Add UpdateCommand and Pair Class to handle updating of equipment details Fixes #21 --- src/main/java/seedu/Pair.java | 32 ++++++++ .../java/seedu/command/UpdateCommand.java | 77 +++++++++++++++++++ .../seedu/equipment/EquipmentManager.java | 5 +- src/main/java/seedu/parser/Parser.java | 24 +++--- 4 files changed, 125 insertions(+), 13 deletions(-) create mode 100644 src/main/java/seedu/Pair.java create mode 100644 src/main/java/seedu/command/UpdateCommand.java diff --git a/src/main/java/seedu/Pair.java b/src/main/java/seedu/Pair.java new file mode 100644 index 0000000000..bb1935b79b --- /dev/null +++ b/src/main/java/seedu/Pair.java @@ -0,0 +1,32 @@ +package seedu; + +/** + * Implementation of Pair which is not available in Java 11. Referenced from https://stackoverflow.com/a/59945161 + * @param the class of the key + * @param the class of the value + */ +public class Pair{ + + K key; + V value; + + public Pair(K key, V value) { + this.key = key; + this.value = value; + } + + public void setValue(V value) { + this.value = value; + } + + public V getValue() { + return value; + } + + public void setKey(K key) { + this.key = key; + } + public K getKey() { + return key; + } +} diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java new file mode 100644 index 0000000000..db1ed17de8 --- /dev/null +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -0,0 +1,77 @@ +package seedu.command; + +import seedu.Pair; + +import java.util.ArrayList; + +public class UpdateCommand extends Command { + public static final String COMMAND_WORD = "update"; + public static final String COMMAND_DESCRIPTION = ": Updates the equipment with the specified serial number. " + + "Parameters: s/SERIAL_NUMBER" + System.lineSeparator() + + "Example: " + + "update s/SM57-1"; + private String serialNumber; + + private String updateName = null, purchaseDate = null, type = null, purchaseFrom = null, cost = null; + + + /** + * constructor for UpdateCommand. Initialises successMessage and usageReminder from Command + */ + public UpdateCommand(){ + successMessage = "Equipment successfully updated: %1$s for serial number %2$s"; + usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; + } + + public CommandResult execute(){ + ArrayList> updatePairs = generateUpdatePairs(); + successMessage = equipmentInventory.updateEquipment(serialNumber, updatePairs); + + return new CommandResult(successMessage); + } + + public void setSerialNumber(String serialNumber) { + this.updateName = serialNumber; + } + + public void setUpdateName(String updateName) { + this.updateName = updateName; + } + + public void setPurchaseDate(String purchaseDate) { + this.purchaseDate = purchaseDate; + } + + public void setType(String type) { + this.type = type; + } + + public void setPurchaseFrom(String purchaseFrom) { + this.purchaseFrom = purchaseFrom; + } + + public void setCost(String cost) { + this.cost = cost; + } + + public ArrayList> generateUpdatePairs(){ + ArrayList> pairs = new ArrayList<>(); + if(updateName != null){ + pairs.add(new Pair("itemName", updateName)); + } + if(type != null){ + pairs.add(new Pair("type", type)); + } + if(cost != null){ + pairs.add(new Pair("cost", cost)); + } + if(purchaseDate != null){ + pairs.add(new Pair("purchasedDate", purchaseDate)); + } + if(purchaseFrom != null){ + pairs.add(new Pair("purchasedFrom", purchaseFrom)); + } + + return pairs; + } +} diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index 23c55e1b04..912fef7935 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -1,5 +1,7 @@ package seedu.equipment; +import seedu.Pair; + import java.util.ArrayList; import java.util.HashMap; @@ -43,8 +45,9 @@ public ArrayList listEquipment() { return new ArrayList<>(equipmentList.values()); } - public void updateEquipment(String serialNumber) { + public String updateEquipment(String serialNumber, ArrayList> updatePairs) { // To be updated + return ""; } public void deleteEquipment(String serialNumber) { diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 123a9f56b6..fe5c9a076c 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -40,6 +40,7 @@ public class Parser { ); public static final String MESSAGE_INCOMPLETE_COMMAND_MISSING_DELIMITER = "Please split your command into arguments with each argument seperated by spaces!"; + public static final String INCORRECT_COMMAND_FORMAT = "Incorrect Command format!"; public Command parseCommand(String userInput) throws IncompleteCommandException { ArrayList commandAndArgument = null; @@ -58,7 +59,6 @@ public Command parseCommand(String userInput) throws IncompleteCommandException } catch (IncompleteCommandException e) { return new IncorrectCommand(AddCommand.COMMAND_WORD + AddCommand.COMMAND_DESCRIPTION); } - break; case CheckCommand.COMMAND_WORD: try { args = prepareView(commandAndArgument.get(1)); @@ -66,7 +66,6 @@ public Command parseCommand(String userInput) throws IncompleteCommandException } catch (IncompleteCommandException e) { return new IncorrectCommand(CheckCommand.COMMAND_WORD + CheckCommand.COMMAND_DESCRIPTION); } - break; case DeleteCommand.COMMAND_WORD: try { args = prepareDelete(commandAndArgument.get(1)); @@ -74,29 +73,31 @@ public Command parseCommand(String userInput) throws IncompleteCommandException } catch (IncompleteCommandException e) { return new IncorrectCommand(DeleteCommand.COMMAND_WORD + DeleteCommand.COMMAND_DESCRIPTION); } - break; case UpdateCommand.COMMAND_WORD: try { args = extractArguments(commandAndArgument.get(1)); - UpdateCommand updateCommand = new UpdateCommand(serialNumber); + UpdateCommand updateCommand = new UpdateCommand(); for (String s : args) { int delimiterPos = s.indexOf('/'); String argType = s.substring(0, delimiterPos); String argValue = s.substring(0, delimiterPos + 1); switch (argType) { - case 'n': + case "s": + updateCommand.setSerialNumber(argValue); + break; + case "n": updateCommand.setUpdateName(argValue); break; - case 'pd': + case "pd": updateCommand.setPurchaseDate(argValue); break; - case 't': + case "t": updateCommand.setType(argValue); break; - case 'pf': + case "pf": updateCommand.setPurchaseFrom(argValue); break; - case 'c': + case "c": updateCommand.setCost(argValue); break; default: @@ -107,9 +108,9 @@ public Command parseCommand(String userInput) throws IncompleteCommandException } catch (IncompleteCommandException e) { return new IncorrectCommand(UpdateCommand.COMMAND_WORD + UpdateCommand.COMMAND_DESCRIPTION); } - break; + default: + return new IncorrectCommand(INCORRECT_COMMAND_FORMAT); } - } /** @@ -137,7 +138,6 @@ protected ArrayList extractArguments(String args) throws IncompleteComma return splitArguments; } - protected ArrayList<> /** * Prepare arguments for AddCommand by splitting up the arguments into different parts From e44a30ba6f4c13468ac76e392014e31819b492ee Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sun, 13 Mar 2022 21:57:18 +0800 Subject: [PATCH 025/229] Update code quality Add exception handling for wrong EquipmentType and wrong input for cost of equipment --- src/main/java/seedu/Pair.java | 2 +- src/main/java/seedu/command/AddCommand.java | 15 +++++++-------- src/main/java/seedu/command/CheckCommand.java | 6 +++--- src/main/java/seedu/command/Command.java | 2 ++ src/main/java/seedu/command/CommandResult.java | 4 ++-- src/main/java/seedu/command/DeleteCommand.java | 4 ++-- src/main/java/seedu/command/ListCommand.java | 10 +++++----- src/main/java/seedu/command/UpdateCommand.java | 6 +++--- 8 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/main/java/seedu/Pair.java b/src/main/java/seedu/Pair.java index bb1935b79b..f2d21ff308 100644 --- a/src/main/java/seedu/Pair.java +++ b/src/main/java/seedu/Pair.java @@ -5,7 +5,7 @@ * @param the class of the key * @param the class of the value */ -public class Pair{ +public class Pair { K key; V value; diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index 890c47364a..1ad5553f96 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -1,7 +1,6 @@ package seedu.command; import seedu.equipment.DuplicateSerialNumber; -import seedu.equipment.Equipment; import seedu.equipment.EquipmentType; import java.util.ArrayList; @@ -34,8 +33,12 @@ public AddCommand(ArrayList commandStrings){ public CommandResult execute(){ try { addEquipment(COMMAND_STRINGS); - }catch(DuplicateSerialNumber e){ + } catch (DuplicateSerialNumber e){ return new CommandResult(String.format(DUPLICATE_ITEM_ERROR, COMMAND_STRINGS.get(1))); + } catch (NullPointerException | NumberFormatException e){ + return new CommandResult(INCORRECT_COST_FORMAT); + } catch (IllegalArgumentException e) { + return new CommandResult(INCORRECT_ENUM_TYPE); } return new CommandResult(String.format(successMessage, COMMAND_STRINGS.get(0), COMMAND_STRINGS.get(1))); @@ -45,7 +48,7 @@ public CommandResult execute(){ * Uses information from the ArrayList to create a new Equipment and add it to the inventory. * @param userInput ArrayList of String which contains the individual attributes of the equipment to be added */ - public void addEquipment(ArrayList userInput) throws DuplicateSerialNumber{ + public void addEquipment(ArrayList userInput) throws DuplicateSerialNumber { String equipmentName = userInput.get(0); String serialNumber = userInput.get(1); EquipmentType type = EquipmentType.valueOf(userInput.get(2)); @@ -53,10 +56,6 @@ public void addEquipment(ArrayList userInput) throws DuplicateSerialNumb String purchasedFrom = userInput.get(4); String purchasedDate = userInput.get(5); - try { - equipmentInventory.addEquipment(equipmentName, serialNumber, type, cost, purchasedFrom, purchasedDate); - }catch(DuplicateSerialNumber e){ - throw new DuplicateSerialNumber(); - } + equipmentInventory.addEquipment(equipmentName, serialNumber, type, cost, purchasedFrom, purchasedDate); } } diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index bfc4b26599..6aa8dae83a 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -12,7 +12,7 @@ public class CheckCommand extends Command { private final ArrayList COMMAND_STRINGS; public static final String COMMAND_WORD = "check"; public static final String COMMAND_DESCRIPTION = ": Gives details of the equipment with the specified name. " - + "Parameters: n/ITEM_NAME\n" + + "Parameters: n/ITEM_NAME" + System.lineSeparator() + "Example: " + "check n/MixerC"; @@ -20,7 +20,7 @@ public class CheckCommand extends Command { * constructor for CheckCommand. Initialises successMessage and usageReminder from Command * @param commandStrings parsed user input which contains details of equipment to be viewed */ - public CheckCommand(ArrayList commandStrings){ + public CheckCommand(ArrayList commandStrings) { COMMAND_STRINGS = commandStrings; successMessage = "Here are the equipment matching to '%1$s':" + System.lineSeparator(); usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; @@ -30,7 +30,7 @@ public CheckCommand(ArrayList commandStrings){ * Gives details of equipment specified by name * @return CommandResult with message from execution of this command */ - public CommandResult execute(){ + public CommandResult execute() { String name, sn, purchasedFrom, purchasedDate; EquipmentType type; double cost; diff --git a/src/main/java/seedu/command/Command.java b/src/main/java/seedu/command/Command.java index 1ee7e21ce5..1e4a0b7ef0 100644 --- a/src/main/java/seedu/command/Command.java +++ b/src/main/java/seedu/command/Command.java @@ -13,6 +13,8 @@ public abstract class Command { protected String successMessage; public String usageReminder; protected EquipmentManager equipmentInventory; + protected final String INCORRECT_ENUM_TYPE = "Wrong type of equipment. The allowed types are: MICROPHONE, SPEAKER, STAND, CABLE"; + protected final String INCORRECT_COST_FORMAT = "Please enter numbers only for cost and omit symbols"; public abstract CommandResult execute(); diff --git a/src/main/java/seedu/command/CommandResult.java b/src/main/java/seedu/command/CommandResult.java index b2adfd7b02..b57c99af1a 100644 --- a/src/main/java/seedu/command/CommandResult.java +++ b/src/main/java/seedu/command/CommandResult.java @@ -13,12 +13,12 @@ public class CommandResult { private final String RESULT_TO_SHOW; private final ArrayList RELEVANT_EQUIPMENT; - public CommandResult(String result){ + public CommandResult(String result) { RESULT_TO_SHOW = result; RELEVANT_EQUIPMENT = null; } - public CommandResult(String result, ArrayList equipmentList){ + public CommandResult(String result, ArrayList equipmentList) { RESULT_TO_SHOW = result; RELEVANT_EQUIPMENT = equipmentList; } diff --git a/src/main/java/seedu/command/DeleteCommand.java b/src/main/java/seedu/command/DeleteCommand.java index d27974d98a..0852685126 100644 --- a/src/main/java/seedu/command/DeleteCommand.java +++ b/src/main/java/seedu/command/DeleteCommand.java @@ -17,7 +17,7 @@ public class DeleteCommand extends Command { * constructor for DeleteCommand. Initialises successMessage and usageReminder from Command * @param commandStrings parsed user input which contains details of equipment to be deleted */ - public DeleteCommand(ArrayList commandStrings){ + public DeleteCommand(ArrayList commandStrings) { COMMAND_STRINGS = commandStrings; successMessage = "Equipment successfully deleted: %1$s, serial number %2$s"; usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; @@ -27,7 +27,7 @@ public DeleteCommand(ArrayList commandStrings){ * Deletes equipment specified by serial number * @return CommandResult with message from execution of this command */ - public CommandResult execute(){ + public CommandResult execute() { String equipmentName = equipmentInventory.getEquipmentList().get(COMMAND_STRINGS.get(0)).getItemName(); equipmentInventory.deleteEquipment(COMMAND_STRINGS.get(0)); diff --git a/src/main/java/seedu/command/ListCommand.java b/src/main/java/seedu/command/ListCommand.java index 750badffa6..002a693bb2 100644 --- a/src/main/java/seedu/command/ListCommand.java +++ b/src/main/java/seedu/command/ListCommand.java @@ -15,13 +15,13 @@ public class ListCommand extends Command { /** * constructor for ListCommand with NO specified type. Initialises successMessage and usageReminder from Command */ - public ListCommand(){ + public ListCommand() { COMMAND_STRINGS = null; - successMessage = "TOTAL QUANTITY OF EQUIPMENT: %1$d\n"; + successMessage = "TOTAL QUANTITY OF EQUIPMENT: %1$d" + System.lineSeparator(); usageReminder = COMMAND_WORD + ": print a list of all equipment in the inventory. " + "Parameters: NIL" + "Example: " - + "list\n" + + "list" + System.lineSeparator() + COMMAND_WORD + " t/Type: print a list of all equipment in the inventory of the specified type" + "Parameters: t/Type" + "Example: " @@ -32,7 +32,7 @@ public ListCommand(){ * constructor for ListCommand with specified type. Initialises successMessage and usageReminder from Command * @param commandStrings parsed user input which contains details of equipment to be viewed */ - public ListCommand(ArrayList commandStrings){ + public ListCommand(ArrayList commandStrings) { COMMAND_STRINGS = commandStrings; successMessage = "TOTAL QUANTITY OF %1$s: %2$d" + System.lineSeparator(); usageReminder = COMMAND_WORD + ": print a list of all equipment in the inventory. " @@ -49,7 +49,7 @@ public ListCommand(ArrayList commandStrings){ * List all equipment or list equipment of specified type * @return CommandResult with message from execution of this command */ - public CommandResult execute(){ + public CommandResult execute() { int listSize; ArrayList equipmentArrayList; if(COMMAND_STRINGS == null){ diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java index db1ed17de8..1b467805bb 100644 --- a/src/main/java/seedu/command/UpdateCommand.java +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -18,12 +18,12 @@ public class UpdateCommand extends Command { /** * constructor for UpdateCommand. Initialises successMessage and usageReminder from Command */ - public UpdateCommand(){ + public UpdateCommand() { successMessage = "Equipment successfully updated: %1$s for serial number %2$s"; usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; } - public CommandResult execute(){ + public CommandResult execute() { ArrayList> updatePairs = generateUpdatePairs(); successMessage = equipmentInventory.updateEquipment(serialNumber, updatePairs); @@ -54,7 +54,7 @@ public void setCost(String cost) { this.cost = cost; } - public ArrayList> generateUpdatePairs(){ + public ArrayList> generateUpdatePairs() { ArrayList> pairs = new ArrayList<>(); if(updateName != null){ pairs.add(new Pair("itemName", updateName)); From b31e9126c9bded6ed03990883869894e8b70e87d Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 15 Mar 2022 21:30:07 +0800 Subject: [PATCH 026/229] Add code in Duke to run program and call for Parser and Commands --- src/main/java/seedu/duke/Duke.java | 30 ++++++++++++++++++++++++-- src/main/java/seedu/parser/Parser.java | 2 +- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java index 5c74e68d59..20c4dc6f83 100644 --- a/src/main/java/seedu/duke/Duke.java +++ b/src/main/java/seedu/duke/Duke.java @@ -1,8 +1,15 @@ package seedu.duke; +import seedu.command.Command; +import seedu.command.CommandResult; +import seedu.equipment.EquipmentManager; +import seedu.parser.Parser; + import java.util.Scanner; public class Duke { + private EquipmentManager equipmentInventory = new EquipmentManager(); + /** * Main entry-point for the java.duke.Duke application. */ @@ -13,9 +20,28 @@ public static void main(String[] args) { + "| |_| | |_| | < __/\n" + "|____/ \\__,_|_|\\_\\___|\n"; System.out.println("Hello from\n" + logo); - System.out.println("What is your name?"); + System.out.println("What do you want to do?"); + + new Duke().runCommandLoop(); + } + private void runCommandLoop() { Scanner in = new Scanner(System.in); - System.out.println("Hello " + in.nextLine()); + String userCommand = in.nextLine(); + Command command; + CommandResult result; + while (!userCommand.equals("bye")) { + command = new Parser().parseCommand(userCommand); + result = executeCommand(command); + System.out.println(result.getResultToShow()); + + userCommand = in.nextLine(); + } + } + + private CommandResult executeCommand(Command command) { + command.setEquipmentInventory(equipmentInventory); + CommandResult result = command.execute(); + return result; } } diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index fe5c9a076c..da2d752371 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -42,7 +42,7 @@ public class Parser { "Please split your command into arguments with each argument seperated by spaces!"; public static final String INCORRECT_COMMAND_FORMAT = "Incorrect Command format!"; - public Command parseCommand(String userInput) throws IncompleteCommandException { + public Command parseCommand(String userInput) { ArrayList commandAndArgument = null; ArrayList args = null; try { From 2eba325a8920225cdd6375fdb3f77518dde66a81 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Wed, 16 Mar 2022 01:00:41 +0800 Subject: [PATCH 027/229] Add JUnit tests for AddCommand --- src/main/java/seedu/command/AddCommand.java | 2 +- src/main/java/seedu/command/CheckCommand.java | 2 +- src/main/java/seedu/command/Command.java | 8 +- .../java/seedu/command/CommandResult.java | 14 +++ .../java/seedu/command/DeleteCommand.java | 4 +- src/main/java/seedu/command/ListCommand.java | 4 +- .../java/seedu/command/UpdateCommand.java | 12 +-- src/main/java/seedu/duke/Duke.java | 2 +- src/main/java/seedu/equipment/Equipment.java | 15 ++++ .../java/seedu/command/AddCommandTest.java | 87 +++++++++++++++++++ 10 files changed, 134 insertions(+), 16 deletions(-) create mode 100644 src/test/java/seedu/command/AddCommandTest.java diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index 1ad5553f96..02b7e24b14 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -56,6 +56,6 @@ public void addEquipment(ArrayList userInput) throws DuplicateSerialNumb String purchasedFrom = userInput.get(4); String purchasedDate = userInput.get(5); - equipmentInventory.addEquipment(equipmentName, serialNumber, type, cost, purchasedFrom, purchasedDate); + equipmentManager.addEquipment(equipmentName, serialNumber, type, cost, purchasedFrom, purchasedDate); } } diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index 6aa8dae83a..f6a1bcffc1 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -35,7 +35,7 @@ public CommandResult execute() { EquipmentType type; double cost; - ArrayList equipment = equipmentInventory.checkEquipment(COMMAND_STRINGS.get(0)); + ArrayList equipment = equipmentManager.checkEquipment(COMMAND_STRINGS.get(0)); return new CommandResult(String.format(successMessage, COMMAND_STRINGS.get(0)), equipment); } diff --git a/src/main/java/seedu/command/Command.java b/src/main/java/seedu/command/Command.java index 1e4a0b7ef0..a42875c018 100644 --- a/src/main/java/seedu/command/Command.java +++ b/src/main/java/seedu/command/Command.java @@ -2,8 +2,6 @@ import seedu.equipment.EquipmentManager; -import java.util.HashMap; - /** * Abstract parent class for all types of commands */ @@ -12,7 +10,7 @@ public abstract class Command { protected String successMessage; public String usageReminder; - protected EquipmentManager equipmentInventory; + protected EquipmentManager equipmentManager; protected final String INCORRECT_ENUM_TYPE = "Wrong type of equipment. The allowed types are: MICROPHONE, SPEAKER, STAND, CABLE"; protected final String INCORRECT_COST_FORMAT = "Please enter numbers only for cost and omit symbols"; @@ -21,4 +19,8 @@ public abstract class Command { public String getUsageReminder(){ return usageReminder; } + + public void setEquipmentManager(EquipmentManager equipmentManager) { + this.equipmentManager = equipmentManager; + } } diff --git a/src/main/java/seedu/command/CommandResult.java b/src/main/java/seedu/command/CommandResult.java index b57c99af1a..7172b2afba 100644 --- a/src/main/java/seedu/command/CommandResult.java +++ b/src/main/java/seedu/command/CommandResult.java @@ -3,6 +3,7 @@ import seedu.equipment.Equipment; import java.util.ArrayList; +import java.util.Objects; /** * Represents the result of a command execution. @@ -30,4 +31,17 @@ public String getResultToShow(){ public ArrayList getRelevantEquipment(){ return RELEVANT_EQUIPMENT; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CommandResult that = (CommandResult) o; + return RESULT_TO_SHOW.equals(that.RESULT_TO_SHOW) && Objects.equals(RELEVANT_EQUIPMENT, that.RELEVANT_EQUIPMENT); + } + + @Override + public int hashCode() { + return Objects.hash(RESULT_TO_SHOW, RELEVANT_EQUIPMENT); + } } diff --git a/src/main/java/seedu/command/DeleteCommand.java b/src/main/java/seedu/command/DeleteCommand.java index 0852685126..a8f289b428 100644 --- a/src/main/java/seedu/command/DeleteCommand.java +++ b/src/main/java/seedu/command/DeleteCommand.java @@ -28,8 +28,8 @@ public DeleteCommand(ArrayList commandStrings) { * @return CommandResult with message from execution of this command */ public CommandResult execute() { - String equipmentName = equipmentInventory.getEquipmentList().get(COMMAND_STRINGS.get(0)).getItemName(); - equipmentInventory.deleteEquipment(COMMAND_STRINGS.get(0)); + String equipmentName = equipmentManager.getEquipmentList().get(COMMAND_STRINGS.get(0)).getItemName(); + equipmentManager.deleteEquipment(COMMAND_STRINGS.get(0)); return new CommandResult(String.format(successMessage, equipmentName,COMMAND_STRINGS.get(1))); } diff --git a/src/main/java/seedu/command/ListCommand.java b/src/main/java/seedu/command/ListCommand.java index 002a693bb2..083d0bf960 100644 --- a/src/main/java/seedu/command/ListCommand.java +++ b/src/main/java/seedu/command/ListCommand.java @@ -53,13 +53,13 @@ public CommandResult execute() { int listSize; ArrayList equipmentArrayList; if(COMMAND_STRINGS == null){ - equipmentArrayList = equipmentInventory.listEquipment(); + equipmentArrayList = equipmentManager.listEquipment(); listSize = equipmentArrayList.size(); return new CommandResult(String.format(successMessage, listSize), equipmentArrayList); } EquipmentType typeToList = EquipmentType.valueOf(COMMAND_STRINGS.get(0)); - equipmentArrayList = equipmentInventory.listEquipment(typeToList); + equipmentArrayList = equipmentManager.listEquipment(typeToList); listSize = equipmentArrayList.size(); return new CommandResult(String.format(successMessage, typeToList, listSize), equipmentArrayList); } diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java index 1b467805bb..313b9e1b58 100644 --- a/src/main/java/seedu/command/UpdateCommand.java +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -25,7 +25,7 @@ public UpdateCommand() { public CommandResult execute() { ArrayList> updatePairs = generateUpdatePairs(); - successMessage = equipmentInventory.updateEquipment(serialNumber, updatePairs); + successMessage = equipmentManager.updateEquipment(serialNumber, updatePairs); return new CommandResult(successMessage); } @@ -56,19 +56,19 @@ public void setCost(String cost) { public ArrayList> generateUpdatePairs() { ArrayList> pairs = new ArrayList<>(); - if(updateName != null){ + if (updateName != null) { pairs.add(new Pair("itemName", updateName)); } - if(type != null){ + if (type != null) { pairs.add(new Pair("type", type)); } - if(cost != null){ + if (cost != null) { pairs.add(new Pair("cost", cost)); } - if(purchaseDate != null){ + if (purchaseDate != null) { pairs.add(new Pair("purchasedDate", purchaseDate)); } - if(purchaseFrom != null){ + if (purchaseFrom != null) { pairs.add(new Pair("purchasedFrom", purchaseFrom)); } diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java index 20c4dc6f83..a52fd55916 100644 --- a/src/main/java/seedu/duke/Duke.java +++ b/src/main/java/seedu/duke/Duke.java @@ -40,7 +40,7 @@ private void runCommandLoop() { } private CommandResult executeCommand(Command command) { - command.setEquipmentInventory(equipmentInventory); + command.setEquipmentManager(equipmentInventory); CommandResult result = command.execute(); return result; } diff --git a/src/main/java/seedu/equipment/Equipment.java b/src/main/java/seedu/equipment/Equipment.java index 78aae7ac44..3845c7dc03 100644 --- a/src/main/java/seedu/equipment/Equipment.java +++ b/src/main/java/seedu/equipment/Equipment.java @@ -1,5 +1,7 @@ package seedu.equipment; +import java.util.Objects; + public class Equipment { private String itemName; private String serialNumber; @@ -64,4 +66,17 @@ public String getPurchasedDate() { public void setPurchasedDate(String purchasedDate) { this.purchasedDate = purchasedDate; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Equipment equipment = (Equipment) o; + return Double.compare(equipment.cost, cost) == 0 && itemName.equals(equipment.itemName) && serialNumber.equals(equipment.serialNumber) && type == equipment.type && purchasedFrom.equals(equipment.purchasedFrom) && purchasedDate.equals(equipment.purchasedDate); + } + + @Override + public int hashCode() { + return Objects.hash(itemName, serialNumber, type, cost, purchasedFrom, purchasedDate); + } } diff --git a/src/test/java/seedu/command/AddCommandTest.java b/src/test/java/seedu/command/AddCommandTest.java new file mode 100644 index 0000000000..085d9f391a --- /dev/null +++ b/src/test/java/seedu/command/AddCommandTest.java @@ -0,0 +1,87 @@ +package seedu.command; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import seedu.equipment.DuplicateSerialNumber; +import seedu.equipment.Equipment; +import seedu.equipment.EquipmentManager; +import seedu.equipment.EquipmentType; +import seedu.parser.Parser; + +import java.util.ArrayList; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; + +class AddCommandTest { + AddCommand addCommand; + ArrayList userInput = new ArrayList<>( + Arrays.asList("Speaker B", "S1404115ASF", "SPEAKER", "1000", "Loud Technologies", "2022-02-23") + ); + +// @BeforeEach +// void setup() { +// addCommand = new AddCommand(userInput); +// } + + @Test + void execute_duplicateSerialNumber_exceptionThrown() throws DuplicateSerialNumber { + addCommand.setEquipmentManager(new EquipmentManager()); + EquipmentManager equipmentManager = addCommand.equipmentManager; + equipmentManager.addEquipment("Speaker B", + "S1404115ASF", + EquipmentType.valueOf("SPEAKER"), + 1000, + "Loud Technologies", + "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(){ + addCommand = new AddCommand(new ArrayList<>( + Arrays.asList("Speaker B", "S1404115ASF", "SPEAKER", "$1000", "Loud Technologies", "2022-02-23") + )); + + CommandResult expectedResult = new CommandResult("Please enter numbers only for cost and omit symbols"); + CommandResult actualResult = addCommand.execute(); + assertEquals(expectedResult, actualResult); + } + + @Test + void execute_incorrectEnumType_exceptionThrown() { + addCommand = new AddCommand(new ArrayList<>( + Arrays.asList("Speaker B", "S1404115ASF", "SPEAKERS", "1000", "Loud Technologies", "2022-02-23") + )); + addCommand.setEquipmentManager(new EquipmentManager()); + EquipmentManager equipmentManager = addCommand.equipmentManager; + + CommandResult expectedResult = new CommandResult("Wrong type of equipment. The allowed types are: MICROPHONE, SPEAKER, STAND, CABLE"); + CommandResult actualResult = addCommand.execute(); + assertEquals(expectedResult, actualResult); + } + + @Test + void addEquipment_validArrayListString_success() throws DuplicateSerialNumber { + 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", + "2022-02-23"); + + addCommand.addEquipment(userInput); + Equipment actualEquipment = equipmentManager.listEquipment().get(equipmentListOriginalSize); + + assertEquals(equipmentListOriginalSize + 1, equipmentManager.getEquipmentList().size()); + assertEquals(expectedEquipment, actualEquipment); + } +} \ No newline at end of file From e9fea229cc25668da4d67d00d6e7ddabf74c9186 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Wed, 16 Mar 2022 22:44:02 +0800 Subject: [PATCH 028/229] Fix Parser bugs, including prepareAdd method Modified call to matcher.group so that individual capturing groups can be added to the returned ArrayList separately Specified argument length requirement for prepareAdd method in case of excess arguments (to be completed) --- src/main/java/seedu/parser/Parser.java | 55 +++++++++++----------- src/test/java/seedu/parser/ParserTest.java | 33 ++++++++++++- 2 files changed, 59 insertions(+), 29 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index da2d752371..e1199d9066 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -1,6 +1,5 @@ package seedu.parser; -import java.lang.reflect.Array; import java.util.ArrayList; import seedu.command.*; @@ -21,13 +20,14 @@ public class Parser { */ public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s+(?.+)"); public static final Pattern ADD_COMMAND_FORMAT = Pattern.compile( - "n/(?.+)" + "\\s+" + - "sn/(?.+)" + "\\s+" + - "t/(?.+)" + "\\s+" + - "c/(?.+)" + "\\s+" + - "pf/(?.+)" + "\\s+" + - "pd/(?.+)" + "n\\/(?.+)" + "\\s+" + + "sn\\/(?.+)" + "\\s+" + + "t\\/(?.+)" + "\\s+" + + "c\\/(?.+)" + "\\s+" + + "pf\\/(?.+)" + "\\s+" + + "pd\\/(?.+)" ); + public static final int PREPAREADD_REQUIRED_ARGUMENT_COUNT = 6; public static final Pattern VIEW_COMMAND_FORMAT = Pattern.compile("n/(?.+)"); public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("s/(?.+)"); // Pattern extracts first n-1 tags @@ -43,8 +43,8 @@ public class Parser { public static final String INCORRECT_COMMAND_FORMAT = "Incorrect Command format!"; public Command parseCommand(String userInput) { - ArrayList commandAndArgument = null; - ArrayList args = null; + ArrayList commandAndArgument; + ArrayList args; try { commandAndArgument = splitCommandTerm(userInput); } catch (IncompleteCommandException e) { @@ -82,9 +82,6 @@ public Command parseCommand(String userInput) { String argType = s.substring(0, delimiterPos); String argValue = s.substring(0, delimiterPos + 1); switch (argType) { - case "s": - updateCommand.setSerialNumber(argValue); - break; case "n": updateCommand.setUpdateName(argValue); break; @@ -111,14 +108,15 @@ public Command parseCommand(String userInput) { default: return new IncorrectCommand(INCORRECT_COMMAND_FORMAT); } + } /** * Splits main arguments into split tags with each substring * - * @param args + * @param args String to be split into substrings * @return ArrayList of two elements - * @throws IncompleteCommandException + * @throws IncompleteCommandException if no parameters found */ protected ArrayList extractArguments(String args) throws IncompleteCommandException { int lastIndex = 0; @@ -150,51 +148,52 @@ protected ArrayList extractArguments(String args) throws IncompleteComma * 4. purchasedFrom : String of vendor name, suggest adhering to one consistent naming scheme * 5. purchasedDate : String representation for now, possibility for future support * - * @param args + * @param args String to be split into substrings * @return ArrayList of arguments * @throws IncompleteCommandException if no match found */ protected ArrayList prepareAdd(String args) throws IncompleteCommandException { final Matcher matcher = ADD_COMMAND_FORMAT.matcher(args.trim()); // validate arg string format - if (!matcher.matches()) { + int matchCount = matcher.groupCount(); + if (!matcher.matches() || matchCount != PREPAREADD_REQUIRED_ARGUMENT_COUNT) { throw new IncompleteCommandException("Add command values are incomplete or missing!"); } - ArrayList results = new ArrayList(); - for (int i = 0; i < matcher.groupCount(); i++) { - results.add(matcher.group()); + ArrayList results = new ArrayList<>(); + for (int i = 1; i <= matchCount; i++) { + results.add(matcher.group(i)); } return results; } /** - * Prepare argument for CheckCommand by removing the preceeding "n/" prefix + * Prepare argument for CheckCommand by removing the preceding "n/" prefix * - * @param args + * @param args String to be split into substrings * @return ArrayList of one element (assumes rest of string is item name) - * @throws IncompleteCommandException + * @throws IncompleteCommandException if no match found */ protected ArrayList prepareView(String args) throws IncompleteCommandException { final Matcher matcher = VIEW_COMMAND_FORMAT.matcher(args.trim()); if (!matcher.matches()) { throw new IncompleteCommandException("View command values are incomplete or missing!"); } - return new ArrayList(Collections.singleton(matcher.group())); + return new ArrayList<>(Collections.singleton(matcher.group())); } /** - * Prepare argument for DeleteCommand by removing the preceeding "s/" prefix + * Prepare argument for DeleteCommand by removing the preceding "s/" prefix * - * @param args + * @param args String to be split into substrings * @return ArrayList of one element (assumes rest of string is serial number) - * @throws IncompleteCommandException + * @throws IncompleteCommandException if no match found */ protected ArrayList prepareDelete(String args) throws IncompleteCommandException { final Matcher matcher = DELETE_COMMAND_FORMAT.matcher(args.trim()); if (!matcher.matches()) { throw new IncompleteCommandException("Delete command values are incomplete or missing!"); } - return new ArrayList(Collections.singleton(matcher.group())); + return new ArrayList<>(Collections.singleton(matcher.group())); } @@ -202,7 +201,7 @@ protected ArrayList prepareDelete(String args) throws IncompleteCommandE * 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. * - * @param userInput + * @param userInput String to be split into substrings * @return ArrayList of String, first element being the command term and the second element being arguments * @throws IncompleteCommandException if no space is found */ diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 8b877ac275..2565e9f352 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -5,6 +5,7 @@ import seedu.parser.IncompleteCommandException; import seedu.parser.Parser; +import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; @@ -33,7 +34,7 @@ void splitCommandTerm_validCommand_success() throws IncompleteCommandException { } @Test - void splitCommandTerm_incompleteCommand_exceptionThrown() { + void splitCommandTerm_noSpaceDelimiter_exceptionThrown() { ArrayList unexpectedResult = new ArrayList<>( Arrays.asList("add", "n/ITEM_NAMEsn/SERIAL_NUMBERt/TYPEc/COSTpf/PURCHASED_FROMpd/PURCHASED_DATE") ); @@ -57,4 +58,34 @@ void prepareAdd_validAddString_success() throws IncompleteCommandException { assertEquals(expectedResult, actualResult); } + @Test + void prepareAdd_insufficientArguments_exceptionThrown() { + ArrayList unexpectedResult = new ArrayList<>( + Arrays.asList("Speaker B", "S1404115ASF", "1000", "Loud Technologies", "2022-02-23") + ); + try { + ArrayList actualResult = parser.prepareAdd( + "n/Speaker B sn/S1404115ASF c/1000 pf/Loud Technologies pd/2022-02-23"); + assertEquals(unexpectedResult, actualResult); + fail(); + } catch (IncompleteCommandException e) { + assertEquals("Add command values are incomplete or missing!", e.getMessage()); + } + } + + @Test + void prepareAdd_argumentEnteredTwice_exceptionThrown() { + ArrayList unexpectedResult = new ArrayList<>( + Arrays.asList("Speaker B", "S1404115ASF", "Speaker", "1000", "1000", "Loud Technologies", "2022-02-23") + ); + try { + ArrayList actualResult = parser.prepareAdd( + "n/Speaker B sn/S1404115ASF t/Speaker c/1000 c/1000 pf/Loud Technologies pd/2022-02-23"); + assertEquals(unexpectedResult, actualResult); + fail(); + } catch (IncompleteCommandException e) { + assertEquals("Add command values are incomplete or missing!", e.getMessage()); + } + } + } \ No newline at end of file From 774483fe605e84a4ea397a191c6c57f4cef2bb73 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Wed, 16 Mar 2022 22:51:02 +0800 Subject: [PATCH 029/229] Extract prepareUpdate method Not very sure about this change, seems to violate SLAP principles? --- src/main/java/seedu/parser/Parser.java | 56 ++++++++++++++------------ 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index e1199d9066..bf7a00597d 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -76,32 +76,7 @@ public Command parseCommand(String userInput) { case UpdateCommand.COMMAND_WORD: try { args = extractArguments(commandAndArgument.get(1)); - UpdateCommand updateCommand = new UpdateCommand(); - for (String s : args) { - int delimiterPos = s.indexOf('/'); - String argType = s.substring(0, delimiterPos); - String argValue = s.substring(0, delimiterPos + 1); - switch (argType) { - case "n": - updateCommand.setUpdateName(argValue); - break; - case "pd": - updateCommand.setPurchaseDate(argValue); - break; - case "t": - updateCommand.setType(argValue); - break; - case "pf": - updateCommand.setPurchaseFrom(argValue); - break; - case "c": - updateCommand.setCost(argValue); - break; - default: - System.out.println("`" + argValue + "` not updated for type " + argType +": Unrecognised Tag"); - } - } - return updateCommand; + return prepareUpdate(args); } catch (IncompleteCommandException e) { return new IncorrectCommand(UpdateCommand.COMMAND_WORD + UpdateCommand.COMMAND_DESCRIPTION); } @@ -111,6 +86,35 @@ public Command parseCommand(String userInput) { } + protected UpdateCommand prepareUpdate(ArrayList args) { + UpdateCommand updateCommand = new UpdateCommand(); + for (String s : args) { + int delimiterPos = s.indexOf('/'); + String argType = s.substring(0, delimiterPos); + String argValue = s.substring(0, delimiterPos + 1); + switch (argType) { + case "n": + updateCommand.setUpdateName(argValue); + break; + case "pd": + updateCommand.setPurchaseDate(argValue); + break; + case "t": + updateCommand.setType(argValue); + break; + case "pf": + updateCommand.setPurchaseFrom(argValue); + break; + case "c": + updateCommand.setCost(argValue); + break; + default: + System.out.println("`" + argValue + "` not updated for type " + argType +": Unrecognised Tag"); + } + } + return updateCommand; + } + /** * Splits main arguments into split tags with each substring * From 0c6330aa68ce56293f128ec26ffb738a61f32fa3 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Wed, 16 Mar 2022 23:30:50 +0800 Subject: [PATCH 030/229] Add documentation for prepareUpdate and modify UpdateCommand UpdateCommand will be initialised with no serialNumber - prepareUpdate will check for lack of serialNumber and throw an appropriate exception to result in an IncorrectCommandClass being returned --- .../java/seedu/command/UpdateCommand.java | 9 ++++++- src/main/java/seedu/parser/Parser.java | 27 +++++++++++++++---- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java index 313b9e1b58..b39ff2271e 100644 --- a/src/main/java/seedu/command/UpdateCommand.java +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -30,8 +30,12 @@ public CommandResult execute() { return new CommandResult(successMessage); } + public String getSerialNumber() { + return serialNumber; + } + public void setSerialNumber(String serialNumber) { - this.updateName = serialNumber; + this.serialNumber = serialNumber; } public void setUpdateName(String updateName) { @@ -71,6 +75,9 @@ public ArrayList> generateUpdatePairs() { if (purchaseFrom != null) { pairs.add(new Pair("purchasedFrom", purchaseFrom)); } + if (serialNumber != null) { + pairs.add(new Pair("serialNumber", serialNumber)); + } return pairs; } diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index bf7a00597d..55719c623d 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -30,11 +30,11 @@ public class Parser { public static final int PREPAREADD_REQUIRED_ARGUMENT_COUNT = 6; public static final Pattern VIEW_COMMAND_FORMAT = Pattern.compile("n/(?.+)"); public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("s/(?.+)"); - // Pattern extracts first n-1 tags + // ARGUMENT_FORMAT extracts first n-1 tags public static final Pattern ARGUMENT_FORMAT = Pattern.compile( "((?:sn|n|t|c|pf|pd)\\/[\\w\\s\\-]+?)\\s+(?=sn|n|t|c|pf|pd)" ); - // Extracts last tag + // ARGUMENT_TRAILING_FORMAT extracts last tag public static final Pattern ARGUMENT_TRAILING_FORMAT = Pattern.compile( "(? args) { + /** + * Create UpdateCommand class containing all arguments required to update a given item + * + * Should multiple arguments specifying the same argument parameter (e.g. 'c/1000' and 'c/2000') is given, + * the previous arguments passed in will be overwritten by the most recent parameter ('c/2000' in example). + * + * @param args ArrayList of arguments for an Update Command + * @return Command object + */ + protected Command prepareUpdate(ArrayList args) throws IncompleteCommandException { UpdateCommand updateCommand = new UpdateCommand(); for (String s : args) { int delimiterPos = s.indexOf('/'); + // the case where delimiterPos = -1 is impossible as + // ARGUMENT_FORMAT and ARGUMENT_TRAILING_FORMAT regex requires a '/' + assert delimiterPos != -1: "Each args will need to include minimally a '/' to split arg and value upon"; String argType = s.substring(0, delimiterPos); - String argValue = s.substring(0, delimiterPos + 1); + String argValue = s.substring(delimiterPos + 1); switch (argType) { case "n": updateCommand.setUpdateName(argValue); @@ -108,10 +120,15 @@ protected UpdateCommand prepareUpdate(ArrayList args) { case "c": updateCommand.setCost(argValue); break; + case "sn": + updateCommand.setSerialNumber(argValue); + break; default: - System.out.println("`" + argValue + "` not updated for type " + argType +": Unrecognised Tag"); + System.out.println("`" + argValue + "` not updated for type " + argType + ": Unrecognised Tag"); } } + if (updateCommand.getSerialNumber() == null) + return new IncorrectCommand("Serial Number is required to update an item!"); return updateCommand; } From a73f838b457a1d00672d73f363e89c49cabba43e Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 17 Mar 2022 03:44:04 +0800 Subject: [PATCH 031/229] Add IncorrectCommand equals method for JUnit Test Suggest to include equals definition in abstract class --- src/main/java/seedu/command/IncorrectCommand.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/seedu/command/IncorrectCommand.java b/src/main/java/seedu/command/IncorrectCommand.java index efcb3d066c..abd83828fa 100644 --- a/src/main/java/seedu/command/IncorrectCommand.java +++ b/src/main/java/seedu/command/IncorrectCommand.java @@ -17,4 +17,8 @@ public CommandResult execute() { return new CommandResult(feedbackToUser); } + public boolean equals(IncorrectCommand other) { + return feedbackToUser.equals(other.feedbackToUser); + } + } From 8e3c98b17e22ba9c144bce58facefe3d0d9e01d8 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 17 Mar 2022 03:45:21 +0800 Subject: [PATCH 032/229] Fix bugs related to Add, Delete, Update and Check commands Implement ParserTest JUnit Testcases --- src/main/java/seedu/parser/Parser.java | 182 +++++++++++---------- src/test/java/seedu/parser/ParserTest.java | 176 +++++++++++++++++++- 2 files changed, 264 insertions(+), 94 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 55719c623d..e8b49fbaa3 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -27,7 +27,6 @@ public class Parser { "pf\\/(?.+)" + "\\s+" + "pd\\/(?.+)" ); - public static final int PREPAREADD_REQUIRED_ARGUMENT_COUNT = 6; public static final Pattern VIEW_COMMAND_FORMAT = Pattern.compile("n/(?.+)"); public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("s/(?.+)"); // ARGUMENT_FORMAT extracts first n-1 tags @@ -42,6 +41,12 @@ public class Parser { "Please split your command into arguments with each argument seperated by spaces!"; public static final String INCORRECT_COMMAND_FORMAT = "Incorrect Command format!"; + /** + * Interpret the command requested by the user and returns a corresponding Command object + * + * @param userInput Raw string of input values + * @return command of parent class Command with parameters specified + */ public Command parseCommand(String userInput) { ArrayList commandAndArgument; ArrayList args; @@ -87,77 +92,24 @@ public Command parseCommand(String userInput) { } /** - * Create UpdateCommand class containing all arguments required to update a given item - * - * Should multiple arguments specifying the same argument parameter (e.g. 'c/1000' and 'c/2000') is given, - * the previous arguments passed in will be overwritten by the most recent parameter ('c/2000' in example). - * - * @param args ArrayList of arguments for an Update Command - * @return Command object - */ - protected Command prepareUpdate(ArrayList args) throws IncompleteCommandException { - UpdateCommand updateCommand = new UpdateCommand(); - for (String s : args) { - int delimiterPos = s.indexOf('/'); - // the case where delimiterPos = -1 is impossible as - // ARGUMENT_FORMAT and ARGUMENT_TRAILING_FORMAT regex requires a '/' - assert delimiterPos != -1: "Each args will need to include minimally a '/' to split arg and value upon"; - String argType = s.substring(0, delimiterPos); - String argValue = s.substring(delimiterPos + 1); - switch (argType) { - case "n": - updateCommand.setUpdateName(argValue); - break; - case "pd": - updateCommand.setPurchaseDate(argValue); - break; - case "t": - updateCommand.setType(argValue); - break; - case "pf": - updateCommand.setPurchaseFrom(argValue); - break; - case "c": - updateCommand.setCost(argValue); - break; - case "sn": - updateCommand.setSerialNumber(argValue); - break; - default: - System.out.println("`" + argValue + "` not updated for type " + argType + ": Unrecognised Tag"); - } - } - if (updateCommand.getSerialNumber() == null) - return new IncorrectCommand("Serial Number is required to update an item!"); - return updateCommand; - } - - /** - * Splits main arguments into split tags with each substring + * 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. * - * @param args String to be split into substrings - * @return ArrayList of two elements - * @throws IncompleteCommandException if no parameters found + * @param userInput String to be split into substrings + * @return ArrayList of String, first element being the command term and the second element being arguments + * @throws IncompleteCommandException if no space is found */ - protected ArrayList extractArguments(String args) throws IncompleteCommandException { - int lastIndex = 0; - ArrayList splitArguments = new ArrayList<>(); - try { - Matcher matcher = ARGUMENT_FORMAT.matcher(args.trim()); - while (matcher.find()) { - splitArguments.add(matcher.group()); - lastIndex = matcher.end(); - } - matcher.usePattern(ARGUMENT_TRAILING_FORMAT); - matcher.find(lastIndex); - splitArguments.add(matcher.group()); - } catch (IllegalStateException e) { - throw new IncompleteCommandException("No parameters found!"); + public ArrayList splitCommandTerm(String userInput) throws IncompleteCommandException { + ArrayList resultArrayList = new ArrayList<>(); + final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); + // guard against no match + if (!matcher.matches()) { + throw new IncompleteCommandException("Could not find space delimiter between command and arguments!"); } - return splitArguments; + resultArrayList.add(matcher.group("commandWord")); + resultArrayList.add(matcher.group("arguments")); + return resultArrayList; } - - /** * Prepare arguments for AddCommand by splitting up the arguments into different parts *

@@ -177,12 +129,16 @@ protected ArrayList prepareAdd(String args) throws IncompleteCommandExce final Matcher matcher = ADD_COMMAND_FORMAT.matcher(args.trim()); // validate arg string format int matchCount = matcher.groupCount(); - if (!matcher.matches() || matchCount != PREPAREADD_REQUIRED_ARGUMENT_COUNT) { + if (!matcher.matches()) { throw new IncompleteCommandException("Add command values are incomplete or missing!"); } ArrayList results = new ArrayList<>(); for (int i = 1; i <= matchCount; i++) { - results.add(matcher.group(i)); + String result = matcher.group(i); + if (hasSlashDelimiter(result)) { + throw new IncompleteCommandException("Use of '/' for purposes other than delimiter is forbidden!"); + } + results.add(result); } return results; } @@ -199,7 +155,7 @@ protected ArrayList prepareView(String args) throws IncompleteCommandExc if (!matcher.matches()) { throw new IncompleteCommandException("View command values are incomplete or missing!"); } - return new ArrayList<>(Collections.singleton(matcher.group())); + return new ArrayList<>(Collections.singleton(matcher.group(1))); } /** @@ -214,28 +170,82 @@ protected ArrayList prepareDelete(String args) throws IncompleteCommandE if (!matcher.matches()) { throw new IncompleteCommandException("Delete command values are incomplete or missing!"); } - return new ArrayList<>(Collections.singleton(matcher.group())); + return new ArrayList<>(Collections.singleton(matcher.group(1))); } + /** + * Splits main arguments into split tags with each substring + * + * @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; + ArrayList splitArguments = new ArrayList<>(); + try { + Matcher matcher = ARGUMENT_FORMAT.matcher(args.trim()); + while (matcher.find()) { + splitArguments.add(matcher.group().trim()); + lastIndex = matcher.end(); + } + matcher.usePattern(ARGUMENT_TRAILING_FORMAT); + matcher.find(lastIndex); + splitArguments.add(matcher.group().trim()); + } catch (IllegalStateException e) { + throw new IncompleteCommandException("No parameters found!"); + } + return splitArguments; + } /** - * 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. + * Create UpdateCommand class containing all arguments required to update a given item + *

+ * Should multiple arguments specifying the same argument parameter (e.g. 'c/1000' and 'c/2000') is given, + * the previous arguments passed in will be overwritten by the most recent parameter ('c/2000' in example). * - * @param userInput String to be split into substrings - * @return ArrayList of String, first element being the command term and the second element being arguments - * @throws IncompleteCommandException if no space is found + * @param args ArrayList of arguments for an Update Command + * @return Command object */ - public ArrayList splitCommandTerm(String userInput) throws IncompleteCommandException { - ArrayList resultArrayList = new ArrayList<>(); - final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); - // guard against no match - if (!matcher.matches()) { - throw new IncompleteCommandException("Could not find space delimiter between command and arguments!"); + protected Command prepareUpdate(ArrayList args) throws IncompleteCommandException { + UpdateCommand updateCommand = new UpdateCommand(); + for (String s : args) { + int delimiterPos = s.indexOf('/'); + // the case where delimiterPos = -1 is impossible as + // ARGUMENT_FORMAT and ARGUMENT_TRAILING_FORMAT regex requires a '/' + assert delimiterPos != -1 : "Each args will need to include minimally a '/' to split arg and value upon"; + String argType = s.substring(0, delimiterPos); + String argValue = s.substring(delimiterPos + 1); + switch (argType) { + case "n": + updateCommand.setUpdateName(argValue); + break; + case "pd": + updateCommand.setPurchaseDate(argValue); + break; + case "t": + updateCommand.setType(argValue); + break; + case "pf": + updateCommand.setPurchaseFrom(argValue); + break; + case "c": + updateCommand.setCost(argValue); + break; + case "sn": + updateCommand.setSerialNumber(argValue); + break; + default: + System.out.println("`" + argValue + "` not updated for type " + argType + ": Unrecognised Tag"); + } } - resultArrayList.add(matcher.group("commandWord")); - resultArrayList.add(matcher.group("arguments")); - return resultArrayList; + if (updateCommand.getSerialNumber() == null) + return new IncorrectCommand("Serial Number is required to update an item!"); + return updateCommand; + } + + private static boolean hasSlashDelimiter(String argument) { + return argument.contains("/"); } diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 2565e9f352..72a1d20dab 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -2,15 +2,16 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import seedu.parser.IncompleteCommandException; -import seedu.parser.Parser; +import seedu.command.IncorrectCommand; +import seedu.command.UpdateCommand; -import java.lang.reflect.Array; +import java.sql.Array; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.concurrent.atomic.AtomicReferenceArray; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.*; class ParserTest { @@ -49,7 +50,7 @@ void splitCommandTerm_noSpaceDelimiter_exceptionThrown() { } @Test - void prepareAdd_validAddString_success() throws IncompleteCommandException { + void prepareAdd_addStringWithSpaces_success() throws IncompleteCommandException { ArrayList expectedResult = new ArrayList<>( Arrays.asList("Speaker B", "S1404115ASF", "Speaker", "1000", "Loud Technologies", "2022-02-23") ); @@ -76,7 +77,7 @@ void prepareAdd_insufficientArguments_exceptionThrown() { @Test void prepareAdd_argumentEnteredTwice_exceptionThrown() { ArrayList unexpectedResult = new ArrayList<>( - Arrays.asList("Speaker B", "S1404115ASF", "Speaker", "1000", "1000", "Loud Technologies", "2022-02-23") + Arrays.asList("Speaker B", "S1404115ASF", "Speaker", "1000 c/1000", "Loud Technologies", "2022-02-23") ); try { ArrayList actualResult = parser.prepareAdd( @@ -84,8 +85,167 @@ void prepareAdd_argumentEnteredTwice_exceptionThrown() { assertEquals(unexpectedResult, actualResult); fail(); } catch (IncompleteCommandException e) { - assertEquals("Add command values are incomplete or missing!", e.getMessage()); + assertEquals("Use of '/' for purposes other than delimiter is forbidden!", e.getMessage()); } } + @Test + void prepareAdd_argumentIncludesSlashA_exceptionThrown() { + ArrayList unexpectedResult = new ArrayList<>( + Arrays.asList("Speaker B", "S1404115/ASF", "Speaker", "1000", "Loud Technologies", "2022-02-23") + ); + try { + ArrayList actualResult = parser.prepareAdd( + "n/Speaker B sn/S1404115/ASF t/Speaker c/1000 pf/Loud Technologies pd/2022-02-23"); + assertEquals(unexpectedResult, actualResult); + fail(); + } catch (IncompleteCommandException e) { + assertEquals("Use of '/' for purposes other than delimiter is forbidden!", e.getMessage()); + } + } + + @Test + void prepareAdd_argumentIncludesSlashB_exceptionThrown() { + ArrayList unexpectedResult = new ArrayList<>( + Arrays.asList("Speaker B", "S1404115", "t/SF t/Speaker", "1000", "Loud Technologies", "2022-02-23") + ); + try { + ArrayList actualResult = parser.prepareAdd( + "n/Speaker B sn/S1404115t/SF t/Speaker c/1000 pf/Loud Technologies pd/2022-02-23"); + assertEquals(unexpectedResult, actualResult); + fail(); + } catch (IncompleteCommandException e) { + assertEquals("Use of '/' for purposes other than delimiter is forbidden!", e.getMessage()); + } + } + + @Test + void prepareView_viewStringWithSpaces_success() throws IncompleteCommandException { + ArrayList expectedResult = new ArrayList<>( + Arrays.asList("Speaker B") + ); + ArrayList actualResult = parser.prepareView( + " n/Speaker B "); + assertEquals(expectedResult, actualResult); + } + + @Test + void prepareView_wrongArgumentTag_exceptionThrown() { + ArrayList expectedResult = new ArrayList<>( + Arrays.asList("Speaker B") + ); + try { + ArrayList actualResult = parser.prepareView( + "sn/Speaker B"); + assertEquals(expectedResult, actualResult); + fail(); + } catch (IncompleteCommandException e) { + assertEquals("View command values are incomplete or missing!", e.getMessage()); + } + } + + @Test + void prepareDelete_deleteStringWithSpaces_success() throws IncompleteCommandException { + ArrayList expectedResult = new ArrayList<>( + Arrays.asList("SM58-1") + ); + ArrayList actualResult = parser.prepareDelete( + " s/SM58-1 "); + assertEquals(expectedResult, actualResult); + } + + @Test + void prepareDelete_wrongArgumentTag_exceptionThrown() { + ArrayList expectedResult = new ArrayList<>( + Arrays.asList("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 extractArguments_validCommands_success() throws IncompleteCommandException { + ArrayList testStrings = new ArrayList<>(Arrays.asList( + "sn/S1404115ASF n/Speaker B t/Speaker c/1000 pf/Loud Technologies pd/2022-02-23", + "sn/S1404115ASF c/1000", + "sn/S1404115ASF n/Speaker B ", + "sn/S1404115ASF pf/Loud Technologies n/Speaker B", + "t/Speaker sn/S1404115ASF", + "c/1000 pf/Loud Technologies sn/S1404115ASF" + )); + ArrayList> expectedResults = new ArrayList<>(); + expectedResults.add(new ArrayList<>(Arrays.asList( + "sn/S1404115ASF", "n/Speaker B", "t/Speaker", "c/1000", "pf/Loud Technologies", "pd/2022-02-23"))); + expectedResults.add(new ArrayList<>(Arrays.asList( + "sn/S1404115ASF", "c/1000"))); + expectedResults.add(new ArrayList<>(Arrays.asList( + "sn/S1404115ASF", "n/Speaker B"))); + expectedResults.add(new ArrayList<>(Arrays.asList( + "sn/S1404115ASF", "pf/Loud Technologies", "n/Speaker B"))); + expectedResults.add(new ArrayList<>(Arrays.asList( + "t/Speaker", "sn/S1404115ASF"))); + expectedResults.add(new ArrayList<>(Arrays.asList( + "c/1000", "pf/Loud Technologies", "sn/S1404115ASF"))); + for (int i = 0; i < expectedResults.size(); i++) { + assertEquals(expectedResults.get(i), parser.extractArguments(testStrings.get(i))); + } + } + + @Test + void extractArguments_noSpaceBeforeTypeSlashDelimiterFound_exceptionThrown() { + ArrayList expectedResult = new ArrayList<>(Arrays.asList( + "x/Speaker B", "t/Speaker", "c/1000", "pf/Loud Technologies", "pd/2022-02-23")); + try { + ArrayList actualResult = parser.extractArguments("x/Speaker Bt/Speakerc/1000pf/Loud Technologiespd/2022-02-23"); + assertEquals(expectedResult, actualResult); + fail(); + } catch (IncompleteCommandException e) { + assertEquals("No parameters found!", e.getMessage()); + } + } + + @Test + void extractArguments_wrongArgTypesUsed_exceptionThrown() throws IncompleteCommandException { + Throwable exception = assertThrows(IncompleteCommandException.class, ()-> parser.extractArguments("x/Speaker B a/Speaker b/1000 d/Loud Technologies e/2022-02-23")); + assertEquals("No parameters found!", exception.getMessage()); + } + + @Test + void prepareUpdate_missingSlashDelimiter_assertionErrorThrown() throws AssertionError { + ArrayList testArrayList = new ArrayList<>(Collections.singleton("thiswillnotwork")); + try { + parser.prepareUpdate(testArrayList); + fail(); + } catch (IncompleteCommandException e) { + fail(); + } catch (AssertionError error) { + assertEquals("Each args will need to include minimally a '/' to split arg and value upon", error.getMessage()); + } + } + + @Test + void prepareUpdate_missingSerialNumber_exceptionThrown() throws IncompleteCommandException { + ArrayList testArrayList = new ArrayList<>(Arrays.asList( + "n/Speaker B", "t/Speaker", "c/1000", "pf/Loud Technologies", "pd/2022-02-23")); + IncorrectCommand expectedCommand = new IncorrectCommand("Serial Number is required to update an item!"); + assertEquals(expectedCommand, parser.prepareUpdate(testArrayList)); + } + + @Test + void prepareUpdate_mostRecentArgValueUsed_success() throws IncompleteCommandException { + // TODO: ask for equals() to be defined in abstract Command class + ArrayList testArrayList = new ArrayList<>(Arrays.asList( + "sn/S1404115ASF", "n/Speaker B", "n/Speaker A")); + UpdateCommand expectedCommand = new UpdateCommand(); + expectedCommand.setSerialNumber("S1404115ASF"); + expectedCommand.setType("Speaker A"); + assertEquals(expectedCommand, parser.prepareUpdate(testArrayList)); + } + } \ No newline at end of file From 6c4cb12b0a351bdd247c9f6de15d59b450006b5b Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 17 Mar 2022 04:16:57 +0800 Subject: [PATCH 033/229] Add case for ListCommand in Parser's parseCommand --- src/main/java/seedu/command/ListCommand.java | 2 +- src/main/java/seedu/parser/Parser.java | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/command/ListCommand.java b/src/main/java/seedu/command/ListCommand.java index 083d0bf960..551ac0d75d 100644 --- a/src/main/java/seedu/command/ListCommand.java +++ b/src/main/java/seedu/command/ListCommand.java @@ -10,7 +10,7 @@ */ public class ListCommand extends Command { private final ArrayList COMMAND_STRINGS; - public final String COMMAND_WORD = "list"; + public static final String COMMAND_WORD = "list"; /** * constructor for ListCommand with NO specified type. Initialises successMessage and usageReminder from Command diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index e8b49fbaa3..1dd60c4890 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -85,6 +85,13 @@ public Command parseCommand(String userInput) { } catch (IncompleteCommandException e) { return new IncorrectCommand(UpdateCommand.COMMAND_WORD + UpdateCommand.COMMAND_DESCRIPTION); } + case ListCommand.COMMAND_WORD: + if (commandAndArgument.get(1).equals(null)) { + return new ListCommand(); + } else { + return new ListCommand(new ArrayList<>(Collections.singleton(commandAndArgument.get(1)))); + } + default: return new IncorrectCommand(INCORRECT_COMMAND_FORMAT); } @@ -94,6 +101,7 @@ public Command parseCommand(String userInput) { /** * 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", remainder arguments can be empty, in which case a null second object will be passed in. * * @param userInput String to be split into substrings * @return ArrayList of String, first element being the command term and the second element being arguments @@ -101,7 +109,13 @@ public Command parseCommand(String userInput) { */ public ArrayList splitCommandTerm(String userInput) throws IncompleteCommandException { ArrayList resultArrayList = new ArrayList<>(); - final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); + userInput = userInput.trim(); + if (userInput.equals(ListCommand.COMMAND_WORD)) { + resultArrayList.add("list"); + resultArrayList.add(null); + return resultArrayList; + } + 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!"); From 44443034783ea3e9355f71159c25e9303479e248 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 17 Mar 2022 11:26:45 +0800 Subject: [PATCH 034/229] Implement full equals method for IncorrectCommand for JUnit test --- .../java/seedu/command/IncorrectCommand.java | 24 +++++++++++++++++-- src/test/java/seedu/parser/ParserTest.java | 4 ++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/command/IncorrectCommand.java b/src/main/java/seedu/command/IncorrectCommand.java index abd83828fa..88c09c4fe9 100644 --- a/src/main/java/seedu/command/IncorrectCommand.java +++ b/src/main/java/seedu/command/IncorrectCommand.java @@ -17,8 +17,28 @@ public CommandResult execute() { return new CommandResult(feedbackToUser); } - public boolean equals(IncorrectCommand other) { - return feedbackToUser.equals(other.feedbackToUser); + /** + * Implement equals for JUnit comparisons + * Source: https://www.geeksforgeeks.org/overriding-equals-method-in-java/ + * @param o Any object + * @return If two commands are the same + */ + public boolean equals(Object o) { + if (o == this) { + return true; + } + + /* Check if o is an instance of IncorrectCommand or not + "null instanceof [type]" also returns false */ + if (!(o instanceof IncorrectCommand)) { + return false; + } + + // typecast o to IncorrectCommand so that we can compare data members + IncorrectCommand c = (IncorrectCommand) o; + + // Compare the data members and return accordingly + return this.feedbackToUser.equals(c.feedbackToUser); } } diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 72a1d20dab..58dcbf43c9 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -234,7 +234,7 @@ void prepareUpdate_missingSerialNumber_exceptionThrown() throws IncompleteComman ArrayList testArrayList = new ArrayList<>(Arrays.asList( "n/Speaker B", "t/Speaker", "c/1000", "pf/Loud Technologies", "pd/2022-02-23")); IncorrectCommand expectedCommand = new IncorrectCommand("Serial Number is required to update an item!"); - assertEquals(expectedCommand, parser.prepareUpdate(testArrayList)); + assertTrue(expectedCommand.equals(parser.prepareUpdate(testArrayList))); } @Test @@ -245,7 +245,7 @@ void prepareUpdate_mostRecentArgValueUsed_success() throws IncompleteCommandExce UpdateCommand expectedCommand = new UpdateCommand(); expectedCommand.setSerialNumber("S1404115ASF"); expectedCommand.setType("Speaker A"); - assertEquals(expectedCommand, parser.prepareUpdate(testArrayList)); + assertTrue(expectedCommand.equals(parser.prepareUpdate(testArrayList))); } } \ No newline at end of file From 208c9a755dc33cfda11e4d3ec627b3784280be2c Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Thu, 17 Mar 2022 15:35:40 +0800 Subject: [PATCH 035/229] Fix AddCommandTest --- src/test/java/seedu/command/AddCommandTest.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/test/java/seedu/command/AddCommandTest.java b/src/test/java/seedu/command/AddCommandTest.java index 085d9f391a..e82b4a5671 100644 --- a/src/test/java/seedu/command/AddCommandTest.java +++ b/src/test/java/seedu/command/AddCommandTest.java @@ -20,13 +20,9 @@ class AddCommandTest { Arrays.asList("Speaker B", "S1404115ASF", "SPEAKER", "1000", "Loud Technologies", "2022-02-23") ); -// @BeforeEach -// void setup() { -// addCommand = new AddCommand(userInput); -// } - @Test void execute_duplicateSerialNumber_exceptionThrown() throws DuplicateSerialNumber { + addCommand = new AddCommand(userInput); addCommand.setEquipmentManager(new EquipmentManager()); EquipmentManager equipmentManager = addCommand.equipmentManager; equipmentManager.addEquipment("Speaker B", From 19dec8eb1c7a733156b59298be4c888343cd6539 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Thu, 17 Mar 2022 15:57:11 +0800 Subject: [PATCH 036/229] Fix invalid serial number bug for DeleteCommand --- src/main/java/seedu/command/Command.java | 1 + src/main/java/seedu/command/DeleteCommand.java | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/command/Command.java b/src/main/java/seedu/command/Command.java index a42875c018..ed9a0d343a 100644 --- a/src/main/java/seedu/command/Command.java +++ b/src/main/java/seedu/command/Command.java @@ -13,6 +13,7 @@ public abstract class Command { protected EquipmentManager equipmentManager; protected final String INCORRECT_ENUM_TYPE = "Wrong type of equipment. The allowed types are: MICROPHONE, SPEAKER, STAND, CABLE"; protected final String INCORRECT_COST_FORMAT = "Please enter numbers only for cost and omit symbols"; + protected final String INVALID_SERIAL_NUMBER = "No such serial number, please enter an existing serial number"; public abstract CommandResult execute(); diff --git a/src/main/java/seedu/command/DeleteCommand.java b/src/main/java/seedu/command/DeleteCommand.java index a8f289b428..d7c738a254 100644 --- a/src/main/java/seedu/command/DeleteCommand.java +++ b/src/main/java/seedu/command/DeleteCommand.java @@ -28,9 +28,15 @@ public DeleteCommand(ArrayList commandStrings) { * @return CommandResult with message from execution of this command */ public CommandResult execute() { - String equipmentName = equipmentManager.getEquipmentList().get(COMMAND_STRINGS.get(0)).getItemName(); + String equipmentName; + try { + equipmentName = equipmentManager.getEquipmentList().get(COMMAND_STRINGS.get(0)).getItemName(); + } catch (NullPointerException e) { + return new CommandResult(INVALID_SERIAL_NUMBER); + } + equipmentManager.deleteEquipment(COMMAND_STRINGS.get(0)); - return new CommandResult(String.format(successMessage, equipmentName,COMMAND_STRINGS.get(1))); + return new CommandResult(String.format(successMessage, equipmentName,COMMAND_STRINGS.get(0))); } } From 10829b30b18c26abb86c5822f6a8eca543f0a2b6 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Thu, 17 Mar 2022 15:57:46 +0800 Subject: [PATCH 037/229] Add JUnit tests for DeleteCommand --- .../java/seedu/command/DeleteCommandTest.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/test/java/seedu/command/DeleteCommandTest.java diff --git a/src/test/java/seedu/command/DeleteCommandTest.java b/src/test/java/seedu/command/DeleteCommandTest.java new file mode 100644 index 0000000000..c14eea8a26 --- /dev/null +++ b/src/test/java/seedu/command/DeleteCommandTest.java @@ -0,0 +1,42 @@ +package seedu.command; + +import org.junit.jupiter.api.Test; +import seedu.equipment.DuplicateSerialNumber; +import seedu.equipment.EquipmentManager; +import seedu.equipment.EquipmentType; + +import java.util.ArrayList; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; + +class DeleteCommandTest { + DeleteCommand deleteCommand; + + @Test + void execute_validSerialNumber_success() { + deleteCommand = new DeleteCommand(new ArrayList<>( + Arrays.asList("S1404115ASF") + )); + deleteCommand.setEquipmentManager(new EquipmentManager()); + EquipmentManager equipmentManager = deleteCommand.equipmentManager; + try { + equipmentManager.addEquipment("Speaker B", + "S1404115ASF", + EquipmentType.valueOf("SPEAKER"), + 1000, + "Loud Technologies", + "2022-02-23"); + } catch (DuplicateSerialNumber 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); + } +} \ No newline at end of file From 61a6eae5ba9074d5231773a88513565395f16c8b Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Thu, 17 Mar 2022 15:58:12 +0800 Subject: [PATCH 038/229] Add JUnit tests for CheckCommand --- src/main/java/seedu/command/CheckCommand.java | 4 -- .../java/seedu/command/CheckCommandTest.java | 49 +++++++++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 src/test/java/seedu/command/CheckCommandTest.java diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index f6a1bcffc1..e3b9e84e4c 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -31,10 +31,6 @@ public CheckCommand(ArrayList commandStrings) { * @return CommandResult with message from execution of this command */ public CommandResult execute() { - String name, sn, purchasedFrom, purchasedDate; - EquipmentType type; - double cost; - ArrayList equipment = equipmentManager.checkEquipment(COMMAND_STRINGS.get(0)); return new CommandResult(String.format(successMessage, COMMAND_STRINGS.get(0)), equipment); diff --git a/src/test/java/seedu/command/CheckCommandTest.java b/src/test/java/seedu/command/CheckCommandTest.java new file mode 100644 index 0000000000..3141b994e8 --- /dev/null +++ b/src/test/java/seedu/command/CheckCommandTest.java @@ -0,0 +1,49 @@ +package seedu.command; + +import org.junit.jupiter.api.Test; +import seedu.equipment.DuplicateSerialNumber; +import seedu.equipment.Equipment; +import seedu.equipment.EquipmentManager; +import seedu.equipment.EquipmentType; + +import java.util.ArrayList; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; + +class CheckCommandTest { + CheckCommand checkCommand; + + @Test + void execute_validEquipmentName_success() { + checkCommand = new CheckCommand(new ArrayList<>( + Arrays.asList("Speaker B") + )); + checkCommand.setEquipmentManager(new EquipmentManager()); + EquipmentManager equipmentManager = checkCommand.equipmentManager; + try { + equipmentManager.addEquipment("Speaker B", + "S1404115ASF", + EquipmentType.valueOf("SPEAKER"), + 1000, + "Loud Technologies", + "2022-02-23"); + } catch (DuplicateSerialNumber 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 'Speaker B':" + System.lineSeparator(), + listOfEquipments); + + assertEquals(expectedResult, actualResult); + } +} \ No newline at end of file From a6d74f79bb7139dcc69d1fc663236c6b5353fc71 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Thu, 17 Mar 2022 15:58:52 +0800 Subject: [PATCH 039/229] Add JUnit tests for UpdateCommand --- src/main/java/seedu/Pair.java | 16 ++++ .../java/seedu/command/UpdateCommand.java | 42 ++++++++--- .../java/seedu/command/UpdateCommandTest.java | 73 +++++++++++++++++++ 3 files changed, 120 insertions(+), 11 deletions(-) create mode 100644 src/test/java/seedu/command/UpdateCommandTest.java diff --git a/src/main/java/seedu/Pair.java b/src/main/java/seedu/Pair.java index f2d21ff308..2378a534b7 100644 --- a/src/main/java/seedu/Pair.java +++ b/src/main/java/seedu/Pair.java @@ -1,5 +1,7 @@ package seedu; +import java.util.Objects; + /** * Implementation of Pair which is not available in Java 11. Referenced from https://stackoverflow.com/a/59945161 * @param the class of the key @@ -26,7 +28,21 @@ public V getValue() { public void setKey(K key) { this.key = key; } + public K getKey() { return key; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Pair pair = (Pair) o; + return key.equals(pair.key) && value.equals(pair.value); + } + + @Override + public int hashCode() { + return Objects.hash(key, value); + } } diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java index b39ff2271e..786aafa463 100644 --- a/src/main/java/seedu/command/UpdateCommand.java +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -19,15 +19,17 @@ public class UpdateCommand extends Command { * constructor for UpdateCommand. Initialises successMessage and usageReminder from Command */ public UpdateCommand() { - successMessage = "Equipment successfully updated: %1$s for serial number %2$s"; + successMessage = "Equipment successfully updated for serial number %1$s," + + System.lineSeparator() + + "Updated details are: %2$s"; usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; } public CommandResult execute() { ArrayList> updatePairs = generateUpdatePairs(); - successMessage = equipmentManager.updateEquipment(serialNumber, updatePairs); + equipmentManager.updateEquipment(serialNumber, updatePairs); - return new CommandResult(successMessage); + return new CommandResult(String.format(successMessage, serialNumber, generateUpdateString())); } public String getSerialNumber() { @@ -61,24 +63,42 @@ public void setCost(String cost) { public ArrayList> generateUpdatePairs() { ArrayList> pairs = new ArrayList<>(); if (updateName != null) { - pairs.add(new Pair("itemName", updateName)); + pairs.add(new Pair<>("itemName", updateName)); } if (type != null) { - pairs.add(new Pair("type", type)); + pairs.add(new Pair<>("type", type)); } if (cost != null) { - pairs.add(new Pair("cost", cost)); + pairs.add(new Pair<>("cost", cost)); } if (purchaseDate != null) { - pairs.add(new Pair("purchasedDate", purchaseDate)); + pairs.add(new Pair<>("purchasedDate", purchaseDate)); } if (purchaseFrom != null) { - pairs.add(new Pair("purchasedFrom", purchaseFrom)); - } - if (serialNumber != null) { - pairs.add(new Pair("serialNumber", serialNumber)); + pairs.add(new Pair<>("purchasedFrom", purchaseFrom)); } return pairs; } + + public String generateUpdateString(){ + String updateDetails = ""; + if (updateName != null) { + updateDetails = updateDetails + System.lineSeparator() + "New name: " + updateName; + } + if (type != null) { + updateDetails = updateDetails + System.lineSeparator() + "New type: " + type; + } + if (cost != null) { + updateDetails = updateDetails + System.lineSeparator() + "New cost: " + cost; + } + if (purchaseDate != null) { + updateDetails = updateDetails + System.lineSeparator() + "New purchase date: " + purchaseDate; + } + if (purchaseFrom != null) { + updateDetails = updateDetails + System.lineSeparator() + "New purchased from: " + purchaseFrom; + } + + return updateDetails; + } } diff --git a/src/test/java/seedu/command/UpdateCommandTest.java b/src/test/java/seedu/command/UpdateCommandTest.java new file mode 100644 index 0000000000..c29b7b30d0 --- /dev/null +++ b/src/test/java/seedu/command/UpdateCommandTest.java @@ -0,0 +1,73 @@ +package seedu.command; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import seedu.Pair; +import seedu.equipment.DuplicateSerialNumber; +import seedu.equipment.EquipmentManager; +import seedu.equipment.EquipmentType; +import seedu.parser.Parser; + +import java.util.ArrayList; + +import static org.junit.jupiter.api.Assertions.*; + +class UpdateCommandTest { + EquipmentManager equipmentManager = new EquipmentManager(); + UpdateCommand updateCommand; + + @BeforeEach + void setup() { + try { + equipmentManager.addEquipment("Speaker B", + "S1404115ASF", + EquipmentType.valueOf("SPEAKER"), + 1000, + "Loud Technologies", + "2022-02-23"); + } catch (DuplicateSerialNumber e) { + fail(); + } + + updateCommand = new UpdateCommand(); + updateCommand.setEquipmentManager(equipmentManager); + updateCommand.setSerialNumber("S1404115ASF"); + updateCommand.setUpdateName("Speaker C"); + updateCommand.setCost("2000"); + updateCommand.setPurchaseDate("2022-01-26"); + } + + @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" + + System.lineSeparator() + + "New purchase date: 2022-01-26"); + + System.out.println(updateCommand.getSerialNumber()); + + CommandResult actualResult = updateCommand.execute(); + + System.out.println(actualResult.getResultToShow()); + +// 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")); + expectedResult.add(new Pair<>("purchasedDate", "2022-01-26")); + + ArrayList> actualResult = updateCommand.generateUpdatePairs(); + + assertEquals(expectedResult, actualResult); + } +} \ No newline at end of file From 23ae0d7e217fdd3f1a29dd9729a285009951f8b0 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Thu, 17 Mar 2022 15:59:10 +0800 Subject: [PATCH 040/229] Add JUnit tests for ListCommand --- .../java/seedu/command/ListCommandTest.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/test/java/seedu/command/ListCommandTest.java diff --git a/src/test/java/seedu/command/ListCommandTest.java b/src/test/java/seedu/command/ListCommandTest.java new file mode 100644 index 0000000000..605c297d82 --- /dev/null +++ b/src/test/java/seedu/command/ListCommandTest.java @@ -0,0 +1,49 @@ +package seedu.command; + +import org.junit.jupiter.api.Test; +import seedu.equipment.DuplicateSerialNumber; +import seedu.equipment.EquipmentManager; +import seedu.equipment.EquipmentType; + +import java.util.ArrayList; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; + +class ListCommandTest { + ListCommand listCommand; + + @Test + void execute_specifiedType_success() { + listCommand = new ListCommand(new ArrayList<>( + Arrays.asList("SPEAKER") + )); + listCommand.setEquipmentManager(new EquipmentManager()); + EquipmentManager equipmentManager = listCommand.equipmentManager; + try { + equipmentManager.addEquipment("Speaker B", + "S1404115ASF", + EquipmentType.valueOf("SPEAKER"), + 1000, + "Loud Technologies", + "2022-02-23"); + } catch (DuplicateSerialNumber e) { + fail(); + } + + CommandResult actualResult = listCommand.execute(); + CommandResult expectedResult = new CommandResult("TOTAL QUANTITY OF SPEAKER: 1" + System.lineSeparator(), equipmentManager.listEquipment()); + + assertEquals(expectedResult, actualResult); + } + + @Test + void execute_noSpecifiedType_success() { + listCommand = new ListCommand(); + + CommandResult actualResult = listCommand.execute(); + CommandResult expectedResult = new CommandResult("TOTAL QUANTITY OF EQUIPMENT: 1" + System.lineSeparator()); + + assertEquals(expectedResult, actualResult); + } +} \ No newline at end of file From 98cfb74ce43d242f7594aa6e71e36ac925508843 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Thu, 17 Mar 2022 17:16:47 +0800 Subject: [PATCH 041/229] Fix JUnit test for ListCommand --- src/test/java/seedu/command/ListCommandTest.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/test/java/seedu/command/ListCommandTest.java b/src/test/java/seedu/command/ListCommandTest.java index 605c297d82..cc68b3f320 100644 --- a/src/test/java/seedu/command/ListCommandTest.java +++ b/src/test/java/seedu/command/ListCommandTest.java @@ -32,7 +32,7 @@ void execute_specifiedType_success() { } CommandResult actualResult = listCommand.execute(); - CommandResult expectedResult = new CommandResult("TOTAL QUANTITY OF SPEAKER: 1" + System.lineSeparator(), equipmentManager.listEquipment()); + CommandResult expectedResult = new CommandResult("TOTAL QUANTITY OF SPEAKER: 1" + System.lineSeparator(), equipmentManager.listEquipment(EquipmentType.valueOf("SPEAKER"))); assertEquals(expectedResult, actualResult); } @@ -40,9 +40,21 @@ void execute_specifiedType_success() { @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", + "2022-02-23"); + } catch (DuplicateSerialNumber e) { + fail(); + } CommandResult actualResult = listCommand.execute(); - CommandResult expectedResult = new CommandResult("TOTAL QUANTITY OF EQUIPMENT: 1" + System.lineSeparator()); + CommandResult expectedResult = new CommandResult("TOTAL QUANTITY OF EQUIPMENT: 1" + System.lineSeparator(), equipmentManager.listEquipment()); assertEquals(expectedResult, actualResult); } From 600fa57e6c6250d0edb57047b514f5346d18a48e Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Thu, 17 Mar 2022 17:17:25 +0800 Subject: [PATCH 042/229] Refactor prepareUpdate from Parser to UpdateCommand, including the JUnit tests --- src/main/java/seedu/command/Command.java | 1 + .../java/seedu/command/UpdateCommand.java | 66 ++++++++++++++++++- src/main/java/seedu/parser/Parser.java | 48 +------------- .../java/seedu/command/UpdateCommandTest.java | 49 +++++++++++--- src/test/java/seedu/parser/ParserTest.java | 32 --------- 5 files changed, 106 insertions(+), 90 deletions(-) diff --git a/src/main/java/seedu/command/Command.java b/src/main/java/seedu/command/Command.java index ed9a0d343a..c3d81ff289 100644 --- a/src/main/java/seedu/command/Command.java +++ b/src/main/java/seedu/command/Command.java @@ -14,6 +14,7 @@ public abstract class Command { protected final String INCORRECT_ENUM_TYPE = "Wrong type of equipment. The allowed types are: MICROPHONE, SPEAKER, STAND, CABLE"; protected final String INCORRECT_COST_FORMAT = "Please enter numbers only for cost and omit symbols"; protected final String INVALID_SERIAL_NUMBER = "No such serial number, please enter an existing serial number"; + protected final String MISSING_SERIAL_NUMBER = "Serial Number is required to run this command"; public abstract CommandResult execute(); diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java index 786aafa463..221549419c 100644 --- a/src/main/java/seedu/command/UpdateCommand.java +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -1,10 +1,13 @@ package seedu.command; import seedu.Pair; +import seedu.parser.IncompleteCommandException; import java.util.ArrayList; +import java.util.Objects; public class UpdateCommand extends Command { + private final ArrayList COMMAND_STRINGS; public static final String COMMAND_WORD = "update"; public static final String COMMAND_DESCRIPTION = ": Updates the equipment with the specified serial number. " + "Parameters: s/SERIAL_NUMBER" + System.lineSeparator() @@ -18,14 +21,20 @@ public class UpdateCommand extends Command { /** * constructor for UpdateCommand. Initialises successMessage and usageReminder from Command */ - public UpdateCommand() { + public UpdateCommand(ArrayList commandStrings) { + COMMAND_STRINGS = commandStrings; successMessage = "Equipment successfully updated for serial number %1$s," + System.lineSeparator() + "Updated details are: %2$s"; usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; + + prepareUpdate(); } public CommandResult execute() { + if (getSerialNumber() == null) + return new CommandResult(MISSING_SERIAL_NUMBER); + ArrayList> updatePairs = generateUpdatePairs(); equipmentManager.updateEquipment(serialNumber, updatePairs); @@ -101,4 +110,59 @@ public String generateUpdateString(){ return updateDetails; } + + /** + * Set up UpdateCommand with arguments required to update a given item + *

+ * Should multiple arguments specifying the same argument parameter (e.g. 'c/1000' and 'c/2000') be given, + * the previous arguments passed in will be overwritten by the most recent parameter ('c/2000' in example). + * + * @return Command object + */ + protected void prepareUpdate() { + for (String s : COMMAND_STRINGS) { + int delimiterPos = s.indexOf('/'); + // the case where delimiterPos = -1 is impossible as + // ARGUMENT_FORMAT and ARGUMENT_TRAILING_FORMAT regex requires a '/' + assert delimiterPos != -1 : "Each args will need to include minimally a '/' to split arg and value upon"; + String argType = s.substring(0, delimiterPos); + String argValue = s.substring(delimiterPos + 1); + switch (argType) { + case "n": + setUpdateName(argValue); + break; + case "pd": + setPurchaseDate(argValue); + break; + case "t": + setType(argValue); + break; + case "pf": + setPurchaseFrom(argValue); + break; + case "c": + setCost(argValue); + break; + case "sn": + setSerialNumber(argValue); + break; + default: + System.out.println("`" + argValue + "` not updated for type " + argType + ": Unrecognised Tag"); + } + } + + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + UpdateCommand that = (UpdateCommand) o; + return serialNumber.equals(that.serialNumber) && Objects.equals(updateName, that.updateName) && Objects.equals(purchaseDate, that.purchaseDate) && Objects.equals(type, that.type) && Objects.equals(purchaseFrom, that.purchaseFrom) && Objects.equals(cost, that.cost); + } + + @Override + public int hashCode() { + return Objects.hash(serialNumber, updateName, purchaseDate, type, purchaseFrom, cost); + } } diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 1dd60c4890..08dafc7ebe 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -81,7 +81,7 @@ public Command parseCommand(String userInput) { case UpdateCommand.COMMAND_WORD: try { args = extractArguments(commandAndArgument.get(1)); - return prepareUpdate(args); + return new UpdateCommand(args); } catch (IncompleteCommandException e) { return new IncorrectCommand(UpdateCommand.COMMAND_WORD + UpdateCommand.COMMAND_DESCRIPTION); } @@ -212,52 +212,6 @@ protected ArrayList extractArguments(String args) throws IncompleteComma return splitArguments; } - /** - * Create UpdateCommand class containing all arguments required to update a given item - *

- * Should multiple arguments specifying the same argument parameter (e.g. 'c/1000' and 'c/2000') is given, - * the previous arguments passed in will be overwritten by the most recent parameter ('c/2000' in example). - * - * @param args ArrayList of arguments for an Update Command - * @return Command object - */ - protected Command prepareUpdate(ArrayList args) throws IncompleteCommandException { - UpdateCommand updateCommand = new UpdateCommand(); - for (String s : args) { - int delimiterPos = s.indexOf('/'); - // the case where delimiterPos = -1 is impossible as - // ARGUMENT_FORMAT and ARGUMENT_TRAILING_FORMAT regex requires a '/' - assert delimiterPos != -1 : "Each args will need to include minimally a '/' to split arg and value upon"; - String argType = s.substring(0, delimiterPos); - String argValue = s.substring(delimiterPos + 1); - switch (argType) { - case "n": - updateCommand.setUpdateName(argValue); - break; - case "pd": - updateCommand.setPurchaseDate(argValue); - break; - case "t": - updateCommand.setType(argValue); - break; - case "pf": - updateCommand.setPurchaseFrom(argValue); - break; - case "c": - updateCommand.setCost(argValue); - break; - case "sn": - updateCommand.setSerialNumber(argValue); - break; - default: - System.out.println("`" + argValue + "` not updated for type " + argType + ": Unrecognised Tag"); - } - } - if (updateCommand.getSerialNumber() == null) - return new IncorrectCommand("Serial Number is required to update an item!"); - return updateCommand; - } - private static boolean hasSlashDelimiter(String argument) { return argument.contains("/"); } diff --git a/src/test/java/seedu/command/UpdateCommandTest.java b/src/test/java/seedu/command/UpdateCommandTest.java index c29b7b30d0..f5ebfd1898 100644 --- a/src/test/java/seedu/command/UpdateCommandTest.java +++ b/src/test/java/seedu/command/UpdateCommandTest.java @@ -7,9 +7,12 @@ import seedu.equipment.DuplicateSerialNumber; import seedu.equipment.EquipmentManager; import seedu.equipment.EquipmentType; +import seedu.parser.IncompleteCommandException; import seedu.parser.Parser; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import static org.junit.jupiter.api.Assertions.*; @@ -30,12 +33,10 @@ void setup() { fail(); } - updateCommand = new UpdateCommand(); + updateCommand = new UpdateCommand(new ArrayList<>( + Arrays.asList("sn/S1404115ASF", "n/Speaker C", "c/2000", "pd/2022-01-26") + )); updateCommand.setEquipmentManager(equipmentManager); - updateCommand.setSerialNumber("S1404115ASF"); - updateCommand.setUpdateName("Speaker C"); - updateCommand.setCost("2000"); - updateCommand.setPurchaseDate("2022-01-26"); } @Test @@ -50,13 +51,9 @@ void execute_validSerialNumber_success() { + System.lineSeparator() + "New purchase date: 2022-01-26"); - System.out.println(updateCommand.getSerialNumber()); - CommandResult actualResult = updateCommand.execute(); - System.out.println(actualResult.getResultToShow()); - -// assertEquals(expectedResult, actualResult); + assertEquals(expectedResult, actualResult); } @Test @@ -70,4 +67,36 @@ void generateUpdatePairs_nonNullUpdates_success() { assertEquals(expectedResult, actualResult); } + + @Test + void prepareUpdate_missingSlashDelimiter_assertionErrorThrown() throws AssertionError { + ArrayList testArrayList = new ArrayList<>(Collections.singleton("thiswillnotwork")); + updateCommand = new UpdateCommand(testArrayList); + try { + updateCommand.prepareUpdate(); + } catch (AssertionError error) { + assertEquals("Each args will need to include minimally a '/' to split arg and value upon", error.getMessage()); + } + } + + @Test + void prepareUpdate_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 = new UpdateCommand(testArrayList); + CommandResult expectedResult = new CommandResult("Serial Number is required to run this command"); + assertEquals(expectedResult, updateCommand.execute()); + } + + @Test + void prepareUpdate_mostRecentArgValueUsed_success() throws IncompleteCommandException { + ArrayList testArrayList = new ArrayList<>(Arrays.asList( + "sn/S1404115ASF", "n/Speaker B", "n/Speaker A")); + UpdateCommand expectedCommand = new UpdateCommand(new ArrayList<>( + Arrays.asList("sn/S1404115ASF", "n/Speaker A") + )); + UpdateCommand actualCommand = new UpdateCommand(testArrayList); + actualCommand.prepareUpdate(); + assertEquals(expectedCommand, actualCommand); + } } \ No newline at end of file diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 72a1d20dab..a32a1b4fab 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -216,36 +216,4 @@ void extractArguments_wrongArgTypesUsed_exceptionThrown() throws IncompleteComma assertEquals("No parameters found!", exception.getMessage()); } - @Test - void prepareUpdate_missingSlashDelimiter_assertionErrorThrown() throws AssertionError { - ArrayList testArrayList = new ArrayList<>(Collections.singleton("thiswillnotwork")); - try { - parser.prepareUpdate(testArrayList); - fail(); - } catch (IncompleteCommandException e) { - fail(); - } catch (AssertionError error) { - assertEquals("Each args will need to include minimally a '/' to split arg and value upon", error.getMessage()); - } - } - - @Test - void prepareUpdate_missingSerialNumber_exceptionThrown() throws IncompleteCommandException { - ArrayList testArrayList = new ArrayList<>(Arrays.asList( - "n/Speaker B", "t/Speaker", "c/1000", "pf/Loud Technologies", "pd/2022-02-23")); - IncorrectCommand expectedCommand = new IncorrectCommand("Serial Number is required to update an item!"); - assertEquals(expectedCommand, parser.prepareUpdate(testArrayList)); - } - - @Test - void prepareUpdate_mostRecentArgValueUsed_success() throws IncompleteCommandException { - // TODO: ask for equals() to be defined in abstract Command class - ArrayList testArrayList = new ArrayList<>(Arrays.asList( - "sn/S1404115ASF", "n/Speaker B", "n/Speaker A")); - UpdateCommand expectedCommand = new UpdateCommand(); - expectedCommand.setSerialNumber("S1404115ASF"); - expectedCommand.setType("Speaker A"); - assertEquals(expectedCommand, parser.prepareUpdate(testArrayList)); - } - } \ No newline at end of file From 60d92fe6786f3f8305519b4ce4201c1a42499b3c Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Thu, 17 Mar 2022 21:23:56 +0800 Subject: [PATCH 043/229] Add updateEquipment method --- .../seedu/equipment/EquipmentManager.java | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index 912fef7935..4a6c586622 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -45,9 +45,38 @@ public ArrayList listEquipment() { return new ArrayList<>(equipmentList.values()); } - public String updateEquipment(String serialNumber, ArrayList> updatePairs) { - // To be updated - return ""; + public boolean updateEquipment(String serialNumber, ArrayList> updatePairs) { + if (!equipmentList.containsKey(serialNumber)){ + return false; + } + Equipment updatedEquipment = equipmentList.get(serialNumber); + for (Pair updates : updatePairs) { + String key = updates.getKey(); + switch (key) { + case "itemName": + updatedEquipment.setItemName(updates.getValue()); + break; + case "type": + try { + updatedEquipment.setType(EquipmentType.valueOf(updates.getValue())); + } catch (IllegalArgumentException e) { + return false; + } + break; + case "cost": + updatedEquipment.setCost(Double.parseDouble(updates.getValue())); + break; + case "purchaseDate": + updatedEquipment.setPurchasedDate(updates.getValue()); + break; + case "purchaseFrom": + updatedEquipment.setPurchasedFrom(updates.getValue()); + break; + default: + break; + } + } + return true; } public void deleteEquipment(String serialNumber) { From 8cf7fa714fdcb5e3314cfebde1a5abb34e26197a Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 17 Mar 2022 22:21:12 +0800 Subject: [PATCH 044/229] Standardise "s/" as tag for equipment serialNumber --- src/main/java/seedu/command/AddCommand.java | 4 +- src/main/java/seedu/parser/Parser.java | 6 +-- .../java/seedu/command/UpdateCommandTest.java | 6 +-- src/test/java/seedu/parser/ParserTest.java | 44 +++++++++---------- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index 02b7e24b14..82d38fd89d 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -12,9 +12,9 @@ public class AddCommand extends Command { private final ArrayList COMMAND_STRINGS; public static final String COMMAND_WORD = "add"; public static final String COMMAND_DESCRIPTION = ": Adds a Equipment to the equipmentInventory. " - + "Parameters: n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE" + System.lineSeparator() + + "Parameters: n/ITEM_NAME s/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE" + System.lineSeparator() + "Example: " - + "add n/SpeakerB sn/S1404115ASF t/Speaker c/1000 pf/Loud_Technologies pd/2022-02-23"; + + "add n/SpeakerB s/S1404115ASF t/Speaker c/1000 pf/Loud_Technologies pd/2022-02-23"; public static final String DUPLICATE_ITEM_ERROR = "There is already an item with this serial number: %1$s"; /** * constructor for AddCommand. Initialises successMessage and usageReminder from Command diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 08dafc7ebe..a9a2c0f3d6 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -21,7 +21,7 @@ public class Parser { public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s+(?.+)"); public static final Pattern ADD_COMMAND_FORMAT = Pattern.compile( "n\\/(?.+)" + "\\s+" + - "sn\\/(?.+)" + "\\s+" + + "s\\/(?.+)" + "\\s+" + "t\\/(?.+)" + "\\s+" + "c\\/(?.+)" + "\\s+" + "pf\\/(?.+)" + "\\s+" + @@ -31,11 +31,11 @@ public class Parser { public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("s/(?.+)"); // ARGUMENT_FORMAT extracts first n-1 tags public static final Pattern ARGUMENT_FORMAT = Pattern.compile( - "((?:sn|n|t|c|pf|pd)\\/[\\w\\s\\-]+?)\\s+(?=sn|n|t|c|pf|pd)" + "((?:s|n|t|c|pf|pd)\\/[\\w\\s\\-]+?)\\s+(?=sn|n|t|c|pf|pd)" ); // ARGUMENT_TRAILING_FORMAT extracts last tag public static final Pattern ARGUMENT_TRAILING_FORMAT = Pattern.compile( - "(?( - Arrays.asList("sn/S1404115ASF", "n/Speaker C", "c/2000", "pd/2022-01-26") + Arrays.asList("s/S1404115ASF", "n/Speaker C", "c/2000", "pd/2022-01-26") )); updateCommand.setEquipmentManager(equipmentManager); } @@ -91,9 +91,9 @@ void prepareUpdate_missingSerialNumber_exceptionThrown() throws IncompleteComman @Test void prepareUpdate_mostRecentArgValueUsed_success() throws IncompleteCommandException { ArrayList testArrayList = new ArrayList<>(Arrays.asList( - "sn/S1404115ASF", "n/Speaker B", "n/Speaker A")); + "s/S1404115ASF", "n/Speaker B", "n/Speaker A")); UpdateCommand expectedCommand = new UpdateCommand(new ArrayList<>( - Arrays.asList("sn/S1404115ASF", "n/Speaker A") + Arrays.asList("s/S1404115ASF", "n/Speaker A") )); UpdateCommand actualCommand = new UpdateCommand(testArrayList); actualCommand.prepareUpdate(); diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index a32a1b4fab..618a8fe313 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -25,10 +25,10 @@ void setup() { @Test void splitCommandTerm_validCommand_success() throws IncompleteCommandException { ArrayList expectedResult = new ArrayList<>( - Arrays.asList("add", "n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE") + 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 sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE"); + "add n/ITEM_NAME s/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE"); assertEquals(expectedResult, actualResult); assertEquals(expectedResult.get(0), actualResult.get(0)); assertEquals(expectedResult.get(1), actualResult.get(1)); @@ -37,11 +37,11 @@ void splitCommandTerm_validCommand_success() throws IncompleteCommandException { @Test void splitCommandTerm_noSpaceDelimiter_exceptionThrown() { ArrayList unexpectedResult = new ArrayList<>( - Arrays.asList("add", "n/ITEM_NAMEsn/SERIAL_NUMBERt/TYPEc/COSTpf/PURCHASED_FROMpd/PURCHASED_DATE") + Arrays.asList("add", "n/ITEM_NAMEs/SERIAL_NUMBERt/TYPEc/COSTpf/PURCHASED_FROMpd/PURCHASED_DATE") ); try { ArrayList actualResult = parser.splitCommandTerm( - "addn/ITEM_NAMEsn/SERIAL_NUMBERt/TYPEc/COSTpf/PURCHASED_FROMpd/PURCHASED_DATE"); + "addn/ITEM_NAMEs/SERIAL_NUMBERt/TYPEc/COSTpf/PURCHASED_FROMpd/PURCHASED_DATE"); assertEquals(unexpectedResult, actualResult); fail(); } catch (IncompleteCommandException e) { @@ -55,7 +55,7 @@ void prepareAdd_addStringWithSpaces_success() throws IncompleteCommandException Arrays.asList("Speaker B", "S1404115ASF", "Speaker", "1000", "Loud Technologies", "2022-02-23") ); ArrayList actualResult = parser.prepareAdd( - "n/Speaker B sn/S1404115ASF t/Speaker c/1000 pf/Loud Technologies pd/2022-02-23"); + "n/Speaker B s/S1404115ASF t/Speaker c/1000 pf/Loud Technologies pd/2022-02-23"); assertEquals(expectedResult, actualResult); } @@ -66,7 +66,7 @@ void prepareAdd_insufficientArguments_exceptionThrown() { ); try { ArrayList actualResult = parser.prepareAdd( - "n/Speaker B sn/S1404115ASF c/1000 pf/Loud Technologies pd/2022-02-23"); + "n/Speaker B s/S1404115ASF c/1000 pf/Loud Technologies pd/2022-02-23"); assertEquals(unexpectedResult, actualResult); fail(); } catch (IncompleteCommandException e) { @@ -81,7 +81,7 @@ void prepareAdd_argumentEnteredTwice_exceptionThrown() { ); try { ArrayList actualResult = parser.prepareAdd( - "n/Speaker B sn/S1404115ASF t/Speaker c/1000 c/1000 pf/Loud Technologies pd/2022-02-23"); + "n/Speaker B s/S1404115ASF t/Speaker c/1000 c/1000 pf/Loud Technologies pd/2022-02-23"); assertEquals(unexpectedResult, actualResult); fail(); } catch (IncompleteCommandException e) { @@ -96,7 +96,7 @@ void prepareAdd_argumentIncludesSlashA_exceptionThrown() { ); try { ArrayList actualResult = parser.prepareAdd( - "n/Speaker B sn/S1404115/ASF t/Speaker c/1000 pf/Loud Technologies pd/2022-02-23"); + "n/Speaker B s/S1404115/ASF t/Speaker c/1000 pf/Loud Technologies pd/2022-02-23"); assertEquals(unexpectedResult, actualResult); fail(); } catch (IncompleteCommandException e) { @@ -111,7 +111,7 @@ void prepareAdd_argumentIncludesSlashB_exceptionThrown() { ); try { ArrayList actualResult = parser.prepareAdd( - "n/Speaker B sn/S1404115t/SF t/Speaker c/1000 pf/Loud Technologies pd/2022-02-23"); + "n/Speaker B s/S1404115t/SF t/Speaker c/1000 pf/Loud Technologies pd/2022-02-23"); assertEquals(unexpectedResult, actualResult); fail(); } catch (IncompleteCommandException e) { @@ -136,7 +136,7 @@ void prepareView_wrongArgumentTag_exceptionThrown() { ); try { ArrayList actualResult = parser.prepareView( - "sn/Speaker B"); + "s/Speaker B"); assertEquals(expectedResult, actualResult); fail(); } catch (IncompleteCommandException e) { @@ -172,26 +172,26 @@ void prepareDelete_wrongArgumentTag_exceptionThrown() { @Test void extractArguments_validCommands_success() throws IncompleteCommandException { ArrayList testStrings = new ArrayList<>(Arrays.asList( - "sn/S1404115ASF n/Speaker B t/Speaker c/1000 pf/Loud Technologies pd/2022-02-23", - "sn/S1404115ASF c/1000", - "sn/S1404115ASF n/Speaker B ", - "sn/S1404115ASF pf/Loud Technologies n/Speaker B", - "t/Speaker sn/S1404115ASF", - "c/1000 pf/Loud Technologies sn/S1404115ASF" + "s/S1404115ASF n/Speaker B t/Speaker c/1000 pf/Loud Technologies pd/2022-02-23", + "s/S1404115ASF c/1000", + "s/S1404115ASF n/Speaker B ", + "s/S1404115ASF pf/Loud Technologies n/Speaker B", + "t/Speaker s/S1404115ASF", + "c/1000 pf/Loud Technologies s/S1404115ASF" )); ArrayList> expectedResults = new ArrayList<>(); expectedResults.add(new ArrayList<>(Arrays.asList( - "sn/S1404115ASF", "n/Speaker B", "t/Speaker", "c/1000", "pf/Loud Technologies", "pd/2022-02-23"))); + "s/S1404115ASF", "n/Speaker B", "t/Speaker", "c/1000", "pf/Loud Technologies", "pd/2022-02-23"))); expectedResults.add(new ArrayList<>(Arrays.asList( - "sn/S1404115ASF", "c/1000"))); + "s/S1404115ASF", "c/1000"))); expectedResults.add(new ArrayList<>(Arrays.asList( - "sn/S1404115ASF", "n/Speaker B"))); + "s/S1404115ASF", "n/Speaker B"))); expectedResults.add(new ArrayList<>(Arrays.asList( - "sn/S1404115ASF", "pf/Loud Technologies", "n/Speaker B"))); + "s/S1404115ASF", "pf/Loud Technologies", "n/Speaker B"))); expectedResults.add(new ArrayList<>(Arrays.asList( - "t/Speaker", "sn/S1404115ASF"))); + "t/Speaker", "s/S1404115ASF"))); expectedResults.add(new ArrayList<>(Arrays.asList( - "c/1000", "pf/Loud Technologies", "sn/S1404115ASF"))); + "c/1000", "pf/Loud Technologies", "s/S1404115ASF"))); for (int i = 0; i < expectedResults.size(); i++) { assertEquals(expectedResults.get(i), parser.extractArguments(testStrings.get(i))); } From b3317efef6f5cdcea44bd8b374becbc7a92e4df5 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 17 Mar 2022 22:45:14 +0800 Subject: [PATCH 045/229] Fix remainder of "s/" changes --- src/main/java/seedu/command/UpdateCommand.java | 6 +++--- src/main/java/seedu/parser/Parser.java | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java index 221549419c..114a27ed2d 100644 --- a/src/main/java/seedu/command/UpdateCommand.java +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -90,7 +90,7 @@ public ArrayList> generateUpdatePairs() { return pairs; } - public String generateUpdateString(){ + public String generateUpdateString() { String updateDetails = ""; if (updateName != null) { updateDetails = updateDetails + System.lineSeparator() + "New name: " + updateName; @@ -119,7 +119,7 @@ public String generateUpdateString(){ * * @return Command object */ - protected void prepareUpdate() { + protected void prepareUpdate() throws AssertionError { for (String s : COMMAND_STRINGS) { int delimiterPos = s.indexOf('/'); // the case where delimiterPos = -1 is impossible as @@ -143,7 +143,7 @@ protected void prepareUpdate() { case "c": setCost(argValue); break; - case "sn": + case "s": setSerialNumber(argValue); break; default: diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index a9a2c0f3d6..4536ec3a68 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -31,7 +31,7 @@ public class Parser { public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("s/(?.+)"); // ARGUMENT_FORMAT extracts first n-1 tags public static final Pattern ARGUMENT_FORMAT = Pattern.compile( - "((?:s|n|t|c|pf|pd)\\/[\\w\\s\\-]+?)\\s+(?=sn|n|t|c|pf|pd)" + "((?:s|n|t|c|pf|pd)\\/[\\w\\s\\-]+?)\\s+(?=s|n|t|c|pf|pd)" ); // ARGUMENT_TRAILING_FORMAT extracts last tag public static final Pattern ARGUMENT_TRAILING_FORMAT = Pattern.compile( @@ -124,6 +124,7 @@ public ArrayList splitCommandTerm(String userInput) throws IncompleteCom resultArrayList.add(matcher.group("arguments")); return resultArrayList; } + /** * Prepare arguments for AddCommand by splitting up the arguments into different parts *

From dfbfbdef4cd629153205074b344ad011ab51a1fd Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 17 Mar 2022 22:46:11 +0800 Subject: [PATCH 046/229] Reformat code to follow code style --- src/main/java/seedu/Pair.java | 3 ++- src/main/java/seedu/command/AddCommand.java | 12 ++++++++---- src/main/java/seedu/command/CheckCommand.java | 2 ++ src/main/java/seedu/command/Command.java | 2 +- src/main/java/seedu/command/CommandResult.java | 4 ++-- src/main/java/seedu/command/DeleteCommand.java | 4 +++- src/main/java/seedu/command/IncorrectCommand.java | 1 + src/main/java/seedu/command/ListCommand.java | 4 +++- .../java/seedu/equipment/DuplicateSerialNumber.java | 3 ++- src/main/java/seedu/equipment/EquipmentManager.java | 2 +- .../seedu/parser/IncompleteCommandException.java | 4 ++-- src/test/java/seedu/command/AddCommandTest.java | 2 +- src/test/java/seedu/command/ListCommandTest.java | 2 +- src/test/java/seedu/parser/ParserTest.java | 2 +- 14 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/main/java/seedu/Pair.java b/src/main/java/seedu/Pair.java index 2378a534b7..1178e67953 100644 --- a/src/main/java/seedu/Pair.java +++ b/src/main/java/seedu/Pair.java @@ -4,6 +4,7 @@ /** * Implementation of Pair which is not available in Java 11. Referenced from https://stackoverflow.com/a/59945161 + * * @param the class of the key * @param the class of the value */ @@ -12,7 +13,7 @@ public class Pair { K key; V value; - public Pair(K key, V value) { + public Pair(K key, V value) { this.key = key; this.value = value; } diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index 82d38fd89d..d283668c89 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -16,11 +16,13 @@ public class AddCommand extends Command { + "Example: " + "add n/SpeakerB s/S1404115ASF t/Speaker c/1000 pf/Loud_Technologies pd/2022-02-23"; public static final String DUPLICATE_ITEM_ERROR = "There is already an item with this serial number: %1$s"; + /** * constructor for AddCommand. Initialises successMessage and usageReminder from Command + * * @param commandStrings parsed user input which contains details of equipment to be added */ - public AddCommand(ArrayList commandStrings){ + public AddCommand(ArrayList commandStrings) { this.COMMAND_STRINGS = commandStrings; successMessage = "Equipment successfully added: %1$s, serial number %2$s"; usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; @@ -28,14 +30,15 @@ public AddCommand(ArrayList commandStrings){ /** * Adds equipment with details given in COMMAND_STRINGS + * * @return CommandResult with message from execution of this command */ - public CommandResult execute(){ + public CommandResult execute() { try { addEquipment(COMMAND_STRINGS); - } catch (DuplicateSerialNumber e){ + } catch (DuplicateSerialNumber e) { return new CommandResult(String.format(DUPLICATE_ITEM_ERROR, COMMAND_STRINGS.get(1))); - } catch (NullPointerException | NumberFormatException e){ + } catch (NullPointerException | NumberFormatException e) { return new CommandResult(INCORRECT_COST_FORMAT); } catch (IllegalArgumentException e) { return new CommandResult(INCORRECT_ENUM_TYPE); @@ -46,6 +49,7 @@ public CommandResult execute(){ /** * Uses information from the ArrayList to create a new Equipment and add it to the inventory. + * * @param userInput ArrayList of String which contains the individual attributes of the equipment to be added */ public void addEquipment(ArrayList userInput) throws DuplicateSerialNumber { diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index e3b9e84e4c..57bca24caf 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -18,6 +18,7 @@ public class CheckCommand extends Command { /** * constructor for CheckCommand. Initialises successMessage and usageReminder from Command + * * @param commandStrings parsed user input which contains details of equipment to be viewed */ public CheckCommand(ArrayList commandStrings) { @@ -28,6 +29,7 @@ public CheckCommand(ArrayList commandStrings) { /** * Gives details of equipment specified by name + * * @return CommandResult with message from execution of this command */ public CommandResult execute() { diff --git a/src/main/java/seedu/command/Command.java b/src/main/java/seedu/command/Command.java index c3d81ff289..a7cc0e1ba4 100644 --- a/src/main/java/seedu/command/Command.java +++ b/src/main/java/seedu/command/Command.java @@ -18,7 +18,7 @@ public abstract class Command { public abstract CommandResult execute(); - public String getUsageReminder(){ + public String getUsageReminder() { return usageReminder; } diff --git a/src/main/java/seedu/command/CommandResult.java b/src/main/java/seedu/command/CommandResult.java index 7172b2afba..2804d9d71c 100644 --- a/src/main/java/seedu/command/CommandResult.java +++ b/src/main/java/seedu/command/CommandResult.java @@ -24,11 +24,11 @@ public CommandResult(String result, ArrayList equipmentList) { RELEVANT_EQUIPMENT = equipmentList; } - public String getResultToShow(){ + public String getResultToShow() { return RESULT_TO_SHOW; } - public ArrayList getRelevantEquipment(){ + public ArrayList getRelevantEquipment() { return RELEVANT_EQUIPMENT; } diff --git a/src/main/java/seedu/command/DeleteCommand.java b/src/main/java/seedu/command/DeleteCommand.java index d7c738a254..f26591a90f 100644 --- a/src/main/java/seedu/command/DeleteCommand.java +++ b/src/main/java/seedu/command/DeleteCommand.java @@ -15,6 +15,7 @@ public class DeleteCommand extends Command { /** * constructor for DeleteCommand. Initialises successMessage and usageReminder from Command + * * @param commandStrings parsed user input which contains details of equipment to be deleted */ public DeleteCommand(ArrayList commandStrings) { @@ -25,6 +26,7 @@ public DeleteCommand(ArrayList commandStrings) { /** * Deletes equipment specified by serial number + * * @return CommandResult with message from execution of this command */ public CommandResult execute() { @@ -37,6 +39,6 @@ public CommandResult execute() { equipmentManager.deleteEquipment(COMMAND_STRINGS.get(0)); - return new CommandResult(String.format(successMessage, equipmentName,COMMAND_STRINGS.get(0))); + return new CommandResult(String.format(successMessage, equipmentName, COMMAND_STRINGS.get(0))); } } diff --git a/src/main/java/seedu/command/IncorrectCommand.java b/src/main/java/seedu/command/IncorrectCommand.java index abd83828fa..a49f575afe 100644 --- a/src/main/java/seedu/command/IncorrectCommand.java +++ b/src/main/java/seedu/command/IncorrectCommand.java @@ -2,6 +2,7 @@ /** * Represents an incorrect command. Upon execution, provide some feedback to user + * * @author Shun Yao */ public class IncorrectCommand extends Command { diff --git a/src/main/java/seedu/command/ListCommand.java b/src/main/java/seedu/command/ListCommand.java index 551ac0d75d..6df36f2efa 100644 --- a/src/main/java/seedu/command/ListCommand.java +++ b/src/main/java/seedu/command/ListCommand.java @@ -30,6 +30,7 @@ public ListCommand() { /** * constructor for ListCommand with specified type. Initialises successMessage and usageReminder from Command + * * @param commandStrings parsed user input which contains details of equipment to be viewed */ public ListCommand(ArrayList commandStrings) { @@ -47,12 +48,13 @@ public ListCommand(ArrayList commandStrings) { /** * List all equipment or list equipment of specified type + * * @return CommandResult with message from execution of this command */ public CommandResult execute() { int listSize; ArrayList equipmentArrayList; - if(COMMAND_STRINGS == null){ + if (COMMAND_STRINGS == null) { equipmentArrayList = equipmentManager.listEquipment(); listSize = equipmentArrayList.size(); return new CommandResult(String.format(successMessage, listSize), equipmentArrayList); diff --git a/src/main/java/seedu/equipment/DuplicateSerialNumber.java b/src/main/java/seedu/equipment/DuplicateSerialNumber.java index 03aba712bd..bda724e5d3 100644 --- a/src/main/java/seedu/equipment/DuplicateSerialNumber.java +++ b/src/main/java/seedu/equipment/DuplicateSerialNumber.java @@ -1,5 +1,6 @@ package seedu.equipment; public class DuplicateSerialNumber extends Exception { - public DuplicateSerialNumber() {} + public DuplicateSerialNumber() { + } } diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index 912fef7935..17089fe784 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -37,7 +37,7 @@ public ArrayList listEquipment(EquipmentType type) { return listOfEquipments; } - public HashMap getEquipmentList(){ + public HashMap getEquipmentList() { return equipmentList; } diff --git a/src/main/java/seedu/parser/IncompleteCommandException.java b/src/main/java/seedu/parser/IncompleteCommandException.java index c07e5d7679..ec35747cf9 100644 --- a/src/main/java/seedu/parser/IncompleteCommandException.java +++ b/src/main/java/seedu/parser/IncompleteCommandException.java @@ -4,11 +4,11 @@ * Signal that given data does not include necessary arguments * Adapted from: https://github.com/se-edu/addressbook-level2/blob/master/src/seedu/addressbook/data/exception/ */ -public class IncompleteCommandException extends Exception{ +public class IncompleteCommandException extends Exception { /** * @param message contains information on failed constraints */ - public IncompleteCommandException(String message){ + public IncompleteCommandException(String message) { super(message); } } diff --git a/src/test/java/seedu/command/AddCommandTest.java b/src/test/java/seedu/command/AddCommandTest.java index e82b4a5671..7b707cb04f 100644 --- a/src/test/java/seedu/command/AddCommandTest.java +++ b/src/test/java/seedu/command/AddCommandTest.java @@ -38,7 +38,7 @@ void execute_duplicateSerialNumber_exceptionThrown() throws DuplicateSerialNumbe } @Test - void execute_incorrectCostFormat_exceptionThrown(){ + void execute_incorrectCostFormat_exceptionThrown() { addCommand = new AddCommand(new ArrayList<>( Arrays.asList("Speaker B", "S1404115ASF", "SPEAKER", "$1000", "Loud Technologies", "2022-02-23") )); diff --git a/src/test/java/seedu/command/ListCommandTest.java b/src/test/java/seedu/command/ListCommandTest.java index cc68b3f320..5991cfdfc7 100644 --- a/src/test/java/seedu/command/ListCommandTest.java +++ b/src/test/java/seedu/command/ListCommandTest.java @@ -32,7 +32,7 @@ void execute_specifiedType_success() { } CommandResult actualResult = listCommand.execute(); - CommandResult expectedResult = new CommandResult("TOTAL QUANTITY OF SPEAKER: 1" + System.lineSeparator(), equipmentManager.listEquipment(EquipmentType.valueOf("SPEAKER"))); + CommandResult expectedResult = new CommandResult("TOTAL QUANTITY OF SPEAKER: 1" + System.lineSeparator(), equipmentManager.listEquipment(EquipmentType.valueOf("SPEAKER"))); assertEquals(expectedResult, actualResult); } diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 618a8fe313..e66e263fd4 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -212,7 +212,7 @@ void extractArguments_noSpaceBeforeTypeSlashDelimiterFound_exceptionThrown() { @Test void extractArguments_wrongArgTypesUsed_exceptionThrown() throws IncompleteCommandException { - Throwable exception = assertThrows(IncompleteCommandException.class, ()-> parser.extractArguments("x/Speaker B a/Speaker b/1000 d/Loud Technologies e/2022-02-23")); + Throwable exception = assertThrows(IncompleteCommandException.class, () -> parser.extractArguments("x/Speaker B a/Speaker b/1000 d/Loud Technologies e/2022-02-23")); assertEquals("No parameters found!", exception.getMessage()); } From fae2e3d4f5602b0c969cdf9cb75372128de34a0f Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 17 Mar 2022 22:46:47 +0800 Subject: [PATCH 047/229] Edit UpdateCommandTest for refactored code --- src/test/java/seedu/command/UpdateCommandTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/seedu/command/UpdateCommandTest.java b/src/test/java/seedu/command/UpdateCommandTest.java index 0d614e22b9..d63302571e 100644 --- a/src/test/java/seedu/command/UpdateCommandTest.java +++ b/src/test/java/seedu/command/UpdateCommandTest.java @@ -71,9 +71,8 @@ void generateUpdatePairs_nonNullUpdates_success() { @Test void prepareUpdate_missingSlashDelimiter_assertionErrorThrown() throws AssertionError { ArrayList testArrayList = new ArrayList<>(Collections.singleton("thiswillnotwork")); - updateCommand = new UpdateCommand(testArrayList); try { - updateCommand.prepareUpdate(); + updateCommand = new UpdateCommand(testArrayList); } catch (AssertionError error) { assertEquals("Each args will need to include minimally a '/' to split arg and value upon", error.getMessage()); } From e422a07e9382f3f74db98b0dfd7594862532748b Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 17 Mar 2022 23:49:35 +0800 Subject: [PATCH 048/229] Further align code to quality standards --- src/main/java/seedu/Pair.java | 8 +++- src/main/java/seedu/command/AddCommand.java | 15 +++--- src/main/java/seedu/command/CheckCommand.java | 9 ++-- src/main/java/seedu/command/Command.java | 10 ++-- .../java/seedu/command/CommandResult.java | 28 ++++++----- .../java/seedu/command/DeleteCommand.java | 14 +++--- src/main/java/seedu/command/ListCommand.java | 14 +++--- .../java/seedu/command/UpdateCommand.java | 32 +++++++++---- src/main/java/seedu/equipment/Equipment.java | 18 ++++++-- .../seedu/equipment/EquipmentManager.java | 46 +++++++++++++++---- .../parser/IncompleteCommandException.java | 2 +- src/main/java/seedu/parser/Parser.java | 33 +++++++------ 12 files changed, 148 insertions(+), 81 deletions(-) diff --git a/src/main/java/seedu/Pair.java b/src/main/java/seedu/Pair.java index 1178e67953..477cbd70f4 100644 --- a/src/main/java/seedu/Pair.java +++ b/src/main/java/seedu/Pair.java @@ -36,8 +36,12 @@ public K getKey() { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } Pair pair = (Pair) o; return key.equals(pair.key) && value.equals(pair.value); } diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index d283668c89..95859a103a 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -9,10 +9,11 @@ * Subclass of Command. Handles adding of equipment to equipmentInventory. */ public class AddCommand extends Command { - private final ArrayList COMMAND_STRINGS; + private final ArrayList commandStrings; public static final String COMMAND_WORD = "add"; public static final String COMMAND_DESCRIPTION = ": Adds a Equipment to the equipmentInventory. " - + "Parameters: n/ITEM_NAME s/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE" + System.lineSeparator() + + "Parameters: n/ITEM_NAME s/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE" + + System.lineSeparator() + "Example: " + "add n/SpeakerB s/S1404115ASF t/Speaker c/1000 pf/Loud_Technologies pd/2022-02-23"; public static final String DUPLICATE_ITEM_ERROR = "There is already an item with this serial number: %1$s"; @@ -23,28 +24,28 @@ public class AddCommand extends Command { * @param commandStrings parsed user input which contains details of equipment to be added */ public AddCommand(ArrayList commandStrings) { - this.COMMAND_STRINGS = commandStrings; + this.commandStrings = commandStrings; successMessage = "Equipment successfully added: %1$s, serial number %2$s"; usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; } /** - * Adds equipment with details given in COMMAND_STRINGS + * Adds equipment with details given in COMMAND_STRINGS. * * @return CommandResult with message from execution of this command */ public CommandResult execute() { try { - addEquipment(COMMAND_STRINGS); + addEquipment(commandStrings); } catch (DuplicateSerialNumber e) { - return new CommandResult(String.format(DUPLICATE_ITEM_ERROR, COMMAND_STRINGS.get(1))); + return new CommandResult(String.format(DUPLICATE_ITEM_ERROR, commandStrings.get(1))); } catch (NullPointerException | NumberFormatException e) { return new CommandResult(INCORRECT_COST_FORMAT); } catch (IllegalArgumentException e) { return new CommandResult(INCORRECT_ENUM_TYPE); } - return new CommandResult(String.format(successMessage, COMMAND_STRINGS.get(0), COMMAND_STRINGS.get(1))); + return new CommandResult(String.format(successMessage, commandStrings.get(0), commandStrings.get(1))); } /** diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index 57bca24caf..9cdaa7522e 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -1,7 +1,6 @@ package seedu.command; import seedu.equipment.Equipment; -import seedu.equipment.EquipmentType; import java.util.ArrayList; @@ -9,7 +8,7 @@ * Subclass of Command. Handles checking of details of a specified equipment from equipmentInventory. */ public class CheckCommand extends Command { - private final ArrayList COMMAND_STRINGS; + private final ArrayList commandStrings; public static final String COMMAND_WORD = "check"; public static final String COMMAND_DESCRIPTION = ": Gives details of the equipment with the specified name. " + "Parameters: n/ITEM_NAME" + System.lineSeparator() @@ -22,7 +21,7 @@ public class CheckCommand extends Command { * @param commandStrings parsed user input which contains details of equipment to be viewed */ public CheckCommand(ArrayList commandStrings) { - COMMAND_STRINGS = commandStrings; + this.commandStrings = commandStrings; successMessage = "Here are the equipment matching to '%1$s':" + System.lineSeparator(); usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; } @@ -33,8 +32,8 @@ public CheckCommand(ArrayList commandStrings) { * @return CommandResult with message from execution of this command */ public CommandResult execute() { - ArrayList equipment = equipmentManager.checkEquipment(COMMAND_STRINGS.get(0)); + ArrayList equipment = equipmentManager.checkEquipment(commandStrings.get(0)); - return new CommandResult(String.format(successMessage, COMMAND_STRINGS.get(0)), equipment); + return new CommandResult(String.format(successMessage, commandStrings.get(0)), equipment); } } diff --git a/src/main/java/seedu/command/Command.java b/src/main/java/seedu/command/Command.java index a7cc0e1ba4..1728b67fa8 100644 --- a/src/main/java/seedu/command/Command.java +++ b/src/main/java/seedu/command/Command.java @@ -3,7 +3,7 @@ import seedu.equipment.EquipmentManager; /** - * Abstract parent class for all types of commands + * Abstract parent class for all types of commands. */ // The Command class as well as all of its subclasses was created with reference to // https://github.com/nus-cs2113-AY2122S2/personbook/tree/master/src/main/java/seedu/personbook/commands @@ -11,10 +11,10 @@ public abstract class Command { protected String successMessage; public String usageReminder; protected EquipmentManager equipmentManager; - protected final String INCORRECT_ENUM_TYPE = "Wrong type of equipment. The allowed types are: MICROPHONE, SPEAKER, STAND, CABLE"; - protected final String INCORRECT_COST_FORMAT = "Please enter numbers only for cost and omit symbols"; - protected final String INVALID_SERIAL_NUMBER = "No such serial number, please enter an existing serial number"; - protected final String MISSING_SERIAL_NUMBER = "Serial Number is required to run this command"; + protected static final String INCORRECT_ENUM_TYPE = "Wrong type of equipment. The allowed types are: MICROPHONE, SPEAKER, STAND, CABLE"; + protected static final String INCORRECT_COST_FORMAT = "Please enter numbers only for cost and omit symbols"; + protected static final String INVALID_SERIAL_NUMBER = "No such serial number, please enter an existing serial number"; + protected static final String MISSING_SERIAL_NUMBER = "Serial Number is required to run this command"; public abstract CommandResult execute(); diff --git a/src/main/java/seedu/command/CommandResult.java b/src/main/java/seedu/command/CommandResult.java index 2804d9d71c..bd6ffc12ef 100644 --- a/src/main/java/seedu/command/CommandResult.java +++ b/src/main/java/seedu/command/CommandResult.java @@ -11,37 +11,41 @@ // Created with reference to // https://github.com/nus-cs2113-AY2122S2/personbook/tree/master/src/main/java/seedu/personbook/commands public class CommandResult { - private final String RESULT_TO_SHOW; - private final ArrayList RELEVANT_EQUIPMENT; + private final String resultToShow; + private final ArrayList relevantEquipment; public CommandResult(String result) { - RESULT_TO_SHOW = result; - RELEVANT_EQUIPMENT = null; + resultToShow = result; + relevantEquipment = null; } public CommandResult(String result, ArrayList equipmentList) { - RESULT_TO_SHOW = result; - RELEVANT_EQUIPMENT = equipmentList; + resultToShow = result; + relevantEquipment = equipmentList; } public String getResultToShow() { - return RESULT_TO_SHOW; + return resultToShow; } public ArrayList getRelevantEquipment() { - return RELEVANT_EQUIPMENT; + return relevantEquipment; } @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } CommandResult that = (CommandResult) o; - return RESULT_TO_SHOW.equals(that.RESULT_TO_SHOW) && Objects.equals(RELEVANT_EQUIPMENT, that.RELEVANT_EQUIPMENT); + return resultToShow.equals(that.resultToShow) && Objects.equals(relevantEquipment, that.relevantEquipment); } @Override public int hashCode() { - return Objects.hash(RESULT_TO_SHOW, RELEVANT_EQUIPMENT); + return Objects.hash(resultToShow, relevantEquipment); } } diff --git a/src/main/java/seedu/command/DeleteCommand.java b/src/main/java/seedu/command/DeleteCommand.java index f26591a90f..353842330a 100644 --- a/src/main/java/seedu/command/DeleteCommand.java +++ b/src/main/java/seedu/command/DeleteCommand.java @@ -6,7 +6,7 @@ * Subclass of Command. Handles deleting of equipment from equipmentInventory. */ public class DeleteCommand extends Command { - private final ArrayList COMMAND_STRINGS; + private final ArrayList commandStrings; public static final String COMMAND_WORD = "delete"; public static final String COMMAND_DESCRIPTION = ": Deletes the equipment with the specified serial number. " + "Parameters: s/SERIAL_NUMBER" + System.lineSeparator() @@ -14,31 +14,31 @@ public class DeleteCommand extends Command { + "delete s/SM57-1"; /** - * constructor for DeleteCommand. Initialises successMessage and usageReminder from Command + * constructor for DeleteCommand. Initialises successMessage and usageReminder from Command. * * @param commandStrings parsed user input which contains details of equipment to be deleted */ public DeleteCommand(ArrayList commandStrings) { - COMMAND_STRINGS = commandStrings; + this.commandStrings = commandStrings; successMessage = "Equipment successfully deleted: %1$s, serial number %2$s"; usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; } /** - * Deletes equipment specified by serial number + * Deletes equipment specified by serial number. * * @return CommandResult with message from execution of this command */ public CommandResult execute() { String equipmentName; try { - equipmentName = equipmentManager.getEquipmentList().get(COMMAND_STRINGS.get(0)).getItemName(); + equipmentName = equipmentManager.getEquipmentList().get(commandStrings.get(0)).getItemName(); } catch (NullPointerException e) { return new CommandResult(INVALID_SERIAL_NUMBER); } - equipmentManager.deleteEquipment(COMMAND_STRINGS.get(0)); + equipmentManager.deleteEquipment(commandStrings.get(0)); - return new CommandResult(String.format(successMessage, equipmentName, COMMAND_STRINGS.get(0))); + return new CommandResult(String.format(successMessage, equipmentName, commandStrings.get(0))); } } diff --git a/src/main/java/seedu/command/ListCommand.java b/src/main/java/seedu/command/ListCommand.java index 6df36f2efa..da741bf1e1 100644 --- a/src/main/java/seedu/command/ListCommand.java +++ b/src/main/java/seedu/command/ListCommand.java @@ -9,14 +9,14 @@ * Subclass of Command. Handles listing of all equipment or listing of equipment of specified type. */ public class ListCommand extends Command { - private final ArrayList COMMAND_STRINGS; + private final ArrayList commandStrings; public static final String COMMAND_WORD = "list"; /** * constructor for ListCommand with NO specified type. Initialises successMessage and usageReminder from Command */ public ListCommand() { - COMMAND_STRINGS = null; + this.commandStrings = null; successMessage = "TOTAL QUANTITY OF EQUIPMENT: %1$d" + System.lineSeparator(); usageReminder = COMMAND_WORD + ": print a list of all equipment in the inventory. " + "Parameters: NIL" @@ -29,12 +29,12 @@ public ListCommand() { } /** - * constructor for ListCommand with specified type. Initialises successMessage and usageReminder from Command + * constructor for ListCommand with specified type. Initialises successMessage and usageReminder from Command. * * @param commandStrings parsed user input which contains details of equipment to be viewed */ public ListCommand(ArrayList commandStrings) { - COMMAND_STRINGS = commandStrings; + this.commandStrings = commandStrings; successMessage = "TOTAL QUANTITY OF %1$s: %2$d" + System.lineSeparator(); usageReminder = COMMAND_WORD + ": print a list of all equipment in the inventory. " + "Parameters: NIL" @@ -47,20 +47,20 @@ public ListCommand(ArrayList commandStrings) { } /** - * List all equipment or list equipment of specified type + * List all equipment or list equipment of specified type. * * @return CommandResult with message from execution of this command */ public CommandResult execute() { int listSize; ArrayList equipmentArrayList; - if (COMMAND_STRINGS == null) { + if (commandStrings == null) { equipmentArrayList = equipmentManager.listEquipment(); listSize = equipmentArrayList.size(); return new CommandResult(String.format(successMessage, listSize), equipmentArrayList); } - EquipmentType typeToList = EquipmentType.valueOf(COMMAND_STRINGS.get(0)); + EquipmentType typeToList = EquipmentType.valueOf(commandStrings.get(0)); equipmentArrayList = equipmentManager.listEquipment(typeToList); listSize = equipmentArrayList.size(); return new CommandResult(String.format(successMessage, typeToList, listSize), equipmentArrayList); diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java index 114a27ed2d..4614f7d675 100644 --- a/src/main/java/seedu/command/UpdateCommand.java +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -1,13 +1,12 @@ package seedu.command; import seedu.Pair; -import seedu.parser.IncompleteCommandException; import java.util.ArrayList; import java.util.Objects; public class UpdateCommand extends Command { - private final ArrayList COMMAND_STRINGS; + private final ArrayList commandStrings; public static final String COMMAND_WORD = "update"; public static final String COMMAND_DESCRIPTION = ": Updates the equipment with the specified serial number. " + "Parameters: s/SERIAL_NUMBER" + System.lineSeparator() @@ -15,14 +14,18 @@ public class UpdateCommand extends Command { + "update s/SM57-1"; private String serialNumber; - private String updateName = null, purchaseDate = null, type = null, purchaseFrom = null, cost = null; + private String updateName = null; + private String purchaseDate = null; + private String type = null; + private String purchaseFrom = null; + private String cost = null; /** * constructor for UpdateCommand. Initialises successMessage and usageReminder from Command */ public UpdateCommand(ArrayList commandStrings) { - COMMAND_STRINGS = commandStrings; + this.commandStrings = commandStrings; successMessage = "Equipment successfully updated for serial number %1$s," + System.lineSeparator() + "Updated details are: %2$s"; @@ -32,8 +35,9 @@ public UpdateCommand(ArrayList commandStrings) { } public CommandResult execute() { - if (getSerialNumber() == null) + if (getSerialNumber() == null) { return new CommandResult(MISSING_SERIAL_NUMBER); + } ArrayList> updatePairs = generateUpdatePairs(); equipmentManager.updateEquipment(serialNumber, updatePairs); @@ -117,10 +121,9 @@ public String generateUpdateString() { * Should multiple arguments specifying the same argument parameter (e.g. 'c/1000' and 'c/2000') be given, * the previous arguments passed in will be overwritten by the most recent parameter ('c/2000' in example). * - * @return Command object */ protected void prepareUpdate() throws AssertionError { - for (String s : COMMAND_STRINGS) { + for (String s : commandStrings) { int delimiterPos = s.indexOf('/'); // the case where delimiterPos = -1 is impossible as // ARGUMENT_FORMAT and ARGUMENT_TRAILING_FORMAT regex requires a '/' @@ -155,10 +158,19 @@ protected void prepareUpdate() throws AssertionError { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } UpdateCommand that = (UpdateCommand) o; - return serialNumber.equals(that.serialNumber) && Objects.equals(updateName, that.updateName) && Objects.equals(purchaseDate, that.purchaseDate) && Objects.equals(type, that.type) && Objects.equals(purchaseFrom, that.purchaseFrom) && Objects.equals(cost, that.cost); + return serialNumber.equals(that.serialNumber) && + Objects.equals(updateName, that.updateName) && + Objects.equals(purchaseDate, that.purchaseDate) && + Objects.equals(type, that.type) && + Objects.equals(purchaseFrom, that.purchaseFrom) && + Objects.equals(cost, that.cost); } @Override diff --git a/src/main/java/seedu/equipment/Equipment.java b/src/main/java/seedu/equipment/Equipment.java index 3845c7dc03..d834ee7242 100644 --- a/src/main/java/seedu/equipment/Equipment.java +++ b/src/main/java/seedu/equipment/Equipment.java @@ -10,7 +10,8 @@ public class Equipment { private String purchasedFrom; private String purchasedDate; - public Equipment(String itemName, String serialNumber, EquipmentType type, double cost, String purchasedFrom, String purchasedDate) { + public Equipment(String itemName, String serialNumber, EquipmentType type, double cost, String purchasedFrom, + String purchasedDate) { this.itemName = itemName; this.serialNumber = serialNumber; this.type = type; @@ -69,10 +70,19 @@ public void setPurchasedDate(String purchasedDate) { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } Equipment equipment = (Equipment) o; - return Double.compare(equipment.cost, cost) == 0 && itemName.equals(equipment.itemName) && serialNumber.equals(equipment.serialNumber) && type == equipment.type && purchasedFrom.equals(equipment.purchasedFrom) && purchasedDate.equals(equipment.purchasedDate); + return Double.compare(equipment.cost, cost) == 0 && + itemName.equals(equipment.itemName) && + serialNumber.equals(equipment.serialNumber) && + type == equipment.type && + purchasedFrom.equals(equipment.purchasedFrom) && + purchasedDate.equals(equipment.purchasedDate); } @Override diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index 17089fe784..fddc909a49 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -8,7 +8,8 @@ public class EquipmentManager { private final HashMap equipmentList = new HashMap<>(); - public void addEquipment(String itemName, String serialNumber, EquipmentType type, double cost, String purchasedFrom, String purchasedDate) throws DuplicateSerialNumber { + public void addEquipment(String itemName, String serialNumber, EquipmentType type, double cost, + String purchasedFrom, String purchasedDate) throws DuplicateSerialNumber { if (!equipmentList.containsKey(serialNumber)) { Equipment equipment = new Equipment(itemName, serialNumber, type, cost, purchasedFrom, purchasedDate); equipmentList.putIfAbsent(serialNumber, equipment); @@ -27,6 +28,10 @@ public ArrayList checkEquipment(String itemName) { return listOfEquipments; } + public ArrayList listEquipment() { + return new ArrayList<>(equipmentList.values()); + } + public ArrayList listEquipment(EquipmentType type) { ArrayList listOfEquipments = new ArrayList<>(); for (Equipment equipment : equipmentList.values()) { @@ -41,13 +46,38 @@ public HashMap getEquipmentList() { return equipmentList; } - public ArrayList listEquipment() { - return new ArrayList<>(equipmentList.values()); - } - - public String updateEquipment(String serialNumber, ArrayList> updatePairs) { - // To be updated - return ""; + public boolean updateEquipment(String serialNumber, ArrayList> updatePairs) { + if (!equipmentList.containsKey(serialNumber)){ + return false; + } + Equipment updatedEquipment = equipmentList.get(serialNumber); + for (Pair updates : updatePairs) { + String key = updates.getKey(); + switch (key) { + case "itemName": + updatedEquipment.setItemName(updates.getValue()); + break; + case "type": + try { + updatedEquipment.setType(EquipmentType.valueOf(updates.getValue())); + } catch (IllegalArgumentException e) { + return false; + } + break; + case "cost": + updatedEquipment.setCost(Double.parseDouble(updates.getValue())); + break; + case "purchaseDate": + updatedEquipment.setPurchasedDate(updates.getValue()); + break; + case "purchaseFrom": + updatedEquipment.setPurchasedFrom(updates.getValue()); + break; + default: + break; + } + } + return true; } public void deleteEquipment(String serialNumber) { diff --git a/src/main/java/seedu/parser/IncompleteCommandException.java b/src/main/java/seedu/parser/IncompleteCommandException.java index ec35747cf9..70043c5bf8 100644 --- a/src/main/java/seedu/parser/IncompleteCommandException.java +++ b/src/main/java/seedu/parser/IncompleteCommandException.java @@ -1,7 +1,7 @@ package seedu.parser; /** - * Signal that given data does not include necessary arguments + * Signal that given data does not include necessary arguments. * Adapted from: https://github.com/se-edu/addressbook-level2/blob/master/src/seedu/addressbook/data/exception/ */ public class IncompleteCommandException extends Exception { diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 4536ec3a68..63f6f77281 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -2,7 +2,13 @@ import java.util.ArrayList; -import seedu.command.*; +import seedu.command.AddCommand; +import seedu.command.CheckCommand; +import seedu.command.Command; +import seedu.command.DeleteCommand; +import seedu.command.IncorrectCommand; +import seedu.command.ListCommand; +import seedu.command.UpdateCommand; import java.util.Collections; import java.util.regex.Matcher; @@ -20,12 +26,12 @@ public class Parser { */ public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s+(?.+)"); public static final Pattern ADD_COMMAND_FORMAT = Pattern.compile( - "n\\/(?.+)" + "\\s+" + - "s\\/(?.+)" + "\\s+" + - "t\\/(?.+)" + "\\s+" + - "c\\/(?.+)" + "\\s+" + - "pf\\/(?.+)" + "\\s+" + - "pd\\/(?.+)" + "n\\/(?.+)" + "\\s+" + + "s\\/(?.+)" + "\\s+" + + "t\\/(?.+)" + "\\s+" + + "c\\/(?.+)" + "\\s+" + + "pf\\/(?.+)" + "\\s+" + + "pd\\/(?.+)" ); public static final Pattern VIEW_COMMAND_FORMAT = Pattern.compile("n/(?.+)"); public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("s/(?.+)"); @@ -42,7 +48,7 @@ public class Parser { public static final String INCORRECT_COMMAND_FORMAT = "Incorrect Command format!"; /** - * Interpret the command requested by the user and returns a corresponding Command object + * Interpret the command requested by the user and returns a corresponding Command object. * * @param userInput Raw string of input values * @return command of parent class Command with parameters specified @@ -101,7 +107,8 @@ public Command parseCommand(String userInput) { /** * 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", remainder arguments can be empty, in which case a null second object will be passed in. + * If first element is "list", remainder arguments can be empty, in which case a null + * second object will be passed in. * * @param userInput String to be split into substrings * @return ArrayList of String, first element being the command term and the second element being arguments @@ -126,7 +133,7 @@ public ArrayList splitCommandTerm(String userInput) throws IncompleteCom } /** - * Prepare arguments for AddCommand by splitting up the arguments into different parts + * Prepare arguments for AddCommand by splitting up the arguments into different parts. *

* Index: * 0. equipmentName : String of equipment name @@ -159,7 +166,7 @@ protected ArrayList prepareAdd(String args) throws IncompleteCommandExce } /** - * Prepare argument for CheckCommand by removing the preceding "n/" prefix + * Prepare argument for CheckCommand by removing the preceding "n/" prefix. * * @param args String to be split into substrings * @return ArrayList of one element (assumes rest of string is item name) @@ -174,7 +181,7 @@ protected ArrayList prepareView(String args) throws IncompleteCommandExc } /** - * Prepare argument for DeleteCommand by removing the preceding "s/" prefix + * Prepare argument for DeleteCommand by removing the preceding "s/" prefix. * * @param args String to be split into substrings * @return ArrayList of one element (assumes rest of string is serial number) @@ -189,7 +196,7 @@ protected ArrayList prepareDelete(String args) throws IncompleteCommandE } /** - * Splits main arguments into split tags with each substring + * Splits main arguments into split tags with each substring. * * @param args String to be split into substrings * @return ArrayList of two elements From 23b0aae1f23e940b3ed5c41262429ae500b32fb5 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Fri, 18 Mar 2022 00:21:05 +0800 Subject: [PATCH 049/229] Add toString override method for Equipment, and print arraylist in Duke --- src/main/java/seedu/duke/Duke.java | 16 +++++++++++----- src/main/java/seedu/equipment/Equipment.java | 11 +++++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java index a52fd55916..01e5bd9277 100644 --- a/src/main/java/seedu/duke/Duke.java +++ b/src/main/java/seedu/duke/Duke.java @@ -14,11 +14,14 @@ public class Duke { * Main entry-point for the java.duke.Duke application. */ public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; + String logo = " _ _ \n" + + " (_) | | \n" + + " ___ __ _ _ _ _ _ __ _ __ ___ ___ _ __ | |_ _ __ ___ __ _ _ __ __ _ __ _ ___ _ __ \n" + + " / _ \\/ _` | | | | | '_ \\| '_ ` _ \\ / _ \\ '_ \\| __| '_ ` _ \\ / _` | '_ \\ / _` |/ _` |/ _ \\ '__|\n" + + " | __/ (_| | |_| | | |_) | | | | | | __/ | | | |_| | | | | | (_| | | | | (_| | (_| | __/ | \n" + + " \\___|\\__, |\\__,_|_| .__/|_| |_| |_|\\___|_| |_|\\__|_| |_| |_|\\__,_|_| |_|\\__,_|\\__, |\\___|_| \n" + + " | | | | __/ | \n" + + " |_| |_| |___/"; System.out.println("Hello from\n" + logo); System.out.println("What do you want to do?"); @@ -34,6 +37,9 @@ private void runCommandLoop() { command = new Parser().parseCommand(userCommand); result = executeCommand(command); System.out.println(result.getResultToShow()); + if (result.getRelevantEquipment() != null) { + System.out.println(result.getRelevantEquipment()); + } userCommand = in.nextLine(); } diff --git a/src/main/java/seedu/equipment/Equipment.java b/src/main/java/seedu/equipment/Equipment.java index d834ee7242..de696d998a 100644 --- a/src/main/java/seedu/equipment/Equipment.java +++ b/src/main/java/seedu/equipment/Equipment.java @@ -89,4 +89,15 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(itemName, serialNumber, type, cost, purchasedFrom, purchasedDate); } + + @Override + public String toString() { + return "itemName=" + itemName + "," + System.lineSeparator() + + "serialNumber=" + serialNumber + "," + System.lineSeparator() + + "type=" + type + "," + System.lineSeparator() + + "cost=" + cost + "," + System.lineSeparator() + + "purchasedFrom=" + purchasedFrom + "," + System.lineSeparator() + + "purchasedDate=" + purchasedDate + System.lineSeparator() + System.lineSeparator() + ; + } } From ca235c6e1c6cb84b0557f69596e9011102df316d Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Fri, 18 Mar 2022 00:50:28 +0800 Subject: [PATCH 050/229] Add tests for updateEquipment --- .../seedu/equipment/EquipmentManager.java | 6 ++- .../seedu/equipment/EquipmentManagerTest.java | 52 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/test/java/seedu/equipment/EquipmentManagerTest.java diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index 4a6c586622..794599aa9d 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -6,7 +6,11 @@ import java.util.HashMap; public class EquipmentManager { - private final HashMap equipmentList = new HashMap<>(); + private final HashMap equipmentList; + + public EquipmentManager() { + this.equipmentList = new HashMap<>(); + } public void addEquipment(String itemName, String serialNumber, EquipmentType type, double cost, String purchasedFrom, String purchasedDate) throws DuplicateSerialNumber { if (!equipmentList.containsKey(serialNumber)) { diff --git a/src/test/java/seedu/equipment/EquipmentManagerTest.java b/src/test/java/seedu/equipment/EquipmentManagerTest.java new file mode 100644 index 0000000000..ea2fe94f5c --- /dev/null +++ b/src/test/java/seedu/equipment/EquipmentManagerTest.java @@ -0,0 +1,52 @@ +package seedu.equipment; + +import org.junit.jupiter.api.Test; +import seedu.Pair; + +import java.util.ArrayList; +import java.util.HashMap; + +import static org.junit.jupiter.api.Assertions.*; + +public class EquipmentManagerTest { + @Test + public void updateEquipment_success() throws DuplicateSerialNumber { + EquipmentManager equipmentManager = new EquipmentManager(); + equipmentManager.addEquipment("Speaker B", "S1404115ASF", EquipmentType.valueOf("SPEAKER"), 1000, "Loud Technologies", "2022-02-23"); + 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", "2022-03-17")); + updates.add(new Pair<>("purchaseFrom", "Louder Technologies")); + equipmentManager.updateEquipment("S1404115ASF", updates); + HashMap equipments = equipmentManager.getEquipmentList(); + Equipment expectedEquipment = new Equipment("Speaker A", "S1404115ASF", EquipmentType.valueOf("STAND"), 2000, "Louder Technologies", "2022-03-17"); + assertEquals(expectedEquipment, equipments.get("S1404115ASF")); + } + + @Test + public void updateEquipment_keyNotFound() { + EquipmentManager equipmentManager = new EquipmentManager(); + 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", "2022-03-17")); + updates.add(new Pair<>("purchaseFrom", "Louder Technologies")); + assertFalse(equipmentManager.updateEquipment("WRONG SERIAL NUMBER", updates)); + } + + @Test + public void updateEquipment_invalidEquipmentType() throws DuplicateSerialNumber { + EquipmentManager equipmentManager = new EquipmentManager(); + equipmentManager.addEquipment("Speaker B", "S1404115ASF", EquipmentType.valueOf("SPEAKER"), 1000, "Loud Technologies", "2022-02-23"); + ArrayList> updates = new ArrayList<>(); + updates.add(new Pair<>("itemName", "Speaker A")); + updates.add(new Pair<>("type", "INVALID EQUIPMENT TYPE")); + updates.add(new Pair<>("cost", "2000")); + updates.add(new Pair<>("purchaseDate", "2022-03-17")); + updates.add(new Pair<>("purchaseFrom", "Louder Technologies")); + assertFalse(equipmentManager.updateEquipment("S1404115ASF", updates)); + } +} From e0bbfbb8b94860420e66abfd714d89f7e2b49979 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Fri, 18 Mar 2022 01:19:01 +0800 Subject: [PATCH 051/229] Fix List bug --- src/main/java/seedu/parser/Parser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 63f6f77281..b8b412408f 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -92,7 +92,7 @@ public Command parseCommand(String userInput) { return new IncorrectCommand(UpdateCommand.COMMAND_WORD + UpdateCommand.COMMAND_DESCRIPTION); } case ListCommand.COMMAND_WORD: - if (commandAndArgument.get(1).equals(null)) { + if (commandAndArgument.get(1) == null) { return new ListCommand(); } else { return new ListCommand(new ArrayList<>(Collections.singleton(commandAndArgument.get(1)))); From 7ee90e5a31439f8de398d84ed6304b7cca632e5f Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Fri, 18 Mar 2022 10:58:22 +0800 Subject: [PATCH 052/229] Add enableAssertions to build.gradle --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index b0c5528fb5..91fffd027d 100644 --- a/build.gradle +++ b/build.gradle @@ -43,4 +43,5 @@ checkstyle { run{ standardInput = System.in + enableAssertions = true } From 202b7017ab71752802fe60ba4265f105e3390373 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Sun, 20 Mar 2022 18:05:41 +0800 Subject: [PATCH 053/229] Add Storage class --- .gitignore | 1 + build.gradle | 1 + src/main/java/META-INF/MANIFEST.MF | 3 ++ src/main/java/seedu/duke/Duke.java | 15 +++++-- .../seedu/equipment/EquipmentManager.java | 8 ++++ src/main/java/seedu/storage/Storage.java | 42 +++++++++++++++++++ 6 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 src/main/java/META-INF/MANIFEST.MF create mode 100644 src/main/java/seedu/storage/Storage.java diff --git a/.gitignore b/.gitignore index f69985ef1f..62dd67f87c 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ bin/ /text-ui-test/ACTUAL.txt text-ui-test/EXPECTED-UNIX.TXT +/equipments.json diff --git a/build.gradle b/build.gradle index b0c5528fb5..0d26bcc048 100644 --- a/build.gradle +++ b/build.gradle @@ -12,6 +12,7 @@ repositories { dependencies { testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0' testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0' + implementation 'com.google.code.gson:gson:2.9.0' } test { diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..19e86fe56e --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: seedu.duke.Duke + diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java index 01e5bd9277..df6356536c 100644 --- a/src/main/java/seedu/duke/Duke.java +++ b/src/main/java/seedu/duke/Duke.java @@ -2,13 +2,16 @@ import seedu.command.Command; import seedu.command.CommandResult; +import seedu.equipment.DuplicateSerialNumber; import seedu.equipment.EquipmentManager; import seedu.parser.Parser; +import seedu.storage.Storage; import java.util.Scanner; public class Duke { - private EquipmentManager equipmentInventory = new EquipmentManager(); + private static EquipmentManager equipmentInventory = new EquipmentManager(); + private static Storage storage = new Storage(); /** * Main entry-point for the java.duke.Duke application. @@ -23,9 +26,15 @@ public static void main(String[] args) { " | | | | __/ | \n" + " |_| |_| |___/"; System.out.println("Hello from\n" + logo); + Duke duke = new Duke(); + try { + storage.loadData(equipmentInventory); + } catch (DuplicateSerialNumber e) { + // Do ? + } System.out.println("What do you want to do?"); - - new Duke().runCommandLoop(); + duke.runCommandLoop(); + storage.saveData(equipmentInventory); } private void runCommandLoop() { diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index fddc909a49..dd313132ed 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -18,6 +18,14 @@ public void addEquipment(String itemName, String serialNumber, EquipmentType typ } } + public void addEquipment(Equipment equipment) throws DuplicateSerialNumber { + if (!equipmentList.containsKey(equipment.getSerialNumber())) { + equipmentList.putIfAbsent(equipment.getSerialNumber(), equipment); + } else if (equipmentList.containsKey(equipment.getSerialNumber())) { + throw new DuplicateSerialNumber(); + } + } + public ArrayList checkEquipment(String itemName) { ArrayList listOfEquipments = new ArrayList<>(); for (Equipment equipment : equipmentList.values()) { diff --git a/src/main/java/seedu/storage/Storage.java b/src/main/java/seedu/storage/Storage.java new file mode 100644 index 0000000000..f70049e940 --- /dev/null +++ b/src/main/java/seedu/storage/Storage.java @@ -0,0 +1,42 @@ +package seedu.storage; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import seedu.equipment.DuplicateSerialNumber; +import seedu.equipment.Equipment; +import seedu.equipment.EquipmentManager; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + + +public class Storage { + public final String path = "./equipments.json"; + private final Gson gson = new Gson(); + + public void loadData(EquipmentManager equipmentManager) throws DuplicateSerialNumber { + 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("io1"); + } + } + + 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("io2"); + } + } +} From 78bd51280a746124686703e7aeae01bead23a159 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Sun, 20 Mar 2022 18:18:04 +0800 Subject: [PATCH 054/229] Add exception --- src/main/java/seedu/storage/Storage.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/storage/Storage.java b/src/main/java/seedu/storage/Storage.java index f70049e940..85d7777cd0 100644 --- a/src/main/java/seedu/storage/Storage.java +++ b/src/main/java/seedu/storage/Storage.java @@ -25,7 +25,7 @@ public void loadData(EquipmentManager equipmentManager) throws DuplicateSerialNu equipmentManager.addEquipment(equipment); } } catch (IOException e) { - System.out.println("io1"); + System.out.println("File not found! Creating new file..."); } } @@ -36,7 +36,7 @@ public void saveData(EquipmentManager equipmentManager) { gson.toJson(equipments, writer); writer.close(); } catch (IOException e) { - System.out.println("io2"); + // Do ? } } } From ddc046dab5072f63b45c4e0d884b1156aec023ce Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Mon, 21 Mar 2022 12:33:57 +0800 Subject: [PATCH 055/229] Update gitignore to ignore manifest --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index f69985ef1f..6e2a766acb 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ bin/ /text-ui-test/ACTUAL.txt text-ui-test/EXPECTED-UNIX.TXT +META-INF/MANIFEST.MF +src/main/java/META-INF/MANIFEST.MF From c3627d0d5c950727b197866f2bee974f83631526 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Mon, 21 Mar 2022 12:42:30 +0800 Subject: [PATCH 056/229] Add logic to check for successful update in UpdateCommand Fixes #55 --- src/main/java/seedu/command/UpdateCommand.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java index 4614f7d675..ac59d6d275 100644 --- a/src/main/java/seedu/command/UpdateCommand.java +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -12,6 +12,7 @@ public class UpdateCommand extends Command { + "Parameters: s/SERIAL_NUMBER" + System.lineSeparator() + "Example: " + "update s/SM57-1"; + public static final String UPDATE_FAILURE_MESSAGE = "Equipment was not updated successfully."; private String serialNumber; private String updateName = null; @@ -40,7 +41,9 @@ public CommandResult execute() { } ArrayList> updatePairs = generateUpdatePairs(); - equipmentManager.updateEquipment(serialNumber, updatePairs); + if(!equipmentManager.updateEquipment(serialNumber, updatePairs)){ + return new CommandResult(UPDATE_FAILURE_MESSAGE); + } return new CommandResult(String.format(successMessage, serialNumber, generateUpdateString())); } From 5485dfc53074426aac02ea3c7f8fd76c624a640b Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Mon, 21 Mar 2022 13:21:13 +0800 Subject: [PATCH 057/229] Update AddCommand to support any order of strings given to add new equipment Fixes #56 --- src/main/java/seedu/command/AddCommand.java | 38 ++++-- .../seedu/command/ModificationCommand.java | 83 +++++++++++++ .../java/seedu/command/UpdateCommand.java | 114 ++++-------------- .../java/seedu/command/UpdateCommandTest.java | 4 +- 4 files changed, 133 insertions(+), 106 deletions(-) create mode 100644 src/main/java/seedu/command/ModificationCommand.java diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index 95859a103a..962a3d4763 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -1,6 +1,7 @@ package seedu.command; import seedu.equipment.DuplicateSerialNumber; +import seedu.equipment.Equipment; import seedu.equipment.EquipmentType; import java.util.ArrayList; @@ -8,8 +9,7 @@ /** * Subclass of Command. Handles adding of equipment to equipmentInventory. */ -public class AddCommand extends Command { - private final ArrayList commandStrings; +public class AddCommand extends ModificationCommand { public static final String COMMAND_WORD = "add"; public static final String COMMAND_DESCRIPTION = ": Adds a Equipment to the equipmentInventory. " + "Parameters: n/ITEM_NAME s/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE" @@ -17,6 +17,8 @@ public class AddCommand extends Command { + "Example: " + "add n/SpeakerB s/S1404115ASF t/Speaker c/1000 pf/Loud_Technologies pd/2022-02-23"; public static final String DUPLICATE_ITEM_ERROR = "There is already an item with this serial number: %1$s"; + public static final String ATTRIBUTE_NOT_SET_ERROR = "Unable to add. " + + "One or more than one of the attributes of Equipment is not specified."; /** * constructor for AddCommand. Initialises successMessage and usageReminder from Command @@ -24,9 +26,11 @@ public class AddCommand extends Command { * @param commandStrings parsed user input which contains details of equipment to be added */ public AddCommand(ArrayList commandStrings) { - this.commandStrings = commandStrings; + super(commandStrings); successMessage = "Equipment successfully added: %1$s, serial number %2$s"; usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; + + prepareModification(); } /** @@ -35,6 +39,10 @@ public AddCommand(ArrayList commandStrings) { * @return CommandResult with message from execution of this command */ public CommandResult execute() { + if (!checkAttributes()) { + return new CommandResult(ATTRIBUTE_NOT_SET_ERROR); + } + try { addEquipment(commandStrings); } catch (DuplicateSerialNumber e) { @@ -54,13 +62,23 @@ public CommandResult execute() { * @param userInput ArrayList of String which contains the individual attributes of the equipment to be added */ public void addEquipment(ArrayList userInput) throws DuplicateSerialNumber { - String equipmentName = userInput.get(0); - String serialNumber = userInput.get(1); - EquipmentType type = EquipmentType.valueOf(userInput.get(2)); - double cost = Double.parseDouble(userInput.get(3)); - String purchasedFrom = userInput.get(4); - String purchasedDate = userInput.get(5); + EquipmentType type = EquipmentType.valueOf(this.type); + double cost = Double.parseDouble(this.cost); + + Equipment newEquipment = new Equipment(equipmentName, serialNumber, type, cost, purchasedFrom, purchasedDate); + equipmentManager.addEquipment(newEquipment); + } + + /** + * Checks if all the attributes of Equipment to be added have been set. There should be no null values. + * @return boolean to indicate whether all attributes are set. + */ + public boolean checkAttributes() { + if (equipmentName == null || serialNumber == null || type == null || cost == null || + purchasedFrom == null || purchasedDate == null) { + return false; + } - equipmentManager.addEquipment(equipmentName, serialNumber, type, cost, purchasedFrom, purchasedDate); + return true; } } diff --git a/src/main/java/seedu/command/ModificationCommand.java b/src/main/java/seedu/command/ModificationCommand.java new file mode 100644 index 0000000000..4bc3a96e16 --- /dev/null +++ b/src/main/java/seedu/command/ModificationCommand.java @@ -0,0 +1,83 @@ +package seedu.command; + +import java.util.ArrayList; + +public abstract class ModificationCommand extends Command { + protected final ArrayList commandStrings; + protected String serialNumber; + protected String equipmentName = null; + protected String purchasedDate = null; + protected String type = null; + protected String purchasedFrom = null; + protected String cost = null; + + public ModificationCommand(ArrayList commandStrings) { + this.commandStrings = commandStrings; + } + + public abstract CommandResult execute(); + + public void setSerialNumber(String serialNumber) { + this.serialNumber = serialNumber; + } + + public void setEquipmentName(String equipmentName) { + this.equipmentName = equipmentName; + } + + public void setPurchasedDate(String purchasedDate) { + this.purchasedDate = purchasedDate; + } + + public void setType(String type) { + this.type = type; + } + + public void setPurchasedFrom(String purchasedFrom) { + this.purchasedFrom = purchasedFrom; + } + + public void setCost(String cost) { + this.cost = cost; + } + + /** + * Set up UpdateCommand with arguments required to update a given item + *

+ * Should multiple arguments specifying the same argument parameter (e.g. 'c/1000' and 'c/2000') be given, + * the previous arguments passed in will be overwritten by the most recent parameter ('c/2000' in example). + */ + protected void prepareModification() throws AssertionError { + for (String s : commandStrings) { + int delimiterPos = s.indexOf('/'); + // the case where delimiterPos = -1 is impossible as + // ARGUMENT_FORMAT and ARGUMENT_TRAILING_FORMAT regex requires a '/' + assert delimiterPos != -1 : "Each args will need to include minimally a '/' to split arg and value upon"; + String argType = s.substring(0, delimiterPos); + String argValue = s.substring(delimiterPos + 1); + switch (argType) { + case "n": + setEquipmentName(argValue); + break; + case "pd": + setPurchasedDate(argValue); + break; + case "t": + setType(argValue); + break; + case "pf": + setPurchasedFrom(argValue); + break; + case "c": + setCost(argValue); + break; + case "s": + setSerialNumber(argValue); + break; + default: + System.out.println("`" + argValue + "` not accepted for type " + argType + ": Unrecognised Tag"); + } + } + + } +} diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java index ac59d6d275..71b4daf097 100644 --- a/src/main/java/seedu/command/UpdateCommand.java +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -5,36 +5,29 @@ import java.util.ArrayList; import java.util.Objects; -public class UpdateCommand extends Command { - private final ArrayList commandStrings; +public class UpdateCommand extends ModificationCommand { + public static final String UPDATE_FAILURE_MESSAGE = "Equipment was not updated successfully."; public static final String COMMAND_WORD = "update"; public static final String COMMAND_DESCRIPTION = ": Updates the equipment with the specified serial number. " + "Parameters: s/SERIAL_NUMBER" + System.lineSeparator() + "Example: " + "update s/SM57-1"; - public static final String UPDATE_FAILURE_MESSAGE = "Equipment was not updated successfully."; - private String serialNumber; - - private String updateName = null; - private String purchaseDate = null; - private String type = null; - private String purchaseFrom = null; - private String cost = null; /** * constructor for UpdateCommand. Initialises successMessage and usageReminder from Command */ public UpdateCommand(ArrayList commandStrings) { - this.commandStrings = commandStrings; + super(commandStrings); successMessage = "Equipment successfully updated for serial number %1$s," + System.lineSeparator() + "Updated details are: %2$s"; usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; - prepareUpdate(); + prepareModification(); } + @Override public CommandResult execute() { if (getSerialNumber() == null) { return new CommandResult(MISSING_SERIAL_NUMBER); @@ -52,34 +45,10 @@ public String getSerialNumber() { return serialNumber; } - public void setSerialNumber(String serialNumber) { - this.serialNumber = serialNumber; - } - - public void setUpdateName(String updateName) { - this.updateName = updateName; - } - - public void setPurchaseDate(String purchaseDate) { - this.purchaseDate = purchaseDate; - } - - public void setType(String type) { - this.type = type; - } - - public void setPurchaseFrom(String purchaseFrom) { - this.purchaseFrom = purchaseFrom; - } - - public void setCost(String cost) { - this.cost = cost; - } - public ArrayList> generateUpdatePairs() { ArrayList> pairs = new ArrayList<>(); - if (updateName != null) { - pairs.add(new Pair<>("itemName", updateName)); + if (equipmentName != null) { + pairs.add(new Pair<>("itemName", equipmentName)); } if (type != null) { pairs.add(new Pair<>("type", type)); @@ -87,11 +56,11 @@ public ArrayList> generateUpdatePairs() { if (cost != null) { pairs.add(new Pair<>("cost", cost)); } - if (purchaseDate != null) { - pairs.add(new Pair<>("purchasedDate", purchaseDate)); + if (purchasedDate != null) { + pairs.add(new Pair<>("purchasedDate", purchasedDate)); } - if (purchaseFrom != null) { - pairs.add(new Pair<>("purchasedFrom", purchaseFrom)); + if (purchasedFrom != null) { + pairs.add(new Pair<>("purchasedFrom", purchasedFrom)); } return pairs; @@ -99,8 +68,8 @@ public ArrayList> generateUpdatePairs() { public String generateUpdateString() { String updateDetails = ""; - if (updateName != null) { - updateDetails = updateDetails + System.lineSeparator() + "New name: " + updateName; + if (equipmentName != null) { + updateDetails = updateDetails + System.lineSeparator() + "New name: " + equipmentName; } if (type != null) { updateDetails = updateDetails + System.lineSeparator() + "New type: " + type; @@ -108,57 +77,16 @@ public String generateUpdateString() { if (cost != null) { updateDetails = updateDetails + System.lineSeparator() + "New cost: " + cost; } - if (purchaseDate != null) { - updateDetails = updateDetails + System.lineSeparator() + "New purchase date: " + purchaseDate; + if (purchasedDate != null) { + updateDetails = updateDetails + System.lineSeparator() + "New purchase date: " + purchasedDate; } - if (purchaseFrom != null) { - updateDetails = updateDetails + System.lineSeparator() + "New purchased from: " + purchaseFrom; + if (purchasedFrom != null) { + updateDetails = updateDetails + System.lineSeparator() + "New purchased from: " + purchasedFrom; } return updateDetails; } - /** - * Set up UpdateCommand with arguments required to update a given item - *

- * Should multiple arguments specifying the same argument parameter (e.g. 'c/1000' and 'c/2000') be given, - * the previous arguments passed in will be overwritten by the most recent parameter ('c/2000' in example). - * - */ - protected void prepareUpdate() throws AssertionError { - for (String s : commandStrings) { - int delimiterPos = s.indexOf('/'); - // the case where delimiterPos = -1 is impossible as - // ARGUMENT_FORMAT and ARGUMENT_TRAILING_FORMAT regex requires a '/' - assert delimiterPos != -1 : "Each args will need to include minimally a '/' to split arg and value upon"; - String argType = s.substring(0, delimiterPos); - String argValue = s.substring(delimiterPos + 1); - switch (argType) { - case "n": - setUpdateName(argValue); - break; - case "pd": - setPurchaseDate(argValue); - break; - case "t": - setType(argValue); - break; - case "pf": - setPurchaseFrom(argValue); - break; - case "c": - setCost(argValue); - break; - case "s": - setSerialNumber(argValue); - break; - default: - System.out.println("`" + argValue + "` not updated for type " + argType + ": Unrecognised Tag"); - } - } - - } - @Override public boolean equals(Object o) { if (this == o) { @@ -169,15 +97,15 @@ public boolean equals(Object o) { } UpdateCommand that = (UpdateCommand) o; return serialNumber.equals(that.serialNumber) && - Objects.equals(updateName, that.updateName) && - Objects.equals(purchaseDate, that.purchaseDate) && + Objects.equals(equipmentName, that.equipmentName) && + Objects.equals(purchasedDate, that.purchasedDate) && Objects.equals(type, that.type) && - Objects.equals(purchaseFrom, that.purchaseFrom) && + Objects.equals(purchasedFrom, that.purchasedFrom) && Objects.equals(cost, that.cost); } @Override public int hashCode() { - return Objects.hash(serialNumber, updateName, purchaseDate, type, purchaseFrom, cost); + return Objects.hash(serialNumber, equipmentName, purchasedDate, type, purchasedFrom, cost); } } diff --git a/src/test/java/seedu/command/UpdateCommandTest.java b/src/test/java/seedu/command/UpdateCommandTest.java index d63302571e..275c6fd7f3 100644 --- a/src/test/java/seedu/command/UpdateCommandTest.java +++ b/src/test/java/seedu/command/UpdateCommandTest.java @@ -1,6 +1,5 @@ package seedu.command; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import seedu.Pair; @@ -8,7 +7,6 @@ import seedu.equipment.EquipmentManager; import seedu.equipment.EquipmentType; import seedu.parser.IncompleteCommandException; -import seedu.parser.Parser; import java.util.ArrayList; import java.util.Arrays; @@ -95,7 +93,7 @@ void prepareUpdate_mostRecentArgValueUsed_success() throws IncompleteCommandExce Arrays.asList("s/S1404115ASF", "n/Speaker A") )); UpdateCommand actualCommand = new UpdateCommand(testArrayList); - actualCommand.prepareUpdate(); + actualCommand.prepareModification(); assertEquals(expectedCommand, actualCommand); } } \ No newline at end of file From 0a1b8371231a0436c94b2cfa439503745ca9f049 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Mon, 21 Mar 2022 14:51:41 +0800 Subject: [PATCH 058/229] Rename DuplicateSerialNumber to DuplicateSerialNumberException --- src/main/java/seedu/command/AddCommand.java | 6 ++--- src/main/java/seedu/duke/Duke.java | 8 ++---- .../equipment/DuplicateSerialNumber.java | 6 ----- .../DuplicateSerialNumberException.java | 6 +++++ src/main/java/seedu/equipment/Equipment.java | 25 +++++++++---------- .../seedu/equipment/EquipmentManager.java | 15 +++++------ src/main/java/seedu/storage/Storage.java | 18 ++++++++----- .../java/seedu/command/AddCommandTest.java | 6 ++--- .../java/seedu/command/CheckCommandTest.java | 4 +-- .../java/seedu/command/DeleteCommandTest.java | 4 +-- .../java/seedu/command/ListCommandTest.java | 6 ++--- .../java/seedu/command/UpdateCommandTest.java | 4 +-- 12 files changed, 55 insertions(+), 53 deletions(-) delete mode 100644 src/main/java/seedu/equipment/DuplicateSerialNumber.java create mode 100644 src/main/java/seedu/equipment/DuplicateSerialNumberException.java diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index 95859a103a..29db5cf957 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -1,6 +1,6 @@ package seedu.command; -import seedu.equipment.DuplicateSerialNumber; +import seedu.equipment.DuplicateSerialNumberException; import seedu.equipment.EquipmentType; import java.util.ArrayList; @@ -37,7 +37,7 @@ public AddCommand(ArrayList commandStrings) { public CommandResult execute() { try { addEquipment(commandStrings); - } catch (DuplicateSerialNumber e) { + } catch (DuplicateSerialNumberException e) { return new CommandResult(String.format(DUPLICATE_ITEM_ERROR, commandStrings.get(1))); } catch (NullPointerException | NumberFormatException e) { return new CommandResult(INCORRECT_COST_FORMAT); @@ -53,7 +53,7 @@ public CommandResult execute() { * * @param userInput ArrayList of String which contains the individual attributes of the equipment to be added */ - public void addEquipment(ArrayList userInput) throws DuplicateSerialNumber { + public void addEquipment(ArrayList userInput) throws DuplicateSerialNumberException { String equipmentName = userInput.get(0); String serialNumber = userInput.get(1); EquipmentType type = EquipmentType.valueOf(userInput.get(2)); diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java index df6356536c..0f2c5e080a 100644 --- a/src/main/java/seedu/duke/Duke.java +++ b/src/main/java/seedu/duke/Duke.java @@ -2,7 +2,7 @@ import seedu.command.Command; import seedu.command.CommandResult; -import seedu.equipment.DuplicateSerialNumber; +import seedu.equipment.DuplicateSerialNumberException; import seedu.equipment.EquipmentManager; import seedu.parser.Parser; import seedu.storage.Storage; @@ -27,11 +27,7 @@ public static void main(String[] args) { " |_| |_| |___/"; System.out.println("Hello from\n" + logo); Duke duke = new Duke(); - try { - storage.loadData(equipmentInventory); - } catch (DuplicateSerialNumber e) { - // Do ? - } + storage.loadData(equipmentInventory); System.out.println("What do you want to do?"); duke.runCommandLoop(); storage.saveData(equipmentInventory); diff --git a/src/main/java/seedu/equipment/DuplicateSerialNumber.java b/src/main/java/seedu/equipment/DuplicateSerialNumber.java deleted file mode 100644 index bda724e5d3..0000000000 --- a/src/main/java/seedu/equipment/DuplicateSerialNumber.java +++ /dev/null @@ -1,6 +0,0 @@ -package seedu.equipment; - -public class DuplicateSerialNumber extends Exception { - public DuplicateSerialNumber() { - } -} diff --git a/src/main/java/seedu/equipment/DuplicateSerialNumberException.java b/src/main/java/seedu/equipment/DuplicateSerialNumberException.java new file mode 100644 index 0000000000..46e10480f0 --- /dev/null +++ b/src/main/java/seedu/equipment/DuplicateSerialNumberException.java @@ -0,0 +1,6 @@ +package seedu.equipment; + +public class DuplicateSerialNumberException extends Exception { + public DuplicateSerialNumberException() { + } +} diff --git a/src/main/java/seedu/equipment/Equipment.java b/src/main/java/seedu/equipment/Equipment.java index de696d998a..685438045b 100644 --- a/src/main/java/seedu/equipment/Equipment.java +++ b/src/main/java/seedu/equipment/Equipment.java @@ -77,12 +77,12 @@ public boolean equals(Object o) { return false; } Equipment equipment = (Equipment) o; - return Double.compare(equipment.cost, cost) == 0 && - itemName.equals(equipment.itemName) && - serialNumber.equals(equipment.serialNumber) && - type == equipment.type && - purchasedFrom.equals(equipment.purchasedFrom) && - purchasedDate.equals(equipment.purchasedDate); + return Double.compare(equipment.cost, cost) == 0 + && itemName.equals(equipment.itemName) + && serialNumber.equals(equipment.serialNumber) + && type == equipment.type + && purchasedFrom.equals(equipment.purchasedFrom) + && purchasedDate.equals(equipment.purchasedDate); } @Override @@ -92,12 +92,11 @@ public int hashCode() { @Override public String toString() { - return "itemName=" + itemName + "," + System.lineSeparator() + - "serialNumber=" + serialNumber + "," + System.lineSeparator() + - "type=" + type + "," + System.lineSeparator() + - "cost=" + cost + "," + System.lineSeparator() + - "purchasedFrom=" + purchasedFrom + "," + System.lineSeparator() + - "purchasedDate=" + purchasedDate + System.lineSeparator() + System.lineSeparator() - ; + return "itemName=" + itemName + "," + System.lineSeparator() + + "serialNumber=" + serialNumber + "," + System.lineSeparator() + + "type=" + type + "," + System.lineSeparator() + + "cost=" + cost + "," + System.lineSeparator() + + "purchasedFrom=" + purchasedFrom + "," + System.lineSeparator() + + "purchasedDate=" + purchasedDate + System.lineSeparator() + System.lineSeparator(); } } diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index dd313132ed..968cd48a5c 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -9,20 +9,21 @@ public class EquipmentManager { private final HashMap equipmentList = new HashMap<>(); public void addEquipment(String itemName, String serialNumber, EquipmentType type, double cost, - String purchasedFrom, String purchasedDate) throws DuplicateSerialNumber { + String purchasedFrom, String purchasedDate) throws DuplicateSerialNumberException { if (!equipmentList.containsKey(serialNumber)) { Equipment equipment = new Equipment(itemName, serialNumber, type, cost, purchasedFrom, purchasedDate); - equipmentList.putIfAbsent(serialNumber, equipment); + equipmentList.put(serialNumber, equipment); } else if (equipmentList.containsKey(serialNumber)) { - throw new DuplicateSerialNumber(); + throw new DuplicateSerialNumberException(); } } - public void addEquipment(Equipment equipment) throws DuplicateSerialNumber { - if (!equipmentList.containsKey(equipment.getSerialNumber())) { + public void addEquipment(Equipment equipment) throws DuplicateSerialNumberException { + String serialNumber = equipment.getSerialNumber(); + if (!equipmentList.containsKey(serialNumber)) { equipmentList.putIfAbsent(equipment.getSerialNumber(), equipment); - } else if (equipmentList.containsKey(equipment.getSerialNumber())) { - throw new DuplicateSerialNumber(); + } else { + throw new DuplicateSerialNumberException(); } } diff --git a/src/main/java/seedu/storage/Storage.java b/src/main/java/seedu/storage/Storage.java index 85d7777cd0..64e1b015f7 100644 --- a/src/main/java/seedu/storage/Storage.java +++ b/src/main/java/seedu/storage/Storage.java @@ -2,11 +2,12 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; -import seedu.equipment.DuplicateSerialNumber; +import seedu.equipment.DuplicateSerialNumberException; import seedu.equipment.Equipment; import seedu.equipment.EquipmentManager; - -import java.io.*; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -14,10 +15,13 @@ public class Storage { + public final String FILE_NOT_FOUND_ERROR_MESSAGE = "File not found! A new file will be created after this session."; + public final String SAVE_ERROR_MESSAGE = "An error occurred while saving!"; + public final String DUPLICATE_SERIAL_NUMBER_ERROR = "Duplicate serial number found!"; public final String path = "./equipments.json"; private final Gson gson = new Gson(); - public void loadData(EquipmentManager equipmentManager) throws DuplicateSerialNumber { + public void loadData(EquipmentManager equipmentManager) { try { Reader reader = Files.newBufferedReader(Path.of(path)); List equipments = gson.fromJson(reader, new TypeToken>() {}.getType()); @@ -25,7 +29,9 @@ public void loadData(EquipmentManager equipmentManager) throws DuplicateSerialNu equipmentManager.addEquipment(equipment); } } catch (IOException e) { - System.out.println("File not found! Creating new file..."); + System.out.println(FILE_NOT_FOUND_ERROR_MESSAGE); + } catch (DuplicateSerialNumberException e) { + System.out.println(DUPLICATE_SERIAL_NUMBER_ERROR); } } @@ -36,7 +42,7 @@ public void saveData(EquipmentManager equipmentManager) { gson.toJson(equipments, writer); writer.close(); } catch (IOException e) { - // Do ? + System.out.println(SAVE_ERROR_MESSAGE); } } } diff --git a/src/test/java/seedu/command/AddCommandTest.java b/src/test/java/seedu/command/AddCommandTest.java index 7b707cb04f..7c4561f6b1 100644 --- a/src/test/java/seedu/command/AddCommandTest.java +++ b/src/test/java/seedu/command/AddCommandTest.java @@ -3,7 +3,7 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import seedu.equipment.DuplicateSerialNumber; +import seedu.equipment.DuplicateSerialNumberException; import seedu.equipment.Equipment; import seedu.equipment.EquipmentManager; import seedu.equipment.EquipmentType; @@ -21,7 +21,7 @@ class AddCommandTest { ); @Test - void execute_duplicateSerialNumber_exceptionThrown() throws DuplicateSerialNumber { + void execute_duplicateSerialNumber_exceptionThrown() throws DuplicateSerialNumberException { addCommand = new AddCommand(userInput); addCommand.setEquipmentManager(new EquipmentManager()); EquipmentManager equipmentManager = addCommand.equipmentManager; @@ -62,7 +62,7 @@ void execute_incorrectEnumType_exceptionThrown() { } @Test - void addEquipment_validArrayListString_success() throws DuplicateSerialNumber { + void addEquipment_validArrayListString_success() throws DuplicateSerialNumberException { addCommand = new AddCommand(userInput); addCommand.setEquipmentManager(new EquipmentManager()); EquipmentManager equipmentManager = addCommand.equipmentManager; diff --git a/src/test/java/seedu/command/CheckCommandTest.java b/src/test/java/seedu/command/CheckCommandTest.java index 3141b994e8..9e57d67384 100644 --- a/src/test/java/seedu/command/CheckCommandTest.java +++ b/src/test/java/seedu/command/CheckCommandTest.java @@ -1,7 +1,7 @@ package seedu.command; import org.junit.jupiter.api.Test; -import seedu.equipment.DuplicateSerialNumber; +import seedu.equipment.DuplicateSerialNumberException; import seedu.equipment.Equipment; import seedu.equipment.EquipmentManager; import seedu.equipment.EquipmentType; @@ -28,7 +28,7 @@ void execute_validEquipmentName_success() { 1000, "Loud Technologies", "2022-02-23"); - } catch (DuplicateSerialNumber e) { + } catch (DuplicateSerialNumberException e) { fail(); } diff --git a/src/test/java/seedu/command/DeleteCommandTest.java b/src/test/java/seedu/command/DeleteCommandTest.java index c14eea8a26..7d1c0e3d93 100644 --- a/src/test/java/seedu/command/DeleteCommandTest.java +++ b/src/test/java/seedu/command/DeleteCommandTest.java @@ -1,7 +1,7 @@ package seedu.command; import org.junit.jupiter.api.Test; -import seedu.equipment.DuplicateSerialNumber; +import seedu.equipment.DuplicateSerialNumberException; import seedu.equipment.EquipmentManager; import seedu.equipment.EquipmentType; @@ -27,7 +27,7 @@ void execute_validSerialNumber_success() { 1000, "Loud Technologies", "2022-02-23"); - } catch (DuplicateSerialNumber e) { + } catch (DuplicateSerialNumberException e) { fail(); } diff --git a/src/test/java/seedu/command/ListCommandTest.java b/src/test/java/seedu/command/ListCommandTest.java index 5991cfdfc7..8d84ea2178 100644 --- a/src/test/java/seedu/command/ListCommandTest.java +++ b/src/test/java/seedu/command/ListCommandTest.java @@ -1,7 +1,7 @@ package seedu.command; import org.junit.jupiter.api.Test; -import seedu.equipment.DuplicateSerialNumber; +import seedu.equipment.DuplicateSerialNumberException; import seedu.equipment.EquipmentManager; import seedu.equipment.EquipmentType; @@ -27,7 +27,7 @@ void execute_specifiedType_success() { 1000, "Loud Technologies", "2022-02-23"); - } catch (DuplicateSerialNumber e) { + } catch (DuplicateSerialNumberException e) { fail(); } @@ -49,7 +49,7 @@ void execute_noSpecifiedType_success() { 1000, "Loud Technologies", "2022-02-23"); - } catch (DuplicateSerialNumber e) { + } catch (DuplicateSerialNumberException e) { fail(); } diff --git a/src/test/java/seedu/command/UpdateCommandTest.java b/src/test/java/seedu/command/UpdateCommandTest.java index d63302571e..64882d5f04 100644 --- a/src/test/java/seedu/command/UpdateCommandTest.java +++ b/src/test/java/seedu/command/UpdateCommandTest.java @@ -4,7 +4,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import seedu.Pair; -import seedu.equipment.DuplicateSerialNumber; +import seedu.equipment.DuplicateSerialNumberException; import seedu.equipment.EquipmentManager; import seedu.equipment.EquipmentType; import seedu.parser.IncompleteCommandException; @@ -29,7 +29,7 @@ void setup() { 1000, "Loud Technologies", "2022-02-23"); - } catch (DuplicateSerialNumber e) { + } catch (DuplicateSerialNumberException e) { fail(); } From bc932777d65c447d1760fcde2cdb90e2bf09c117 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Mon, 21 Mar 2022 21:22:39 +0800 Subject: [PATCH 059/229] Add JUnit test for new method checkAttributes() in AddCommand --- .../seedu/command/ModificationCommand.java | 3 +++ .../java/seedu/command/AddCommandTest.java | 24 ++++++++++++++++--- .../java/seedu/command/UpdateCommandTest.java | 8 +++---- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/main/java/seedu/command/ModificationCommand.java b/src/main/java/seedu/command/ModificationCommand.java index 4bc3a96e16..ce7884bd1e 100644 --- a/src/main/java/seedu/command/ModificationCommand.java +++ b/src/main/java/seedu/command/ModificationCommand.java @@ -2,6 +2,9 @@ import java.util.ArrayList; +/** + * Abstract class acting as parent class to AddCommand and UpdateCommand which have use for the same prepareModification method. + */ public abstract class ModificationCommand extends Command { protected final ArrayList commandStrings; protected String serialNumber; diff --git a/src/test/java/seedu/command/AddCommandTest.java b/src/test/java/seedu/command/AddCommandTest.java index 7b707cb04f..ab6df48e0a 100644 --- a/src/test/java/seedu/command/AddCommandTest.java +++ b/src/test/java/seedu/command/AddCommandTest.java @@ -17,7 +17,7 @@ class AddCommandTest { AddCommand addCommand; ArrayList userInput = new ArrayList<>( - Arrays.asList("Speaker B", "S1404115ASF", "SPEAKER", "1000", "Loud Technologies", "2022-02-23") + Arrays.asList("n/Speaker B", "s/S1404115ASF", "t/SPEAKER", "c/1000", "pf/Loud Technologies", "pd/2022-02-23") ); @Test @@ -40,7 +40,7 @@ void execute_duplicateSerialNumber_exceptionThrown() throws DuplicateSerialNumbe @Test void execute_incorrectCostFormat_exceptionThrown() { addCommand = new AddCommand(new ArrayList<>( - Arrays.asList("Speaker B", "S1404115ASF", "SPEAKER", "$1000", "Loud Technologies", "2022-02-23") + Arrays.asList("n/Speaker B", "s/S1404115ASF", "t/SPEAKER", "c/$1000", "pf/Loud Technologies", "pd/2022-02-23") )); CommandResult expectedResult = new CommandResult("Please enter numbers only for cost and omit symbols"); @@ -51,7 +51,7 @@ void execute_incorrectCostFormat_exceptionThrown() { @Test void execute_incorrectEnumType_exceptionThrown() { addCommand = new AddCommand(new ArrayList<>( - Arrays.asList("Speaker B", "S1404115ASF", "SPEAKERS", "1000", "Loud Technologies", "2022-02-23") + Arrays.asList("n/Speaker B", "s/S1404115ASF", "t/SPEAKERS", "c/1000", "pf/Loud Technologies", "pd/2022-02-23") )); addCommand.setEquipmentManager(new EquipmentManager()); EquipmentManager equipmentManager = addCommand.equipmentManager; @@ -80,4 +80,22 @@ void addEquipment_validArrayListString_success() throws DuplicateSerialNumber { assertEquals(equipmentListOriginalSize + 1, equipmentManager.getEquipmentList().size()); assertEquals(expectedEquipment, actualEquipment); } + + @Test + void checkAttributes_allAttributesSet_true() { + addCommand = new AddCommand(userInput); + boolean actualResult = addCommand.checkAttributes(); + + assertEquals(true, actualResult); + } + + @Test + void checkAttributes_oneOrMoreNulls_false() { + addCommand = new AddCommand(new ArrayList<>( + Arrays.asList("n/Speaker B", "s/S1404115ASF", "t/SPEAKER", "pf/Loud Technologies") + )); + boolean actualResult = addCommand.checkAttributes(); + + assertEquals(false, actualResult); + } } \ No newline at end of file diff --git a/src/test/java/seedu/command/UpdateCommandTest.java b/src/test/java/seedu/command/UpdateCommandTest.java index 275c6fd7f3..39e0a913a8 100644 --- a/src/test/java/seedu/command/UpdateCommandTest.java +++ b/src/test/java/seedu/command/UpdateCommandTest.java @@ -67,7 +67,7 @@ void generateUpdatePairs_nonNullUpdates_success() { } @Test - void prepareUpdate_missingSlashDelimiter_assertionErrorThrown() throws AssertionError { + void prepareModification_missingSlashDelimiter_assertionErrorThrown() throws AssertionError { ArrayList testArrayList = new ArrayList<>(Collections.singleton("thiswillnotwork")); try { updateCommand = new UpdateCommand(testArrayList); @@ -77,16 +77,16 @@ void prepareUpdate_missingSlashDelimiter_assertionErrorThrown() throws Assertion } @Test - void prepareUpdate_missingSerialNumber_exceptionThrown() throws IncompleteCommandException { + 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")); + "n/Speaker B", "t/SPEAKER", "c/1000", "pf/Loud Technologies", "pd/2022-02-23")); updateCommand = new UpdateCommand(testArrayList); CommandResult expectedResult = new CommandResult("Serial Number is required to run this command"); assertEquals(expectedResult, updateCommand.execute()); } @Test - void prepareUpdate_mostRecentArgValueUsed_success() throws IncompleteCommandException { + void prepareModification_mostRecentArgValueUsed_success() throws IncompleteCommandException { ArrayList testArrayList = new ArrayList<>(Arrays.asList( "s/S1404115ASF", "n/Speaker B", "n/Speaker A")); UpdateCommand expectedCommand = new UpdateCommand(new ArrayList<>( From 4e92084993321fc7b9f6c438dd650823fb05aa73 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Mon, 21 Mar 2022 22:57:52 +0800 Subject: [PATCH 060/229] Add UI class to have UI displaying messages to users. Fixes #36 --- src/main/java/seedu/duke/Duke.java | 41 ++++++++++--------- src/main/java/seedu/equipment/Equipment.java | 13 +++--- src/main/java/seedu/ui/TextUi.java | 42 ++++++++++++++++++++ 3 files changed, 68 insertions(+), 28 deletions(-) create mode 100644 src/main/java/seedu/ui/TextUi.java diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java index 01e5bd9277..3f01e60de3 100644 --- a/src/main/java/seedu/duke/Duke.java +++ b/src/main/java/seedu/duke/Duke.java @@ -4,50 +4,49 @@ import seedu.command.CommandResult; import seedu.equipment.EquipmentManager; import seedu.parser.Parser; +import seedu.ui.TextUi; import java.util.Scanner; public class Duke { private EquipmentManager equipmentInventory = new EquipmentManager(); + private TextUi ui; /** * Main entry-point for the java.duke.Duke application. */ public static void main(String[] args) { - String logo = " _ _ \n" + - " (_) | | \n" + - " ___ __ _ _ _ _ _ __ _ __ ___ ___ _ __ | |_ _ __ ___ __ _ _ __ __ _ __ _ ___ _ __ \n" + - " / _ \\/ _` | | | | | '_ \\| '_ ` _ \\ / _ \\ '_ \\| __| '_ ` _ \\ / _` | '_ \\ / _` |/ _` |/ _ \\ '__|\n" + - " | __/ (_| | |_| | | |_) | | | | | | __/ | | | |_| | | | | | (_| | | | | (_| | (_| | __/ | \n" + - " \\___|\\__, |\\__,_|_| .__/|_| |_| |_|\\___|_| |_|\\__|_| |_| |_|\\__,_|_| |_|\\__,_|\\__, |\\___|_| \n" + - " | | | | __/ | \n" + - " |_| |_| |___/"; - System.out.println("Hello from\n" + logo); - System.out.println("What do you want to do?"); - - new Duke().runCommandLoop(); + Duke duke = new Duke(); + + duke.start(); + duke.runCommandLoop(); + } + + /** + * Initialises the required objects and loads up the data from storage and show welcome message to user + */ + private void start() { + ui = new TextUi(); + ui.showWelcomeMessage(); } private void runCommandLoop() { Scanner in = new Scanner(System.in); - String userCommand = in.nextLine(); + String userCommand; Command command; CommandResult result; - while (!userCommand.equals("bye")) { + do { + userCommand = in.nextLine(); command = new Parser().parseCommand(userCommand); result = executeCommand(command); - System.out.println(result.getResultToShow()); - if (result.getRelevantEquipment() != null) { - System.out.println(result.getRelevantEquipment()); - } - - userCommand = in.nextLine(); - } + ui.showResultToUser(result); + } while (!userCommand.equals("bye")); } private CommandResult executeCommand(Command command) { command.setEquipmentManager(equipmentInventory); CommandResult result = command.execute(); + return result; } } diff --git a/src/main/java/seedu/equipment/Equipment.java b/src/main/java/seedu/equipment/Equipment.java index de696d998a..b8f544b989 100644 --- a/src/main/java/seedu/equipment/Equipment.java +++ b/src/main/java/seedu/equipment/Equipment.java @@ -92,12 +92,11 @@ public int hashCode() { @Override public String toString() { - return "itemName=" + itemName + "," + System.lineSeparator() + - "serialNumber=" + serialNumber + "," + System.lineSeparator() + - "type=" + type + "," + System.lineSeparator() + - "cost=" + cost + "," + System.lineSeparator() + - "purchasedFrom=" + purchasedFrom + "," + System.lineSeparator() + - "purchasedDate=" + purchasedDate + System.lineSeparator() + System.lineSeparator() - ; + return "serialNumber=" + serialNumber + "," + + "itemName=" + itemName + "," + + "type=" + type + "," + + "cost=" + cost + "," + + "purchasedFrom=" + purchasedFrom + "," + + "purchasedDate=" + purchasedDate; } } diff --git a/src/main/java/seedu/ui/TextUi.java b/src/main/java/seedu/ui/TextUi.java new file mode 100644 index 0000000000..77e56594f5 --- /dev/null +++ b/src/main/java/seedu/ui/TextUi.java @@ -0,0 +1,42 @@ +package seedu.ui; + +import seedu.command.Command; +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 final static 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?"); + } + + /** + * 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++; + } + } + } + +} From b1dde28fc873b1f662638523f4c1e60449bedea6 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Mon, 21 Mar 2022 23:40:26 +0800 Subject: [PATCH 061/229] Add HelpCommand to show available commands to users. --- src/main/java/seedu/command/AddCommand.java | 1 + src/main/java/seedu/command/CheckCommand.java | 1 + .../java/seedu/command/DeleteCommand.java | 1 + src/main/java/seedu/command/HelpCommand.java | 29 +++++++++++++++++++ src/main/java/seedu/command/ListCommand.java | 29 +++++++++---------- .../java/seedu/command/UpdateCommand.java | 6 ++-- src/main/java/seedu/parser/Parser.java | 17 ++++++----- 7 files changed, 58 insertions(+), 26 deletions(-) create mode 100644 src/main/java/seedu/command/HelpCommand.java diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index 95859a103a..435ee54c53 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -12,6 +12,7 @@ public class AddCommand extends Command { private final ArrayList commandStrings; public static final String COMMAND_WORD = "add"; public static final String COMMAND_DESCRIPTION = ": Adds a Equipment to the equipmentInventory. " + + System.lineSeparator() + "Parameters: n/ITEM_NAME s/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE" + System.lineSeparator() + "Example: " diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index 9cdaa7522e..7faec9b436 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -11,6 +11,7 @@ public class CheckCommand extends Command { private final ArrayList commandStrings; public static final String COMMAND_WORD = "check"; public static final String COMMAND_DESCRIPTION = ": Gives details of the equipment with the specified name. " + + System.lineSeparator() + "Parameters: n/ITEM_NAME" + System.lineSeparator() + "Example: " + "check n/MixerC"; diff --git a/src/main/java/seedu/command/DeleteCommand.java b/src/main/java/seedu/command/DeleteCommand.java index 353842330a..0d16992ec6 100644 --- a/src/main/java/seedu/command/DeleteCommand.java +++ b/src/main/java/seedu/command/DeleteCommand.java @@ -9,6 +9,7 @@ public class DeleteCommand extends Command { private final ArrayList commandStrings; public static final String COMMAND_WORD = "delete"; public static final String COMMAND_DESCRIPTION = ": Deletes the equipment with the specified serial number. " + + System.lineSeparator() + "Parameters: s/SERIAL_NUMBER" + System.lineSeparator() + "Example: " + "delete s/SM57-1"; diff --git a/src/main/java/seedu/command/HelpCommand.java b/src/main/java/seedu/command/HelpCommand.java new file mode 100644 index 0000000000..353e7dc455 --- /dev/null +++ b/src/main/java/seedu/command/HelpCommand.java @@ -0,0 +1,29 @@ +package seedu.command; + +/** + * Subclass of Command. Shows information of the available commands to users. + */ +public class HelpCommand extends Command{ + public static final String COMMAND_WORD = "help"; + public static final String COMMAND_DESCRIPTION = ": Shows details of available commands to users. " + + System.lineSeparator() + + "Parameters: NIL" + System.lineSeparator() + + "Example: " + + "help"; + + public CommandResult execute() { + return new CommandResult(AddCommand.COMMAND_WORD + AddCommand.COMMAND_DESCRIPTION + + System.lineSeparator() + + System.lineSeparator() + DeleteCommand.COMMAND_WORD + DeleteCommand.COMMAND_DESCRIPTION + + System.lineSeparator() + + System.lineSeparator() + UpdateCommand.COMMAND_WORD + UpdateCommand.COMMAND_DESCRIPTION + + System.lineSeparator() + + System.lineSeparator() + ListCommand.COMMAND_WORD + ListCommand.COMMAND_DESCRIPTION + + System.lineSeparator() + + System.lineSeparator() + ListCommand.COMMAND_WORD + ListCommand.COMMAND_DESCRIPTION_WITH_TYPE + + System.lineSeparator() + + System.lineSeparator() + CheckCommand.COMMAND_WORD + CheckCommand.COMMAND_DESCRIPTION + + System.lineSeparator() + + System.lineSeparator() + HelpCommand.COMMAND_WORD + HelpCommand.COMMAND_DESCRIPTION); + } +} diff --git a/src/main/java/seedu/command/ListCommand.java b/src/main/java/seedu/command/ListCommand.java index da741bf1e1..92fd040213 100644 --- a/src/main/java/seedu/command/ListCommand.java +++ b/src/main/java/seedu/command/ListCommand.java @@ -11,6 +11,17 @@ public class ListCommand extends Command { private final ArrayList commandStrings; public static final String COMMAND_WORD = "list"; + public static final String COMMAND_DESCRIPTION = ": Prints a list of all equipment in the inventory. " + + System.lineSeparator() + + "Parameters: NIL" + System.lineSeparator() + + "Example: " + + "list"; + public static final String COMMAND_DESCRIPTION_WITH_TYPE = + "Prints a list of all equipment in the inventory of the specified type. " + + System.lineSeparator() + + "Parameters: t/Type" + System.lineSeparator() + + "Example: " + + "list MICROPHONE"; /** * constructor for ListCommand with NO specified type. Initialises successMessage and usageReminder from Command @@ -18,14 +29,7 @@ public class ListCommand extends Command { public ListCommand() { this.commandStrings = null; successMessage = "TOTAL QUANTITY OF EQUIPMENT: %1$d" + System.lineSeparator(); - usageReminder = COMMAND_WORD + ": print a list of all equipment in the inventory. " - + "Parameters: NIL" - + "Example: " - + "list" + System.lineSeparator() - + COMMAND_WORD + " t/Type: print a list of all equipment in the inventory of the specified type" - + "Parameters: t/Type" - + "Example: " - + "list Microphone"; + usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; } /** @@ -36,14 +40,7 @@ public ListCommand() { public ListCommand(ArrayList commandStrings) { this.commandStrings = commandStrings; successMessage = "TOTAL QUANTITY OF %1$s: %2$d" + System.lineSeparator(); - usageReminder = COMMAND_WORD + ": print a list of all equipment in the inventory. " - + "Parameters: NIL" - + "Example: " - + "list" + System.lineSeparator() - + COMMAND_WORD + " t/Type: print a list of all equipment in the inventory of the specified type" - + "Parameters: t/Type" - + "Example: " - + "list Microphone"; + usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION_WITH_TYPE; } /** diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java index 4614f7d675..9fc76fffd9 100644 --- a/src/main/java/seedu/command/UpdateCommand.java +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -9,9 +9,11 @@ public class UpdateCommand extends Command { private final ArrayList commandStrings; public static final String COMMAND_WORD = "update"; public static final String COMMAND_DESCRIPTION = ": Updates the equipment with the specified serial number. " - + "Parameters: s/SERIAL_NUMBER" + System.lineSeparator() + + System.lineSeparator() + + "Parameters: s/SERIAL_NUMBER(required) n/ITEM_NAME t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE" + + System.lineSeparator() + "Example: " - + "update s/SM57-1"; + + "update s/SM57-1 n/SpeakerC c/2510 pd/2022-08-21"; private String serialNumber; private String updateName = null; diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index b8b412408f..cc407f7851 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -2,13 +2,7 @@ import java.util.ArrayList; -import seedu.command.AddCommand; -import seedu.command.CheckCommand; -import seedu.command.Command; -import seedu.command.DeleteCommand; -import seedu.command.IncorrectCommand; -import seedu.command.ListCommand; -import seedu.command.UpdateCommand; +import seedu.command.*; import java.util.Collections; import java.util.regex.Matcher; @@ -45,7 +39,7 @@ public class Parser { ); public static final String MESSAGE_INCOMPLETE_COMMAND_MISSING_DELIMITER = "Please split your command into arguments with each argument seperated by spaces!"; - public static final String INCORRECT_COMMAND_FORMAT = "Incorrect Command format!"; + public static final String INCORRECT_COMMAND_FORMAT = "Incorrect Command format! Enter help for more information."; /** * Interpret the command requested by the user and returns a corresponding Command object. @@ -97,6 +91,8 @@ public Command parseCommand(String userInput) { } else { return new ListCommand(new ArrayList<>(Collections.singleton(commandAndArgument.get(1)))); } + case HelpCommand.COMMAND_WORD: + return new HelpCommand(); default: return new IncorrectCommand(INCORRECT_COMMAND_FORMAT); @@ -122,6 +118,11 @@ public ArrayList splitCommandTerm(String userInput) throws IncompleteCom resultArrayList.add(null); return resultArrayList; } + if (userInput.equals(HelpCommand.COMMAND_WORD)) { + resultArrayList.add("help"); + resultArrayList.add(null); + return resultArrayList; + } final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput); // guard against no match if (!matcher.matches()) { From 9fe8ab1536f895c9d0f1eb5d8b6083272817cb52 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Mon, 21 Mar 2022 23:45:30 +0800 Subject: [PATCH 062/229] Update Javadocs for HelpCommand.execute() Fixes #54 --- src/main/java/seedu/command/HelpCommand.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/seedu/command/HelpCommand.java b/src/main/java/seedu/command/HelpCommand.java index 353e7dc455..ccd32d2268 100644 --- a/src/main/java/seedu/command/HelpCommand.java +++ b/src/main/java/seedu/command/HelpCommand.java @@ -11,6 +11,10 @@ public class HelpCommand extends Command{ + "Example: " + "help"; + /** + * List all available commands and their usage examples. + * @return CommandResult with description of all available commands for users to use. + */ public CommandResult execute() { return new CommandResult(AddCommand.COMMAND_WORD + AddCommand.COMMAND_DESCRIPTION + System.lineSeparator() From 2be326f7e16802d3ab00d77d335a044b53c2f7a6 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Mon, 21 Mar 2022 23:47:43 +0800 Subject: [PATCH 063/229] Update welcome message to tell users to enter help if they need help. --- src/main/java/seedu/ui/TextUi.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/ui/TextUi.java b/src/main/java/seedu/ui/TextUi.java index 77e56594f5..7753c32962 100644 --- a/src/main/java/seedu/ui/TextUi.java +++ b/src/main/java/seedu/ui/TextUi.java @@ -20,7 +20,7 @@ public class TextUi { public void showWelcomeMessage() { System.out.println("Hello from" + System.lineSeparator() + LOGO); - System.out.println("What do you want to do?"); + System.out.println("What do you want to do? (ENTER help TO SEE WHAT YOU CAN DO)"); } /** From b64810b559d3412fd1b09a1e645c32a5e807cf38 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 22 Mar 2022 14:23:54 +0800 Subject: [PATCH 064/229] Update creatioin of Parser object to be outside of do while loop --- src/main/java/seedu/duke/Duke.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java index 3f01e60de3..8c576cb09e 100644 --- a/src/main/java/seedu/duke/Duke.java +++ b/src/main/java/seedu/duke/Duke.java @@ -32,12 +32,13 @@ private void start() { private void runCommandLoop() { Scanner in = new Scanner(System.in); + Parser parser = new Parser(); String userCommand; Command command; CommandResult result; do { userCommand = in.nextLine(); - command = new Parser().parseCommand(userCommand); + command = parser.parseCommand(userCommand); result = executeCommand(command); ui.showResultToUser(result); } while (!userCommand.equals("bye")); From 57ced3f44969a080d155ede721b71fee4bea8b1e Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 22 Mar 2022 14:31:27 +0800 Subject: [PATCH 065/229] Update code based on comments given by @shunyao643 for pull request 57 --- src/main/java/seedu/command/ModificationCommand.java | 2 +- src/test/java/seedu/command/AddCommandTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/command/ModificationCommand.java b/src/main/java/seedu/command/ModificationCommand.java index ce7884bd1e..2d0360c0fc 100644 --- a/src/main/java/seedu/command/ModificationCommand.java +++ b/src/main/java/seedu/command/ModificationCommand.java @@ -45,7 +45,7 @@ public void setCost(String cost) { } /** - * Set up UpdateCommand with arguments required to update a given item + * Set up ModificationCommand with arguments required to update a given item *

* Should multiple arguments specifying the same argument parameter (e.g. 'c/1000' and 'c/2000') be given, * the previous arguments passed in will be overwritten by the most recent parameter ('c/2000' in example). diff --git a/src/test/java/seedu/command/AddCommandTest.java b/src/test/java/seedu/command/AddCommandTest.java index ab6df48e0a..9856cbe241 100644 --- a/src/test/java/seedu/command/AddCommandTest.java +++ b/src/test/java/seedu/command/AddCommandTest.java @@ -86,7 +86,7 @@ void checkAttributes_allAttributesSet_true() { addCommand = new AddCommand(userInput); boolean actualResult = addCommand.checkAttributes(); - assertEquals(true, actualResult); + assertTrue(actualResult); } @Test @@ -96,6 +96,6 @@ void checkAttributes_oneOrMoreNulls_false() { )); boolean actualResult = addCommand.checkAttributes(); - assertEquals(false, actualResult); + assertFalse(actualResult); } } \ No newline at end of file From 7e8fced8483b8947b5539fbd4816e8b0c7a3f583 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 22 Mar 2022 14:39:55 +0800 Subject: [PATCH 066/229] Shift tests for prepareModification to ModificationCommandTest from UpdateCommandTest --- .../seedu/command/ModificationCommand.java | 8 ++- .../command/ModificationCommandTest.java | 46 ++++++++++++++ .../java/seedu/command/UpdateCommandTest.java | 60 +++++++++---------- 3 files changed, 82 insertions(+), 32 deletions(-) create mode 100644 src/test/java/seedu/command/ModificationCommandTest.java diff --git a/src/main/java/seedu/command/ModificationCommand.java b/src/main/java/seedu/command/ModificationCommand.java index 2d0360c0fc..b8d6f944a5 100644 --- a/src/main/java/seedu/command/ModificationCommand.java +++ b/src/main/java/seedu/command/ModificationCommand.java @@ -5,7 +5,9 @@ /** * Abstract class acting as parent class to AddCommand and UpdateCommand which have use for the same prepareModification method. */ -public abstract class ModificationCommand extends Command { +public class ModificationCommand extends Command { + public final String IMPLEMENTED_BY_CHILD = "Execute method for Modification should be implemented by " + + "child classes AddCommand and UpdateCommand"; protected final ArrayList commandStrings; protected String serialNumber; protected String equipmentName = null; @@ -18,7 +20,9 @@ public ModificationCommand(ArrayList commandStrings) { this.commandStrings = commandStrings; } - public abstract CommandResult execute(); + public CommandResult execute() { + return new CommandResult(IMPLEMENTED_BY_CHILD); + } public void setSerialNumber(String serialNumber) { this.serialNumber = serialNumber; diff --git a/src/test/java/seedu/command/ModificationCommandTest.java b/src/test/java/seedu/command/ModificationCommandTest.java new file mode 100644 index 0000000000..71d08c46ff --- /dev/null +++ b/src/test/java/seedu/command/ModificationCommandTest.java @@ -0,0 +1,46 @@ +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.*; + +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") + )); + ModificationCommand actualCommand = new ModificationCommand(testArrayList); + 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 index 39e0a913a8..f1bd5ace53 100644 --- a/src/test/java/seedu/command/UpdateCommandTest.java +++ b/src/test/java/seedu/command/UpdateCommandTest.java @@ -66,34 +66,34 @@ void generateUpdatePairs_nonNullUpdates_success() { assertEquals(expectedResult, actualResult); } - @Test - void prepareModification_missingSlashDelimiter_assertionErrorThrown() throws AssertionError { - ArrayList testArrayList = new ArrayList<>(Collections.singleton("thiswillnotwork")); - try { - updateCommand = new UpdateCommand(testArrayList); - } 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 = 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")); - UpdateCommand expectedCommand = new UpdateCommand(new ArrayList<>( - Arrays.asList("s/S1404115ASF", "n/Speaker A") - )); - UpdateCommand actualCommand = new UpdateCommand(testArrayList); - actualCommand.prepareModification(); - assertEquals(expectedCommand, actualCommand); - } +// @Test +// void prepareModification_missingSlashDelimiter_assertionErrorThrown() throws AssertionError { +// ArrayList testArrayList = new ArrayList<>(Collections.singleton("thiswillnotwork")); +// try { +// updateCommand = new UpdateCommand(testArrayList); +// } 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 = 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")); +// UpdateCommand expectedCommand = new UpdateCommand(new ArrayList<>( +// Arrays.asList("s/S1404115ASF", "n/Speaker A") +// )); +// UpdateCommand actualCommand = new UpdateCommand(testArrayList); +// actualCommand.prepareModification(); +// assertEquals(expectedCommand, actualCommand); +// } } \ No newline at end of file From 01975b88ecd6d90033d8e5217223db68705d7ec0 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 22 Mar 2022 15:30:31 +0800 Subject: [PATCH 067/229] Update all classes for Java CI checks --- src/main/java/seedu/command/AddCommand.java | 8 ++++---- src/main/java/seedu/command/CheckCommand.java | 2 +- src/main/java/seedu/command/Command.java | 6 ++++-- src/main/java/seedu/command/HelpCommand.java | 2 +- .../seedu/command/ModificationCommand.java | 11 +++++----- .../java/seedu/command/UpdateCommand.java | 14 ++++++------- src/main/java/seedu/duke/Duke.java | 2 +- src/main/java/seedu/equipment/Equipment.java | 12 +++++------ .../seedu/equipment/EquipmentManager.java | 2 +- .../parser/IncompleteCommandException.java | 1 - src/main/java/seedu/parser/Parser.java | 12 ++++++++--- src/main/java/seedu/storage/Storage.java | 9 +++++---- src/main/java/seedu/ui/TextUi.java | 20 ++++++++++--------- .../seedu/equipment/EquipmentManagerTest.java | 4 ++-- 14 files changed, 58 insertions(+), 47 deletions(-) diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index 93de22a8c3..a9150f71b2 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -18,8 +18,8 @@ public class AddCommand extends ModificationCommand { + "Example: " + "add n/SpeakerB s/S1404115ASF t/Speaker c/1000 pf/Loud_Technologies pd/2022-02-23"; public static final String DUPLICATE_ITEM_ERROR = "There is already an item with this serial number: %1$s"; - public static final String ATTRIBUTE_NOT_SET_ERROR = "Unable to add. " + - "One or more than one of the attributes of Equipment is not specified."; + public static final String ATTRIBUTE_NOT_SET_ERROR = "Unable to add. " + + "One or more than one of the attributes of Equipment is not specified."; /** * constructor for AddCommand. Initialises successMessage and usageReminder from Command @@ -75,8 +75,8 @@ public void addEquipment(ArrayList userInput) throws DuplicateSerialNumb * @return boolean to indicate whether all attributes are set. */ public boolean checkAttributes() { - if (equipmentName == null || serialNumber == null || type == null || cost == null || - purchasedFrom == null || purchasedDate == null) { + if (equipmentName == null || serialNumber == null || type == null || cost == null + || purchasedFrom == null || purchasedDate == null) { return false; } return true; diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index 7faec9b436..88502f8963 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -28,7 +28,7 @@ public CheckCommand(ArrayList commandStrings) { } /** - * Gives details of equipment specified by name + * Gives details of equipment specified by name. * * @return CommandResult with message from execution of this command */ diff --git a/src/main/java/seedu/command/Command.java b/src/main/java/seedu/command/Command.java index 1728b67fa8..e7dfd0b9d7 100644 --- a/src/main/java/seedu/command/Command.java +++ b/src/main/java/seedu/command/Command.java @@ -11,9 +11,11 @@ public abstract class Command { protected String successMessage; public String usageReminder; protected EquipmentManager equipmentManager; - protected static final String INCORRECT_ENUM_TYPE = "Wrong type of equipment. The allowed types are: MICROPHONE, SPEAKER, STAND, CABLE"; + protected static final String INCORRECT_ENUM_TYPE = "Wrong type of equipment. The allowed types are: " + + "MICROPHONE, SPEAKER, STAND, CABLE"; protected static final String INCORRECT_COST_FORMAT = "Please enter numbers only for cost and omit symbols"; - protected static final String INVALID_SERIAL_NUMBER = "No such serial number, please enter an existing serial number"; + protected static final String INVALID_SERIAL_NUMBER = "No such serial number, please enter an existing " + + "serial number"; protected static final String MISSING_SERIAL_NUMBER = "Serial Number is required to run this command"; public abstract CommandResult execute(); diff --git a/src/main/java/seedu/command/HelpCommand.java b/src/main/java/seedu/command/HelpCommand.java index ccd32d2268..5b6702ead4 100644 --- a/src/main/java/seedu/command/HelpCommand.java +++ b/src/main/java/seedu/command/HelpCommand.java @@ -3,7 +3,7 @@ /** * Subclass of Command. Shows information of the available commands to users. */ -public class HelpCommand extends Command{ +public class HelpCommand extends Command { public static final String COMMAND_WORD = "help"; public static final String COMMAND_DESCRIPTION = ": Shows details of available commands to users. " + System.lineSeparator() diff --git a/src/main/java/seedu/command/ModificationCommand.java b/src/main/java/seedu/command/ModificationCommand.java index b8d6f944a5..87c9e7e62b 100644 --- a/src/main/java/seedu/command/ModificationCommand.java +++ b/src/main/java/seedu/command/ModificationCommand.java @@ -3,11 +3,12 @@ import java.util.ArrayList; /** - * Abstract class acting as parent class to AddCommand and UpdateCommand which have use for the same prepareModification method. + * Abstract class acting as parent class to AddCommand and UpdateCommand which have use for the + * same prepareModification method. */ public class ModificationCommand extends Command { - public final String IMPLEMENTED_BY_CHILD = "Execute method for Modification should be implemented by " + - "child classes AddCommand and UpdateCommand"; + public static final String IMPLEMENTED_BY_CHILD = "Execute method for Modification should be implemented by " + + "child classes AddCommand and UpdateCommand"; protected final ArrayList commandStrings; protected String serialNumber; protected String equipmentName = null; @@ -50,8 +51,8 @@ public void setCost(String cost) { /** * Set up ModificationCommand with arguments required to update a given item - *

- * Should multiple arguments specifying the same argument parameter (e.g. 'c/1000' and 'c/2000') be given, + * + *

Should multiple arguments specifying the same argument parameter (e.g. 'c/1000' and 'c/2000') be given, * the previous arguments passed in will be overwritten by the most recent parameter ('c/2000' in example). */ protected void prepareModification() throws AssertionError { diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java index 4149980504..29ed8fb72f 100644 --- a/src/main/java/seedu/command/UpdateCommand.java +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -43,7 +43,7 @@ public CommandResult execute() { } ArrayList> updatePairs = generateUpdatePairs(); - if(!equipmentManager.updateEquipment(serialNumber, updatePairs)){ + if (!equipmentManager.updateEquipment(serialNumber, updatePairs)) { return new CommandResult(UPDATE_FAILURE_MESSAGE); } @@ -105,12 +105,12 @@ public boolean equals(Object o) { return false; } UpdateCommand that = (UpdateCommand) o; - return serialNumber.equals(that.serialNumber) && - Objects.equals(equipmentName, that.equipmentName) && - Objects.equals(purchasedDate, that.purchasedDate) && - Objects.equals(type, that.type) && - Objects.equals(purchasedFrom, that.purchasedFrom) && - Objects.equals(cost, that.cost); + return serialNumber.equals(that.serialNumber) + && Objects.equals(equipmentName, that.equipmentName) + && Objects.equals(purchasedDate, that.purchasedDate) + && Objects.equals(type, that.type) + && Objects.equals(purchasedFrom, that.purchasedFrom) + && Objects.equals(cost, that.cost); } @Override diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java index b404350c12..2d3631555d 100644 --- a/src/main/java/seedu/duke/Duke.java +++ b/src/main/java/seedu/duke/Duke.java @@ -28,7 +28,7 @@ public static void main(String[] args) { } /** - * Initialises the required objects and loads up the data from storage and show welcome message to user + * Initialises the required objects and loads up the data from storage and show welcome message to user. */ private void start() { ui = new TextUi(); diff --git a/src/main/java/seedu/equipment/Equipment.java b/src/main/java/seedu/equipment/Equipment.java index 7c08234862..1a7b1eeb85 100644 --- a/src/main/java/seedu/equipment/Equipment.java +++ b/src/main/java/seedu/equipment/Equipment.java @@ -92,11 +92,11 @@ public int hashCode() { @Override public String toString() { - return "serialNumber=" + serialNumber + "," + - "itemName=" + itemName + "," + - "type=" + type + "," + - "cost=" + cost + "," + - "purchasedFrom=" + purchasedFrom + "," + - "purchasedDate=" + purchasedDate; + return "serialNumber=" + serialNumber + "," + + "itemName=" + itemName + "," + + "type=" + type + "," + + "cost=" + cost + "," + + "purchasedFrom=" + purchasedFrom + "," + + "purchasedDate=" + purchasedDate; } } diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index 8c78be86d6..926ce18654 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -60,7 +60,7 @@ public HashMap getEquipmentList() { } public boolean updateEquipment(String serialNumber, ArrayList> updatePairs) { - if (!equipmentList.containsKey(serialNumber)){ + if (!equipmentList.containsKey(serialNumber)) { return false; } Equipment updatedEquipment = equipmentList.get(serialNumber); diff --git a/src/main/java/seedu/parser/IncompleteCommandException.java b/src/main/java/seedu/parser/IncompleteCommandException.java index 70043c5bf8..f875bba38b 100644 --- a/src/main/java/seedu/parser/IncompleteCommandException.java +++ b/src/main/java/seedu/parser/IncompleteCommandException.java @@ -1,5 +1,4 @@ package seedu.parser; - /** * Signal that given data does not include necessary arguments. * Adapted from: https://github.com/se-edu/addressbook-level2/blob/master/src/seedu/addressbook/data/exception/ diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index cc407f7851..88a3dce7dc 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -2,7 +2,14 @@ import java.util.ArrayList; -import seedu.command.*; +import seedu.command.AddCommand; +import seedu.command.UpdateCommand; +import seedu.command.ListCommand; +import seedu.command.IncorrectCommand; +import seedu.command.CheckCommand; +import seedu.command.DeleteCommand; +import seedu.command.HelpCommand; +import seedu.command.Command; import java.util.Collections; import java.util.regex.Matcher; @@ -135,8 +142,7 @@ public ArrayList splitCommandTerm(String userInput) throws IncompleteCom /** * Prepare arguments for AddCommand by splitting up the arguments into different parts. - *

- * Index: + *

* Index: * 0. equipmentName : String of equipment name * 1. serialNumber : String of unique serial number * 2. type : String representation of enumerated class diff --git a/src/main/java/seedu/storage/Storage.java b/src/main/java/seedu/storage/Storage.java index 64e1b015f7..a74d8afdcf 100644 --- a/src/main/java/seedu/storage/Storage.java +++ b/src/main/java/seedu/storage/Storage.java @@ -15,10 +15,11 @@ public class Storage { - public final String FILE_NOT_FOUND_ERROR_MESSAGE = "File not found! A new file will be created after this session."; - public final String SAVE_ERROR_MESSAGE = "An error occurred while saving!"; - public final String DUPLICATE_SERIAL_NUMBER_ERROR = "Duplicate serial number found!"; - public final String path = "./equipments.json"; + public static final String FILE_NOT_FOUND_ERROR_MESSAGE = "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 final Gson gson = new Gson(); public void loadData(EquipmentManager equipmentManager) { diff --git a/src/main/java/seedu/ui/TextUi.java b/src/main/java/seedu/ui/TextUi.java index 7753c32962..d1be7d30a4 100644 --- a/src/main/java/seedu/ui/TextUi.java +++ b/src/main/java/seedu/ui/TextUi.java @@ -1,6 +1,5 @@ package seedu.ui; -import seedu.command.Command; import seedu.command.CommandResult; import seedu.equipment.Equipment; @@ -9,14 +8,17 @@ * https://github.com/se-edu/addressbook-level2/blob/master/src/seedu/addressbook/ui/TextUi.java */ public class TextUi { - private final static String LOGO = " _ _ \n" + - " (_) | | \n" + - " ___ __ _ _ _ _ _ __ _ __ ___ ___ _ __ | |_ _ __ ___ __ _ _ __ __ _ __ _ ___ _ __ \n" + - " / _ \\/ _` | | | | | '_ \\| '_ ` _ \\ / _ \\ '_ \\| __| '_ ` _ \\ / _` | '_ \\ / _` |/ _` |/ _ \\ '__|\n" + - " | __/ (_| | |_| | | |_) | | | | | | __/ | | | |_| | | | | | (_| | | | | (_| | (_| | __/ | \n" + - " \\___|\\__, |\\__,_|_| .__/|_| |_| |_|\\___|_| |_|\\__|_| |_| |_|\\__,_|_| |_|\\__,_|\\__, |\\___|_| \n" + - " | | | | __/ | \n" + - " |_| |_| |___/"; + private final static String LOGO = " _ _" + + " \n" + + " (_) | | \n" + + " ___ __ _ _ _ _ _ __ _ __ ___ ___ _ __ | |_ _ __ ___ __ _ _ __ __ _ __ _ ___ _ __ \n" + + " / _ \\/ _` | | | | | '_ \\| '_ ` _ \\ / _ \\ '_ \\| __| '_ ` _ \\ / _` " + + "| '_ \\ / _` |/ _` |/ _ \\ '__|\n" + + " | __/ (_| | |_| | | |_) | | | | | | __/ | | | |_| | | | | | (_| | | | | (_| | (_| | __/ | \n" + + " \\___|\\__, |\\__,_|_| .__/|_| |_| |_|\\___|_| " + + "|_|\\__|_| |_| |_|\\__,_|_| |_|\\__,_|\\__, |\\___|_| \n" + + " | | | | __/ | \n" + + " |_| |_| |___/"; public void showWelcomeMessage() { System.out.println("Hello from" + System.lineSeparator() + LOGO); diff --git a/src/test/java/seedu/equipment/EquipmentManagerTest.java b/src/test/java/seedu/equipment/EquipmentManagerTest.java index ea2fe94f5c..854da94d59 100644 --- a/src/test/java/seedu/equipment/EquipmentManagerTest.java +++ b/src/test/java/seedu/equipment/EquipmentManagerTest.java @@ -10,7 +10,7 @@ public class EquipmentManagerTest { @Test - public void updateEquipment_success() throws DuplicateSerialNumber { + public void updateEquipment_success() throws DuplicateSerialNumberException { EquipmentManager equipmentManager = new EquipmentManager(); equipmentManager.addEquipment("Speaker B", "S1404115ASF", EquipmentType.valueOf("SPEAKER"), 1000, "Loud Technologies", "2022-02-23"); ArrayList> updates = new ArrayList<>(); @@ -38,7 +38,7 @@ public void updateEquipment_keyNotFound() { } @Test - public void updateEquipment_invalidEquipmentType() throws DuplicateSerialNumber { + public void updateEquipment_invalidEquipmentType() throws DuplicateSerialNumberException { EquipmentManager equipmentManager = new EquipmentManager(); equipmentManager.addEquipment("Speaker B", "S1404115ASF", EquipmentType.valueOf("SPEAKER"), 1000, "Loud Technologies", "2022-02-23"); ArrayList> updates = new ArrayList<>(); From 1bbef72fbd3bc9848b047cd6bb69b9d5ac3ffe7b Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 22 Mar 2022 15:34:47 +0800 Subject: [PATCH 068/229] Fix remaining pending Java CI errors --- .../java/seedu/parser/IncompleteCommandException.java | 8 +------- src/main/java/seedu/parser/Parser.java | 1 + src/main/java/seedu/ui/TextUi.java | 2 +- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/main/java/seedu/parser/IncompleteCommandException.java b/src/main/java/seedu/parser/IncompleteCommandException.java index f875bba38b..fea4ab9732 100644 --- a/src/main/java/seedu/parser/IncompleteCommandException.java +++ b/src/main/java/seedu/parser/IncompleteCommandException.java @@ -1,12 +1,6 @@ package seedu.parser; -/** - * Signal that given data does not include necessary arguments. - * Adapted from: https://github.com/se-edu/addressbook-level2/blob/master/src/seedu/addressbook/data/exception/ - */ + public class IncompleteCommandException extends Exception { - /** - * @param message contains information on failed constraints - */ public IncompleteCommandException(String message) { super(message); } diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 88a3dce7dc..cc30742d68 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -142,6 +142,7 @@ public ArrayList splitCommandTerm(String userInput) throws IncompleteCom /** * Prepare arguments for AddCommand by splitting up the arguments into different parts. + * *

* Index: * 0. equipmentName : String of equipment name * 1. serialNumber : String of unique serial number diff --git a/src/main/java/seedu/ui/TextUi.java b/src/main/java/seedu/ui/TextUi.java index d1be7d30a4..e2503a4dd5 100644 --- a/src/main/java/seedu/ui/TextUi.java +++ b/src/main/java/seedu/ui/TextUi.java @@ -8,7 +8,7 @@ * https://github.com/se-edu/addressbook-level2/blob/master/src/seedu/addressbook/ui/TextUi.java */ public class TextUi { - private final static String LOGO = " _ _" + private static final String LOGO = " _ _" + " \n" + " (_) | | \n" + " ___ __ _ _ _ _ _ __ _ __ ___ ___ _ __ | |_ _ __ ___ __ _ _ __ __ _ __ _ ___ _ __ \n" From 1b93be4e7aaf2a710c01ba58f72f872a2ae113a1 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 22 Mar 2022 16:28:20 +0800 Subject: [PATCH 069/229] Fix Java CI errors from test files --- src/main/java/seedu/command/AddCommand.java | 2 +- .../seedu/command/ModificationCommand.java | 23 ++++++++++++ .../java/seedu/command/UpdateCommand.java | 7 ---- .../java/seedu/command/AddCommandTest.java | 33 +++++++++++++---- .../java/seedu/command/CheckCommandTest.java | 3 +- .../java/seedu/command/DeleteCommandTest.java | 6 ++-- .../java/seedu/command/ListCommandTest.java | 10 ++++-- .../command/ModificationCommandTest.java | 5 +-- .../java/seedu/command/UpdateCommandTest.java | 36 ++----------------- .../seedu/equipment/EquipmentManagerTest.java | 26 +++++++++++--- src/test/java/seedu/parser/ParserTest.java | 10 ++++-- 11 files changed, 97 insertions(+), 64 deletions(-) diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index a9150f71b2..c9b030a57e 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -47,7 +47,7 @@ public CommandResult execute() { try { addEquipment(commandStrings); } catch (DuplicateSerialNumberException e) { - return new CommandResult(String.format(DUPLICATE_ITEM_ERROR, commandStrings.get(1))); + return new CommandResult(String.format(DUPLICATE_ITEM_ERROR, serialNumber)); } catch (NullPointerException | NumberFormatException e) { return new CommandResult(INCORRECT_COST_FORMAT); } catch (IllegalArgumentException e) { diff --git a/src/main/java/seedu/command/ModificationCommand.java b/src/main/java/seedu/command/ModificationCommand.java index 87c9e7e62b..79b1e37dd7 100644 --- a/src/main/java/seedu/command/ModificationCommand.java +++ b/src/main/java/seedu/command/ModificationCommand.java @@ -1,6 +1,7 @@ package seedu.command; import java.util.ArrayList; +import java.util.Objects; /** * Abstract class acting as parent class to AddCommand and UpdateCommand which have use for the @@ -19,6 +20,7 @@ public class ModificationCommand extends Command { public ModificationCommand(ArrayList commandStrings) { this.commandStrings = commandStrings; + prepareModification(); } public CommandResult execute() { @@ -86,6 +88,27 @@ protected void prepareModification() throws AssertionError { System.out.println("`" + argValue + "` not accepted for type " + argType + ": Unrecognised Tag"); } } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ModificationCommand that = (ModificationCommand) o; + return serialNumber.equals(that.serialNumber) + && Objects.equals(equipmentName, that.equipmentName) + && Objects.equals(purchasedDate, that.purchasedDate) + && Objects.equals(type, that.type) + && Objects.equals(purchasedFrom, that.purchasedFrom) + && Objects.equals(cost, that.cost); + } + @Override + public int hashCode() { + return Objects.hash(serialNumber, equipmentName, purchasedDate, type, purchasedFrom, cost); } } diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java index 29ed8fb72f..6aa2227116 100644 --- a/src/main/java/seedu/command/UpdateCommand.java +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -14,13 +14,6 @@ public class UpdateCommand extends ModificationCommand { + System.lineSeparator() + "Example: " + "update s/SM57-1 n/SpeakerC c/2510 pd/2022-08-21"; - private String serialNumber; - - private String updateName = null; - private String purchaseDate = null; - private String type = null; - private String purchaseFrom = null; - private String cost = null; /** diff --git a/src/test/java/seedu/command/AddCommandTest.java b/src/test/java/seedu/command/AddCommandTest.java index 14d14cea82..2f05a6bf81 100644 --- a/src/test/java/seedu/command/AddCommandTest.java +++ b/src/test/java/seedu/command/AddCommandTest.java @@ -12,12 +12,21 @@ import java.util.ArrayList; import java.util.Arrays; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; + 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") + Arrays.asList( + "n/Speaker B", + "s/S1404115ASF", + "t/SPEAKER", + "c/1000", + "pf/Loud Technologies", + "pd/2022-02-23") ); @Test @@ -32,7 +41,8 @@ void execute_duplicateSerialNumber_exceptionThrown() throws DuplicateSerialNumbe "Loud Technologies", "2022-02-23"); - CommandResult expectedResult = new CommandResult("There is already an item with this serial number: S1404115ASF"); + CommandResult expectedResult = + new CommandResult("There is already an item with this serial number: S1404115ASF"); CommandResult actualResult = addCommand.execute(); assertEquals(expectedResult, actualResult); } @@ -40,7 +50,12 @@ void execute_duplicateSerialNumber_exceptionThrown() throws DuplicateSerialNumbe @Test void execute_incorrectCostFormat_exceptionThrown() { addCommand = new AddCommand(new ArrayList<>( - Arrays.asList("n/Speaker B", "s/S1404115ASF", "t/SPEAKER", "c/$1000", "pf/Loud Technologies", "pd/2022-02-23") + Arrays.asList("n/Speaker B", + "s/S1404115ASF", + "t/SPEAKER", + "c/$1000", + "pf/Loud Technologies", + "pd/2022-02-23") )); CommandResult expectedResult = new CommandResult("Please enter numbers only for cost and omit symbols"); @@ -51,12 +66,18 @@ void execute_incorrectCostFormat_exceptionThrown() { @Test void execute_incorrectEnumType_exceptionThrown() { addCommand = new AddCommand(new ArrayList<>( - Arrays.asList("n/Speaker B", "s/S1404115ASF", "t/SPEAKERS", "c/1000", "pf/Loud Technologies", "pd/2022-02-23") + Arrays.asList("n/Speaker B", + "s/S1404115ASF", + "t/SPEAKERS", + "c/1000", + "pf/Loud Technologies", + "pd/2022-02-23") )); addCommand.setEquipmentManager(new EquipmentManager()); EquipmentManager equipmentManager = addCommand.equipmentManager; - CommandResult expectedResult = new CommandResult("Wrong type of equipment. The allowed types are: MICROPHONE, SPEAKER, STAND, CABLE"); + CommandResult expectedResult = new CommandResult("Wrong type of equipment. " + + "The allowed types are: MICROPHONE, SPEAKER, STAND, CABLE"); CommandResult actualResult = addCommand.execute(); assertEquals(expectedResult, actualResult); } diff --git a/src/test/java/seedu/command/CheckCommandTest.java b/src/test/java/seedu/command/CheckCommandTest.java index 9e57d67384..9949639fab 100644 --- a/src/test/java/seedu/command/CheckCommandTest.java +++ b/src/test/java/seedu/command/CheckCommandTest.java @@ -9,7 +9,8 @@ import java.util.ArrayList; import java.util.Arrays; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; class CheckCommandTest { CheckCommand checkCommand; diff --git a/src/test/java/seedu/command/DeleteCommandTest.java b/src/test/java/seedu/command/DeleteCommandTest.java index 7d1c0e3d93..e8034eae8e 100644 --- a/src/test/java/seedu/command/DeleteCommandTest.java +++ b/src/test/java/seedu/command/DeleteCommandTest.java @@ -8,7 +8,8 @@ import java.util.ArrayList; import java.util.Arrays; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; class DeleteCommandTest { DeleteCommand deleteCommand; @@ -35,7 +36,8 @@ void execute_validSerialNumber_success() { assertEquals(1, equipmentListSize); CommandResult actualResult = deleteCommand.execute(); - CommandResult expectedResult = new CommandResult("Equipment successfully deleted: Speaker B, serial number S1404115ASF"); + CommandResult expectedResult = + new CommandResult("Equipment successfully deleted: Speaker B, serial number S1404115ASF"); assertEquals(expectedResult, actualResult); } diff --git a/src/test/java/seedu/command/ListCommandTest.java b/src/test/java/seedu/command/ListCommandTest.java index 8d84ea2178..9825931a32 100644 --- a/src/test/java/seedu/command/ListCommandTest.java +++ b/src/test/java/seedu/command/ListCommandTest.java @@ -8,7 +8,8 @@ import java.util.ArrayList; import java.util.Arrays; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; class ListCommandTest { ListCommand listCommand; @@ -32,7 +33,9 @@ void execute_specifiedType_success() { } CommandResult actualResult = listCommand.execute(); - CommandResult expectedResult = new CommandResult("TOTAL QUANTITY OF SPEAKER: 1" + System.lineSeparator(), equipmentManager.listEquipment(EquipmentType.valueOf("SPEAKER"))); + CommandResult expectedResult = new CommandResult( + "TOTAL QUANTITY OF SPEAKER: 1" + System.lineSeparator(), + equipmentManager.listEquipment(EquipmentType.valueOf("SPEAKER"))); assertEquals(expectedResult, actualResult); } @@ -54,7 +57,8 @@ void execute_noSpecifiedType_success() { } CommandResult actualResult = listCommand.execute(); - CommandResult expectedResult = new CommandResult("TOTAL QUANTITY OF EQUIPMENT: 1" + System.lineSeparator(), equipmentManager.listEquipment()); + CommandResult expectedResult = new CommandResult("TOTAL QUANTITY OF EQUIPMENT: 1" + System.lineSeparator(), + equipmentManager.listEquipment()); assertEquals(expectedResult, actualResult); } diff --git a/src/test/java/seedu/command/ModificationCommandTest.java b/src/test/java/seedu/command/ModificationCommandTest.java index 71d08c46ff..49a89ea025 100644 --- a/src/test/java/seedu/command/ModificationCommandTest.java +++ b/src/test/java/seedu/command/ModificationCommandTest.java @@ -7,7 +7,7 @@ import java.util.Arrays; import java.util.Collections; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; class ModificationCommandTest { ModificationCommand modificationCommand; @@ -19,7 +19,8 @@ void prepareModification_missingSlashDelimiter_assertionErrorThrown() throws Ass 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()); + assertEquals("Each args will need to include minimally a '/' to split arg and value upon", + error.getMessage()); } } diff --git a/src/test/java/seedu/command/UpdateCommandTest.java b/src/test/java/seedu/command/UpdateCommandTest.java index 84025db727..255b8ce558 100644 --- a/src/test/java/seedu/command/UpdateCommandTest.java +++ b/src/test/java/seedu/command/UpdateCommandTest.java @@ -6,13 +6,12 @@ import seedu.equipment.DuplicateSerialNumberException; import seedu.equipment.EquipmentManager; import seedu.equipment.EquipmentType; -import seedu.parser.IncompleteCommandException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; class UpdateCommandTest { EquipmentManager equipmentManager = new EquipmentManager(); @@ -65,35 +64,4 @@ void generateUpdatePairs_nonNullUpdates_success() { assertEquals(expectedResult, actualResult); } - -// @Test -// void prepareModification_missingSlashDelimiter_assertionErrorThrown() throws AssertionError { -// ArrayList testArrayList = new ArrayList<>(Collections.singleton("thiswillnotwork")); -// try { -// updateCommand = new UpdateCommand(testArrayList); -// } 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 = 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")); -// UpdateCommand expectedCommand = new UpdateCommand(new ArrayList<>( -// Arrays.asList("s/S1404115ASF", "n/Speaker A") -// )); -// UpdateCommand actualCommand = new UpdateCommand(testArrayList); -// actualCommand.prepareModification(); -// assertEquals(expectedCommand, actualCommand); -// } } \ No newline at end of file diff --git a/src/test/java/seedu/equipment/EquipmentManagerTest.java b/src/test/java/seedu/equipment/EquipmentManagerTest.java index 854da94d59..4211f88e86 100644 --- a/src/test/java/seedu/equipment/EquipmentManagerTest.java +++ b/src/test/java/seedu/equipment/EquipmentManagerTest.java @@ -6,13 +6,19 @@ import java.util.ArrayList; import java.util.HashMap; -import static org.junit.jupiter.api.Assertions.*; +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", "2022-02-23"); + equipmentManager.addEquipment("Speaker B", + "S1404115ASF", + EquipmentType.valueOf("SPEAKER"), + 1000, + "Loud Technologies", + "2022-02-23"); ArrayList> updates = new ArrayList<>(); updates.add(new Pair<>("itemName", "Speaker A")); updates.add(new Pair<>("type", "STAND")); @@ -21,26 +27,36 @@ public void updateEquipment_success() throws DuplicateSerialNumberException { updates.add(new Pair<>("purchaseFrom", "Louder Technologies")); equipmentManager.updateEquipment("S1404115ASF", updates); HashMap equipments = equipmentManager.getEquipmentList(); - Equipment expectedEquipment = new Equipment("Speaker A", "S1404115ASF", EquipmentType.valueOf("STAND"), 2000, "Louder Technologies", "2022-03-17"); + Equipment expectedEquipment = new Equipment("Speaker A", + "S1404115ASF", + EquipmentType.valueOf("STAND"), + 2000, + "Louder Technologies", + "2022-03-17"); assertEquals(expectedEquipment, equipments.get("S1404115ASF")); } @Test public void updateEquipment_keyNotFound() { - EquipmentManager equipmentManager = new EquipmentManager(); 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", "2022-03-17")); updates.add(new Pair<>("purchaseFrom", "Louder Technologies")); + EquipmentManager equipmentManager = new EquipmentManager(); assertFalse(equipmentManager.updateEquipment("WRONG SERIAL NUMBER", updates)); } @Test public void updateEquipment_invalidEquipmentType() throws DuplicateSerialNumberException { EquipmentManager equipmentManager = new EquipmentManager(); - equipmentManager.addEquipment("Speaker B", "S1404115ASF", EquipmentType.valueOf("SPEAKER"), 1000, "Loud Technologies", "2022-02-23"); + equipmentManager.addEquipment("Speaker B", + "S1404115ASF", + EquipmentType.valueOf("SPEAKER"), + 1000, + "Loud Technologies", + "2022-02-23"); ArrayList> updates = new ArrayList<>(); updates.add(new Pair<>("itemName", "Speaker A")); updates.add(new Pair<>("type", "INVALID EQUIPMENT TYPE")); diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index e66e263fd4..8ff7b00f5d 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -11,7 +11,9 @@ import java.util.Collections; import java.util.concurrent.atomic.AtomicReferenceArray; -import static org.junit.jupiter.api.Assertions.*; +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 { @@ -202,7 +204,8 @@ void extractArguments_noSpaceBeforeTypeSlashDelimiterFound_exceptionThrown() { ArrayList expectedResult = new ArrayList<>(Arrays.asList( "x/Speaker B", "t/Speaker", "c/1000", "pf/Loud Technologies", "pd/2022-02-23")); try { - ArrayList actualResult = parser.extractArguments("x/Speaker Bt/Speakerc/1000pf/Loud Technologiespd/2022-02-23"); + ArrayList actualResult = parser.extractArguments( + "x/Speaker Bt/Speakerc/1000pf/Loud Technologiespd/2022-02-23"); assertEquals(expectedResult, actualResult); fail(); } catch (IncompleteCommandException e) { @@ -212,7 +215,8 @@ void extractArguments_noSpaceBeforeTypeSlashDelimiterFound_exceptionThrown() { @Test void extractArguments_wrongArgTypesUsed_exceptionThrown() throws IncompleteCommandException { - Throwable exception = assertThrows(IncompleteCommandException.class, () -> parser.extractArguments("x/Speaker B a/Speaker b/1000 d/Loud Technologies e/2022-02-23")); + Throwable exception = assertThrows(IncompleteCommandException.class, () -> parser.extractArguments( + "x/Speaker B a/Speaker b/1000 d/Loud Technologies e/2022-02-23")); assertEquals("No parameters found!", exception.getMessage()); } From 061cdd91aaa7418007958257816df4aea3e0c00c Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 22 Mar 2022 16:38:36 +0800 Subject: [PATCH 070/229] Add support for parsing command word regardless of case Additionally, improved documentation for splitCommandTerm --- src/main/java/seedu/parser/Parser.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index cc30742d68..f88df7f5d1 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -12,6 +12,7 @@ import seedu.command.Command; import java.util.Collections; +import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -120,22 +121,26 @@ public Command parseCommand(String userInput) { public ArrayList splitCommandTerm(String userInput) throws IncompleteCommandException { ArrayList resultArrayList = new ArrayList<>(); userInput = userInput.trim(); - if (userInput.equals(ListCommand.COMMAND_WORD)) { - resultArrayList.add("list"); + // Checks for "list" command word first + if (userInput.toLowerCase(Locale.ROOT).equals(ListCommand.COMMAND_WORD)) { + resultArrayList.add(ListCommand.COMMAND_WORD); resultArrayList.add(null); return resultArrayList; } - if (userInput.equals(HelpCommand.COMMAND_WORD)) { - resultArrayList.add("help"); + // Checks for "help" command word next + if (userInput.toLowerCase(Locale.ROOT).equals(HelpCommand.COMMAND_WORD)) { + resultArrayList.add(HelpCommand.COMMAND_WORD); resultArrayList.add(null); return resultArrayList; } + // Match terms against syntax final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput); - // guard against no match + // Guard against no match if (!matcher.matches()) { throw new IncompleteCommandException("Could not find space delimiter between command and arguments!"); } - resultArrayList.add(matcher.group("commandWord")); + // Match and return ArrayList appropriately + resultArrayList.add(matcher.group("commandWord").toLowerCase(Locale.ROOT)); resultArrayList.add(matcher.group("arguments")); return resultArrayList; } From 43fd0ef9ef769d01aa199809a49afcc586d1a869 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 22 Mar 2022 16:39:55 +0800 Subject: [PATCH 071/229] Switch prepareAdd to extractArguments for Parser @yuhaochua, please check if this is the expected behaviour from your end! --- src/main/java/seedu/parser/Parser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index f88df7f5d1..208bae4bfb 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -67,7 +67,7 @@ public Command parseCommand(String userInput) { switch (commandAndArgument.get(0)) { case AddCommand.COMMAND_WORD: try { - args = prepareAdd(commandAndArgument.get(1)); + args = extractArguments(commandAndArgument.get(1)); return new AddCommand(args); } catch (IncompleteCommandException e) { return new IncorrectCommand(AddCommand.COMMAND_WORD + AddCommand.COMMAND_DESCRIPTION); From 8c8d59f4df22b4afe4f9e62cd8bfe235ff94a1ef Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 22 Mar 2022 16:42:09 +0800 Subject: [PATCH 072/229] Add helper method to set argument tags to lowercase Work in progress --- src/main/java/seedu/parser/Parser.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 208bae4bfb..3cfe5c4b41 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -237,5 +237,9 @@ private static boolean hasSlashDelimiter(String argument) { return argument.contains("/"); } + private static String setArgumentTagsToLower(String argument) { + int slashIndex = argument.indexOf("/"); + return argument.substring(0, slashIndex).toUpperCase(Locale.ROOT) + argument.substring(slashIndex); + } } From c575044ca37962504dc36b2801429a7bea1f0352 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 22 Mar 2022 16:53:46 +0800 Subject: [PATCH 073/229] Reformat Regex for improved readability --- src/main/java/seedu/parser/Parser.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 3cfe5c4b41..3cc6cff704 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -39,11 +39,18 @@ public class Parser { public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("s/(?.+)"); // ARGUMENT_FORMAT extracts first n-1 tags public static final Pattern ARGUMENT_FORMAT = Pattern.compile( - "((?:s|n|t|c|pf|pd)\\/[\\w\\s\\-]+?)\\s+(?=s|n|t|c|pf|pd)" + "((?:s|n|t|c|pf|pd)" // argument tag + + "\\/" // argument delimiter + + "[\\w\\s\\-]+?)" // actual argument value + + "\\s+" // argument space before next delimiter + + "(?=s|n|t|c|pf|pd)" // next delimiter ); // ARGUMENT_TRAILING_FORMAT extracts last tag public static final Pattern ARGUMENT_TRAILING_FORMAT = Pattern.compile( - "(? Date: Tue, 22 Mar 2022 17:19:07 +0800 Subject: [PATCH 074/229] Remove I/O redirection checks from github gradle build --- .github/workflows/gradle.yml | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index fd8c44d086..6e9958b427 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -32,19 +32,4 @@ jobs: - name: Build and check with Gradle run: ./gradlew check - - - name: Perform IO redirection test (*NIX) - if: runner.os == 'Linux' - working-directory: ${{ github.workspace }}/text-ui-test - run: ./runtest.sh - - - name: Perform IO redirection test (MacOS) - if: always() && runner.os == 'macOS' - working-directory: ${{ github.workspace }}/text-ui-test - run: ./runtest.sh - - - name: Perform IO redirection test (Windows) - if: always() && runner.os == 'Windows' - working-directory: ${{ github.workspace }}/text-ui-test - shell: cmd - run: runtest.bat \ No newline at end of file + \ No newline at end of file From cc12f641554a570468c2fda956424d43af31d293 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 22 Mar 2022 17:40:03 +0800 Subject: [PATCH 075/229] Include regex101.com debug link for easy maintainence --- src/main/java/seedu/parser/Parser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 3cc6cff704..8ed0defdaa 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -37,7 +37,7 @@ public class Parser { ); public static final Pattern VIEW_COMMAND_FORMAT = Pattern.compile("n/(?.+)"); public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("s/(?.+)"); - // ARGUMENT_FORMAT extracts first n-1 tags + // ARGUMENT_FORMAT extracts first n-1 tags, for debugging: https://regex101.com/r/gwjHWD/1 public static final Pattern ARGUMENT_FORMAT = Pattern.compile( "((?:s|n|t|c|pf|pd)" // argument tag + "\\/" // argument delimiter From 106e543cce20f817eef4382f80e7d66f402fb722 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 22 Mar 2022 18:38:03 +0800 Subject: [PATCH 076/229] Replace magic constants in Parser's prepareView and prepareDelete with named elements --- src/main/java/seedu/parser/Parser.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 8ed0defdaa..aa29d8b73a 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -197,7 +197,7 @@ protected ArrayList prepareView(String args) throws IncompleteCommandExc if (!matcher.matches()) { throw new IncompleteCommandException("View command values are incomplete or missing!"); } - return new ArrayList<>(Collections.singleton(matcher.group(1))); + return new ArrayList<>(Collections.singleton(matcher.group("itemName"))); } /** @@ -212,7 +212,7 @@ protected ArrayList prepareDelete(String args) throws IncompleteCommandE if (!matcher.matches()) { throw new IncompleteCommandException("Delete command values are incomplete or missing!"); } - return new ArrayList<>(Collections.singleton(matcher.group(1))); + return new ArrayList<>(Collections.singleton(matcher.group("serialNumber"))); } /** From be99f2a1b1deef5a428e2aec4d6c7c8070d62a02 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 22 Mar 2022 18:39:16 +0800 Subject: [PATCH 077/229] Deprecate prepareAdd entirely Rationale: extractArguments can handle all instances of prepareAdd --- src/main/java/seedu/parser/Parser.java | 58 ++++++++++++++-------- src/test/java/seedu/parser/ParserTest.java | 44 ++++++++++++++-- 2 files changed, 76 insertions(+), 26 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index aa29d8b73a..2f97858542 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -27,6 +27,7 @@ public class Parser { * passed into arguments. */ public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s+(?.+)"); + @Deprecated public static final Pattern ADD_COMMAND_FORMAT = Pattern.compile( "n\\/(?.+)" + "\\s+" + "s\\/(?.+)" + "\\s+" @@ -35,20 +36,20 @@ public class Parser { + "pf\\/(?.+)" + "\\s+" + "pd\\/(?.+)" ); - public static final Pattern VIEW_COMMAND_FORMAT = Pattern.compile("n/(?.+)"); - public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("s/(?.+)"); - // ARGUMENT_FORMAT extracts first n-1 tags, for debugging: https://regex101.com/r/gwjHWD/1 - public static final Pattern ARGUMENT_FORMAT = Pattern.compile( - "((?:s|n|t|c|pf|pd)" // argument tag + public static final Pattern VIEW_COMMAND_FORMAT = Pattern.compile("[Nn]/(?.+)"); + public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("[Ss]/(?.+)"); + // ARGUMENT_FORMAT extracts first n-1 tags, for debugging: https://regex101.com/r/gwjHWD/3 + public static final Pattern MODIFICATION_ARGUMENT_FORMAT = Pattern.compile( + "((?:[sntcSNTC]|[pP][fF]|[pP][dD])" // argument tag + "\\/" // argument delimiter - + "[\\w\\s\\-]+?)" // actual argument value + + "[\\w\\s\\-]+)" // actual argument value + "\\s+" // argument space before next delimiter - + "(?=s|n|t|c|pf|pd)" // next delimiter + + "(?=[sntcSNTC]|[pP][fF]|[pP][dD])" // next delimiter ); // ARGUMENT_TRAILING_FORMAT extracts last tag - public static final Pattern ARGUMENT_TRAILING_FORMAT = Pattern.compile( + public static final Pattern MODIFICATION_ARGUMENT_TRAILING_FORMAT = Pattern.compile( "(? splitCommandTerm(String userInput) throws IncompleteCom /** * Prepare arguments for AddCommand by splitting up the arguments into different parts. * - *

* Index: - * 0. equipmentName : String of equipment name - * 1. serialNumber : String of unique serial number - * 2. type : String representation of enumerated class - * 3. cost : String representation of double value, "$" optional but "," delimiter forbidden - * 4. purchasedFrom : String of vendor name, suggest adhering to one consistent naming scheme - * 5. purchasedDate : String representation for now, possibility for future support + *

Index: * + *

0. equipmentName : String of equipment name + * + *

1. serialNumber : String of unique serial number + * + *

2. type : String representation of enumerated class + * + *

3. cost : String representation of double value, "$" optional but "," delimiter forbidden + * + *

4. purchasedFrom : String of vendor name, suggest adhering to one consistent naming scheme + * + *

5. purchasedDate : String representation for now, possibility for future support + * + * @deprecated Use extractArguments as it is more robust in conjunction with subclasses of ModificationCommand * @param args String to be split into substrings * @return ArrayList of arguments * @throws IncompleteCommandException if no match found + * */ + @Deprecated protected ArrayList prepareAdd(String args) throws IncompleteCommandException { final Matcher matcher = ADD_COMMAND_FORMAT.matcher(args.trim()); // validate arg string format @@ -224,16 +234,22 @@ protected ArrayList prepareDelete(String args) throws IncompleteCommandE */ protected ArrayList extractArguments(String args) throws IncompleteCommandException { int lastIndex = 0; + String argumentToAdd; + String argument; ArrayList splitArguments = new ArrayList<>(); try { - Matcher matcher = ARGUMENT_FORMAT.matcher(args.trim()); + Matcher matcher = MODIFICATION_ARGUMENT_FORMAT.matcher(args.trim()); while (matcher.find()) { - splitArguments.add(matcher.group().trim()); + argument = matcher.group(); + argumentToAdd = setArgumentTagsToLower(argument.trim()); + splitArguments.add(argumentToAdd); lastIndex = matcher.end(); } - matcher.usePattern(ARGUMENT_TRAILING_FORMAT); + matcher.usePattern(MODIFICATION_ARGUMENT_TRAILING_FORMAT); matcher.find(lastIndex); - splitArguments.add(matcher.group().trim()); + argument = matcher.group(); + argumentToAdd = setArgumentTagsToLower(argument.trim()); + splitArguments.add(argumentToAdd); } catch (IllegalStateException e) { throw new IncompleteCommandException("No parameters found!"); } @@ -246,7 +262,7 @@ private static boolean hasSlashDelimiter(String argument) { private static String setArgumentTagsToLower(String argument) { int slashIndex = argument.indexOf("/"); - return argument.substring(0, slashIndex).toUpperCase(Locale.ROOT) + argument.substring(slashIndex); + return argument.substring(0, slashIndex).toLowerCase(Locale.ROOT) + argument.substring(slashIndex); } } diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 8ff7b00f5d..1af8d282b0 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -1,15 +1,11 @@ package seedu.parser; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import seedu.command.IncorrectCommand; -import seedu.command.UpdateCommand; -import java.sql.Array; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; -import java.util.concurrent.atomic.AtomicReferenceArray; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -51,6 +47,8 @@ void splitCommandTerm_noSpaceDelimiter_exceptionThrown() { } } + @Deprecated + @Disabled("extractArgument is a better replacement for prepareAdd") @Test void prepareAdd_addStringWithSpaces_success() throws IncompleteCommandException { ArrayList expectedResult = new ArrayList<>( @@ -61,6 +59,8 @@ void prepareAdd_addStringWithSpaces_success() throws IncompleteCommandException assertEquals(expectedResult, actualResult); } + @Deprecated + @Disabled("extractArgument is a better replacement for prepareAdd") @Test void prepareAdd_insufficientArguments_exceptionThrown() { ArrayList unexpectedResult = new ArrayList<>( @@ -76,6 +76,8 @@ void prepareAdd_insufficientArguments_exceptionThrown() { } } + @Deprecated + @Disabled("extractArgument is a better replacement for prepareAdd") @Test void prepareAdd_argumentEnteredTwice_exceptionThrown() { ArrayList unexpectedResult = new ArrayList<>( @@ -91,6 +93,8 @@ void prepareAdd_argumentEnteredTwice_exceptionThrown() { } } + @Deprecated + @Disabled("extractArgument is a better replacement for prepareAdd") @Test void prepareAdd_argumentIncludesSlashA_exceptionThrown() { ArrayList unexpectedResult = new ArrayList<>( @@ -106,6 +110,8 @@ void prepareAdd_argumentIncludesSlashA_exceptionThrown() { } } + @Deprecated + @Disabled("extractArgument is a better replacement for prepareAdd") @Test void prepareAdd_argumentIncludesSlashB_exceptionThrown() { ArrayList unexpectedResult = new ArrayList<>( @@ -199,6 +205,34 @@ void extractArguments_validCommands_success() throws IncompleteCommandException } } + @Test + void extractArguments_mixedCaseText_success() throws IncompleteCommandException { + ArrayList testStrings = new ArrayList<>(Arrays.asList( + "S/S1404115ASF n/Speaker B t/Speaker c/1000 Pf/Loud Technologies PD/2022-02-23", + "s/S1404115ASF C/1000", + "s/S1404115ASF N/Speaker B ", + "s/S1404115ASF pf/Loud Technologies n/Speaker B", + "t/Speaker S/S1404115ASF", + "c/1000 pF/Loud Technologies s/S1404115ASF" + )); + ArrayList> expectedResults = new ArrayList<>(); + expectedResults.add(new ArrayList<>(Arrays.asList( + "s/S1404115ASF", "n/Speaker B", "t/Speaker", "c/1000", "pf/Loud Technologies", "pd/2022-02-23"))); + expectedResults.add(new ArrayList<>(Arrays.asList( + "s/S1404115ASF", "c/1000"))); + expectedResults.add(new ArrayList<>(Arrays.asList( + "s/S1404115ASF", "n/Speaker B"))); + expectedResults.add(new ArrayList<>(Arrays.asList( + "s/S1404115ASF", "pf/Loud Technologies", "n/Speaker B"))); + expectedResults.add(new ArrayList<>(Arrays.asList( + "t/Speaker", "s/S1404115ASF"))); + expectedResults.add(new ArrayList<>(Arrays.asList( + "c/1000", "pf/Loud Technologies", "s/S1404115ASF"))); + for (int i = 0; i < expectedResults.size(); i++) { + assertEquals(expectedResults.get(i), parser.extractArguments(testStrings.get(i))); + } + } + @Test void extractArguments_noSpaceBeforeTypeSlashDelimiterFound_exceptionThrown() { ArrayList expectedResult = new ArrayList<>(Arrays.asList( From c7fce04061646ab2bfe53f2ea4fb8bb3559c2769 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 22 Mar 2022 21:56:23 +0800 Subject: [PATCH 078/229] Return type enumeration in all caps resolves #62 --- src/main/java/seedu/parser/Parser.java | 15 +++++++++++++-- src/test/java/seedu/parser/ParserTest.java | 21 +++++++++++++++------ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 2f97858542..355ab86fd6 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -38,6 +38,7 @@ public class Parser { ); public static final Pattern VIEW_COMMAND_FORMAT = Pattern.compile("[Nn]/(?.+)"); public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("[Ss]/(?.+)"); + public static final Pattern TYPE_ENUM_FORMAT = Pattern.compile("[Tt]/(?\\w+)"); // ARGUMENT_FORMAT extracts first n-1 tags, for debugging: https://regex101.com/r/gwjHWD/3 public static final Pattern MODIFICATION_ARGUMENT_FORMAT = Pattern.compile( "((?:[sntcSNTC]|[pP][fF]|[pP][dD])" // argument tag @@ -170,11 +171,10 @@ public ArrayList splitCommandTerm(String userInput) throws IncompleteCom * *

5. purchasedDate : String representation for now, possibility for future support * - * @deprecated Use extractArguments as it is more robust in conjunction with subclasses of ModificationCommand * @param args String to be split into substrings * @return ArrayList of arguments * @throws IncompleteCommandException if no match found - * + * @deprecated Use extractArguments as it is more robust in conjunction with subclasses of ModificationCommand */ @Deprecated protected ArrayList prepareAdd(String args) throws IncompleteCommandException { @@ -253,6 +253,17 @@ protected ArrayList extractArguments(String args) throws IncompleteComma } catch (IllegalStateException e) { throw new IncompleteCommandException("No parameters found!"); } + + for (int i = splitArguments.size() - 1; i >= 0; i--) { + String argumentPair = splitArguments.get(i); + Matcher matcher = TYPE_ENUM_FORMAT.matcher(argumentPair); + if (matcher.matches()) { + splitArguments.remove(argumentPair); + splitArguments.add("t/" + matcher.group("equipmentType").toUpperCase(Locale.ROOT)); + return splitArguments; + } + } + return splitArguments; } diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 1af8d282b0..0ce7129f20 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -189,7 +190,7 @@ void extractArguments_validCommands_success() throws IncompleteCommandException )); ArrayList> expectedResults = new ArrayList<>(); expectedResults.add(new ArrayList<>(Arrays.asList( - "s/S1404115ASF", "n/Speaker B", "t/Speaker", "c/1000", "pf/Loud Technologies", "pd/2022-02-23"))); + "s/S1404115ASF", "n/Speaker B", "t/SPEAKER", "c/1000", "pf/Loud Technologies", "pd/2022-02-23"))); expectedResults.add(new ArrayList<>(Arrays.asList( "s/S1404115ASF", "c/1000"))); expectedResults.add(new ArrayList<>(Arrays.asList( @@ -197,11 +198,15 @@ void extractArguments_validCommands_success() throws IncompleteCommandException expectedResults.add(new ArrayList<>(Arrays.asList( "s/S1404115ASF", "pf/Loud Technologies", "n/Speaker B"))); expectedResults.add(new ArrayList<>(Arrays.asList( - "t/Speaker", "s/S1404115ASF"))); + "t/SPEAKER", "s/S1404115ASF"))); expectedResults.add(new ArrayList<>(Arrays.asList( "c/1000", "pf/Loud Technologies", "s/S1404115ASF"))); for (int i = 0; i < expectedResults.size(); i++) { - assertEquals(expectedResults.get(i), parser.extractArguments(testStrings.get(i))); + ArrayList testResultsSorted = parser.extractArguments(testStrings.get(i)); + ArrayList expectedResultsSorted = expectedResults.get(i); + testResultsSorted.sort(Comparator.comparing(String::toString)); + expectedResultsSorted.sort(Comparator.comparing(String::toString)); + assertEquals(expectedResultsSorted, testResultsSorted); } } @@ -217,7 +222,7 @@ void extractArguments_mixedCaseText_success() throws IncompleteCommandException )); ArrayList> expectedResults = new ArrayList<>(); expectedResults.add(new ArrayList<>(Arrays.asList( - "s/S1404115ASF", "n/Speaker B", "t/Speaker", "c/1000", "pf/Loud Technologies", "pd/2022-02-23"))); + "s/S1404115ASF", "n/Speaker B", "t/SPEAKER", "c/1000", "pf/Loud Technologies", "pd/2022-02-23"))); expectedResults.add(new ArrayList<>(Arrays.asList( "s/S1404115ASF", "c/1000"))); expectedResults.add(new ArrayList<>(Arrays.asList( @@ -225,11 +230,15 @@ void extractArguments_mixedCaseText_success() throws IncompleteCommandException expectedResults.add(new ArrayList<>(Arrays.asList( "s/S1404115ASF", "pf/Loud Technologies", "n/Speaker B"))); expectedResults.add(new ArrayList<>(Arrays.asList( - "t/Speaker", "s/S1404115ASF"))); + "t/SPEAKER", "s/S1404115ASF"))); expectedResults.add(new ArrayList<>(Arrays.asList( "c/1000", "pf/Loud Technologies", "s/S1404115ASF"))); for (int i = 0; i < expectedResults.size(); i++) { - assertEquals(expectedResults.get(i), parser.extractArguments(testStrings.get(i))); + ArrayList testResultsSorted = parser.extractArguments(testStrings.get(i)); + ArrayList expectedResultsSorted = expectedResults.get(i); + testResultsSorted.sort(Comparator.comparing(String::toString)); + expectedResultsSorted.sort(Comparator.comparing(String::toString)); + assertEquals(expectedResultsSorted, testResultsSorted); } } From 81f1b319340185c4459afbe740f7681d5c6e90c9 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 22 Mar 2022 23:33:05 +0800 Subject: [PATCH 079/229] Attempt to change String in value of Pair to generic wildcard class --- src/main/java/seedu/Pair.java | 1 + src/main/java/seedu/command/UpdateCommand.java | 6 +++--- .../java/seedu/equipment/EquipmentManager.java | 14 +++++++------- src/test/java/seedu/command/UpdateCommandTest.java | 2 +- .../java/seedu/equipment/EquipmentManagerTest.java | 6 +++--- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/main/java/seedu/Pair.java b/src/main/java/seedu/Pair.java index 477cbd70f4..223f6ecf93 100644 --- a/src/main/java/seedu/Pair.java +++ b/src/main/java/seedu/Pair.java @@ -1,5 +1,6 @@ package seedu; +import java.util.AbstractMap; import java.util.Objects; /** diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java index 6aa2227116..e27232d847 100644 --- a/src/main/java/seedu/command/UpdateCommand.java +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -35,7 +35,7 @@ public CommandResult execute() { return new CommandResult(MISSING_SERIAL_NUMBER); } - ArrayList> updatePairs = generateUpdatePairs(); + ArrayList> updatePairs = generateUpdatePairs(); if (!equipmentManager.updateEquipment(serialNumber, updatePairs)) { return new CommandResult(UPDATE_FAILURE_MESSAGE); } @@ -47,8 +47,8 @@ public String getSerialNumber() { return serialNumber; } - public ArrayList> generateUpdatePairs() { - ArrayList> pairs = new ArrayList<>(); + public ArrayList> generateUpdatePairs() { + ArrayList> pairs = new ArrayList<>(); if (equipmentName != null) { pairs.add(new Pair<>("itemName", equipmentName)); } diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index 926ce18654..271bf869a8 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -59,32 +59,32 @@ public HashMap getEquipmentList() { return equipmentList; } - public boolean updateEquipment(String serialNumber, ArrayList> updatePairs) { + public boolean updateEquipment(String serialNumber, ArrayList> updatePairs) { if (!equipmentList.containsKey(serialNumber)) { return false; } Equipment updatedEquipment = equipmentList.get(serialNumber); - for (Pair updates : updatePairs) { + for (Pair updates : updatePairs) { String key = updates.getKey(); switch (key) { case "itemName": - updatedEquipment.setItemName(updates.getValue()); + updatedEquipment.setItemName((String) updates.getValue()); break; case "type": try { - updatedEquipment.setType(EquipmentType.valueOf(updates.getValue())); + updatedEquipment.setType(EquipmentType.valueOf((String)updates.getValue())); } catch (IllegalArgumentException e) { return false; } break; case "cost": - updatedEquipment.setCost(Double.parseDouble(updates.getValue())); + updatedEquipment.setCost(Double.valueOf((String) updates.getValue())); break; case "purchaseDate": - updatedEquipment.setPurchasedDate(updates.getValue()); + updatedEquipment.setPurchasedDate((String) updates.getValue()); break; case "purchaseFrom": - updatedEquipment.setPurchasedFrom(updates.getValue()); + updatedEquipment.setPurchasedFrom((String) updates.getValue()); break; default: break; diff --git a/src/test/java/seedu/command/UpdateCommandTest.java b/src/test/java/seedu/command/UpdateCommandTest.java index 255b8ce558..78ba5a22c0 100644 --- a/src/test/java/seedu/command/UpdateCommandTest.java +++ b/src/test/java/seedu/command/UpdateCommandTest.java @@ -60,7 +60,7 @@ void generateUpdatePairs_nonNullUpdates_success() { expectedResult.add(new Pair<>("cost", "2000")); expectedResult.add(new Pair<>("purchasedDate", "2022-01-26")); - ArrayList> actualResult = updateCommand.generateUpdatePairs(); + ArrayList> actualResult = updateCommand.generateUpdatePairs(); assertEquals(expectedResult, actualResult); } diff --git a/src/test/java/seedu/equipment/EquipmentManagerTest.java b/src/test/java/seedu/equipment/EquipmentManagerTest.java index 4211f88e86..81ef0400ca 100644 --- a/src/test/java/seedu/equipment/EquipmentManagerTest.java +++ b/src/test/java/seedu/equipment/EquipmentManagerTest.java @@ -19,7 +19,7 @@ public void updateEquipment_success() throws DuplicateSerialNumberException { 1000, "Loud Technologies", "2022-02-23"); - ArrayList> updates = new ArrayList<>(); + ArrayList> updates = new ArrayList<>(); updates.add(new Pair<>("itemName", "Speaker A")); updates.add(new Pair<>("type", "STAND")); updates.add(new Pair<>("cost", "2000")); @@ -38,7 +38,7 @@ public void updateEquipment_success() throws DuplicateSerialNumberException { @Test public void updateEquipment_keyNotFound() { - ArrayList> updates = new ArrayList<>(); + ArrayList> updates = new ArrayList<>(); updates.add(new Pair<>("itemName", "Speaker A")); updates.add(new Pair<>("type", "STAND")); updates.add(new Pair<>("cost", "2000")); @@ -57,7 +57,7 @@ public void updateEquipment_invalidEquipmentType() throws DuplicateSerialNumberE 1000, "Loud Technologies", "2022-02-23"); - ArrayList> updates = new ArrayList<>(); + ArrayList> updates = new ArrayList<>(); updates.add(new Pair<>("itemName", "Speaker A")); updates.add(new Pair<>("type", "INVALID EQUIPMENT TYPE")); updates.add(new Pair<>("cost", "2000")); From a6f9cfb691290f1f09f43ddb974590bdc12e3643 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Wed, 23 Mar 2022 02:51:49 +0800 Subject: [PATCH 080/229] Add documentation for architecture, parser and acknowledgements --- docs/DeveloperGuide.md | 66 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 64e1f0ed2b..ff61514dd4 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -1,14 +1,70 @@ -# Developer Guide - +--- +layout: page +title: Developer Guide +--- +* Table of Contents + {:toc} + +-------------------------------------------------------------------------------------------------------------------- ## Acknowledgements {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well} -## Design & implementation +Our project could not have been possible without the prior work of the following: + +- [SE-EDU project team](https://se-education.org/docs/team.html) for their work on [AddressBook Level 3](https://github.com/se-edu/addressbook-level3), for which we referenced ideas as well as code snippets. +- Google's [GSON Java library](https://github.com/google/gson) for which we used to load and save our data files. +- Members of the [AY2122S2-CS2113-F10-2 team](https://github.com/nus-cs2113-AY2122S2) for pointing out the possibility of and requesting permission to make use of the above GSON library. + +-------------------------------------------------------------------------------------------------------------------- +## Design & Implementation {Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.} +### Architecture + +Our design draws significant inspiration from the implementation of AddressBook Level 3 (henceforth AddressBook). +As the program was initially conceptualised to be a text-based command-line interface, heavy consideration was given +to the design and user interactions when it came to the text input to be parsed by the user. +As such, we referenced AddressBook to segment the program into **`Parser`**, **`Command`** and **`Equipment`** classes. + +**Main components of the architecture** + +- **`Duke`** is the Main class and entry-point for the program. +- **`Parser`** serves as the first filter to split raw text input and pass in arguments to the **`Command`** for further processing. +- **`Command`**, together with its various subclasses serve as specific implementations to pass the arguments taken in to the various methods of the **`EquipmentManager`** class. +- **`EquipmentManager`** keeps track of actual **`Equipment`** instances created by our program. +- **`Storage`** performs File I/O functions. + +### Parser + +**`Parser`** is the first filter for text inputs read to the user. +As alluded to prior, one major consideration was to build it in a manner that can parse text input as effectively as possible. In considering text input, we divided the parsing into the following segments: + +#### `commandWord` `argumentTag/argumentValue` `argumentTag/argumentValue` `...` + +To dispatch `argumentTag/argumentValue` strings to the correct **`Command`** class, the following logic is employed throughout **`Parser`** by **`parseCommand`**. + +**1. Parse the correct Command Word** + +**`splitCommandTerm`** splits the input string upon the first space. +The first substring is used to decide which **`Command`** to dispatch while the second is used for its arguments. +In the case where a second substring is not required, as in the case of **`help`** and **`list`**, a null String is used. + +**2. Split Arguments** + +For simpler command words such as **`delete`** and **`check`**, only one pair of **`argumentType`** and **`argumentValue`** were required. +As such, these will be passed in directly to their **`Command`** classes without a **`argumentType`** pair. + +More complex command words such as **`add`** and **`update`** necessitated multiple arguments. +To implement this while ensuring that multi-word strings are acceptable input, **`extractArguments`** was implemented. +Without specifically explaining the main regular expression ([details here](https://regex101.com/r/gwjHWD/3)), the approach sought to match **`argumentTag/argumentValue`** pairs with a positive lookahead. +The final argument pair will then be extracted using a separate regex. +Together, this ensured that all argument pairs can be effectively parsed and dispatched to each **`Command`** class. + +Throughout the `Parser` implementation, exceptions were used to return `IncorrectCommand` classes that can be used to pass error messages to the user. These will be discussed in the following segments. +-------------------------------------------------------------------------------------------------------------------- ## Product scope ### Target user profile @@ -18,6 +74,7 @@ {Describe the value proposition: what problem does it solve?} +-------------------------------------------------------------------------------------------------------------------- ## User Stories |Version| As a ... | I want to ... | So that I can ...| @@ -25,14 +82,17 @@ |v1.0|new user|see usage instructions|refer to them when I forget how to use the application| |v2.0|user|find a to-do item by name|locate a to-do without having to go through the entire list| +-------------------------------------------------------------------------------------------------------------------- ## Non-Functional Requirements {Give non-functional requirements} +-------------------------------------------------------------------------------------------------------------------- ## Glossary * *glossary item* - Definition +-------------------------------------------------------------------------------------------------------------------- ## Instructions for manual testing {Give instructions on how to do a manual product testing e.g., how to load sample data to be used for testing} From b3ec295191cb36444a34fb5b617b7f75aef3c2a9 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Thu, 24 Mar 2022 00:33:41 +0800 Subject: [PATCH 081/229] Fix bug where app ccrashes Fixes #65 --- src/main/java/seedu/command/ListCommand.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/command/ListCommand.java b/src/main/java/seedu/command/ListCommand.java index 92fd040213..5501475acc 100644 --- a/src/main/java/seedu/command/ListCommand.java +++ b/src/main/java/seedu/command/ListCommand.java @@ -57,7 +57,13 @@ public CommandResult execute() { return new CommandResult(String.format(successMessage, listSize), equipmentArrayList); } - EquipmentType typeToList = EquipmentType.valueOf(commandStrings.get(0)); + EquipmentType typeToList; + try { + typeToList = EquipmentType.valueOf(commandStrings.get(0)); + } catch (IllegalArgumentException e) { + return new CommandResult(INCORRECT_ENUM_TYPE); + } + equipmentArrayList = equipmentManager.listEquipment(typeToList); listSize = equipmentArrayList.size(); return new CommandResult(String.format(successMessage, typeToList, listSize), equipmentArrayList); From 103d600a23a9cb228ca5ae30e96b257bfbf88ff7 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Thu, 24 Mar 2022 00:35:32 +0800 Subject: [PATCH 082/229] Minor edit to make output shown to user more presentable when using AddCommand --- src/main/java/seedu/command/AddCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index c9b030a57e..35cefd5481 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -54,7 +54,7 @@ public CommandResult execute() { return new CommandResult(INCORRECT_ENUM_TYPE); } - return new CommandResult(String.format(successMessage, commandStrings.get(0), commandStrings.get(1))); + return new CommandResult(String.format(successMessage, equipmentName, serialNumber)); } /** From 49b427c554b382575c012119da33d0779d883949 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 24 Mar 2022 00:49:17 +0800 Subject: [PATCH 083/229] Add support for lowercase argument for list command Test case written as well with ListCommand equals implementation --- src/main/java/seedu/command/ListCommand.java | 24 ++++++++++++++++++++ src/main/java/seedu/parser/Parser.java | 3 ++- src/test/java/seedu/parser/ParserTest.java | 13 +++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/command/ListCommand.java b/src/main/java/seedu/command/ListCommand.java index 92fd040213..4e8e850624 100644 --- a/src/main/java/seedu/command/ListCommand.java +++ b/src/main/java/seedu/command/ListCommand.java @@ -4,6 +4,7 @@ import seedu.equipment.EquipmentType; import java.util.ArrayList; +import java.util.Objects; /** * Subclass of Command. Handles listing of all equipment or listing of equipment of specified type. @@ -62,4 +63,27 @@ public CommandResult execute() { listSize = equipmentArrayList.size(); return new CommandResult(String.format(successMessage, typeToList, listSize), equipmentArrayList); } + + /** + * Implement equals for JUnit comparisons + * Source: https://www.geeksforgeeks.org/overriding-equals-method-in-java/ + * @param o Any object + * @return If two commands are the same + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ListCommand that = (ListCommand) o; + return Objects.equals(commandStrings, that.commandStrings); + } + + @Override + public int hashCode() { + return Objects.hash(commandStrings); + } } diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 355ab86fd6..8bbcdf1e56 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -106,7 +106,8 @@ public Command parseCommand(String userInput) { if (commandAndArgument.get(1) == null) { return new ListCommand(); } else { - return new ListCommand(new ArrayList<>(Collections.singleton(commandAndArgument.get(1)))); + args = new ArrayList<>(Collections.singleton(commandAndArgument.get(1).toUpperCase(Locale.ROOT))); + return new ListCommand(args); } case HelpCommand.COMMAND_WORD: return new HelpCommand(); diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 0ce7129f20..5980e2e71b 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -3,9 +3,12 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import seedu.command.Command; +import seedu.command.ListCommand; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Comparator; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -263,4 +266,14 @@ void extractArguments_wrongArgTypesUsed_exceptionThrown() throws IncompleteComma assertEquals("No parameters found!", exception.getMessage()); } + @Test + void parseCommand_listEnumTypeConvertedToUpper_success() throws IncompleteCommandException { + Command testCommand = parser.parseCommand("list spEAker"); + Command expectedCommand = new ListCommand(new ArrayList<>(Collections.singleton("SPEAKER"))); + assertEquals(expectedCommand, testCommand); + } + + + + } \ No newline at end of file From 40aedfbd86c51655f813d2eb32077f9684674dcc Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Thu, 24 Mar 2022 20:39:48 +0800 Subject: [PATCH 084/229] Add JavaDocs to methods in UpdateCommand. --- src/main/java/seedu/command/UpdateCommand.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java index 6aa2227116..9a2571ec05 100644 --- a/src/main/java/seedu/command/UpdateCommand.java +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -29,6 +29,12 @@ public UpdateCommand(ArrayList commandStrings) { prepareModification(); } + /** + * Updates the equipment of specified serial number with the given update values. + * @return different CommandResult is returned depending on situation. The different CommandResult + * represent the situations where serial number is not specified, update of equipment failed + * or update is successful. + */ @Override public CommandResult execute() { if (getSerialNumber() == null) { @@ -47,6 +53,12 @@ public String getSerialNumber() { return serialNumber; } + /** + * Generates an ArrayList of Pair. + * Pair is a class that was implemented to match each attribute to its value. + * By using pair, we are able to update only the values that have been specified to be updated. + * @return ArrayList of the Pair of update values and their matching attributes. + */ public ArrayList> generateUpdatePairs() { ArrayList> pairs = new ArrayList<>(); if (equipmentName != null) { @@ -68,6 +80,10 @@ public ArrayList> generateUpdatePairs() { return pairs; } + /** + * Generates the String which specifies which attributes have been updated. + * @return String containing update details. + */ public String generateUpdateString() { String updateDetails = ""; if (equipmentName != null) { From 74fbb68efbaf796c44822d2d7264faab433db538 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Thu, 24 Mar 2022 20:40:19 +0800 Subject: [PATCH 085/229] Update Developer Guide and add images used. --- docs/DeveloperGuide.md | 35 ++++++++++++++++++++++++++++++-- docs/images/equipment0.png | Bin 0 -> 10177 bytes docs/images/equipment1.png | Bin 0 -> 9583 bytes docs/images/sequenceDiagram.png | Bin 0 -> 54923 bytes 4 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 docs/images/equipment0.png create mode 100644 docs/images/equipment1.png create mode 100644 docs/images/sequenceDiagram.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index ff61514dd4..64dd75608d 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -17,9 +17,40 @@ Our project could not have been possible without the prior work of the following - Members of the [AY2122S2-CS2113-F10-2 team](https://github.com/nus-cs2113-AY2122S2) for pointing out the possibility of and requesting permission to make use of the above GSON library. -------------------------------------------------------------------------------------------------------------------- -## Design & Implementation +## **Design and Implementation** -{Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.} +This section describes some noteworthy details on how certain features are designed and implemented. + +### Update feature + +#### Current Design and Implementation + +The update feature is facilitated by `UpdateCommand`. It extends `ModificationCommand` and implements the following operations: + +* `UpdateCommand#generateUpdatePairs()` — Generates pairs of attributes and their update values. +* `VersionedAddressBook#generateUpdateString()` — Generates sString with details of the update executed. + +Given below is an example usage scenario and how the update feature behaves at each step. + +Step 1. The user adds an equipment to the system with the help of the `add` command. The added equipment has the following attributes shown below. + +![equipment0](images/equipment0.png) + +Step 2. The user executes `update s/S1404115ASF n/SpeakerC c/2000 pd/2022-01-29` to update equipment with serial number S1404115ASF. `Parser#parseCommand` is called from `Duke` to parse the user's input. + +Step 3. The parser recognises that an `UpdateCommand` is required, and the UpdateCommand is prepared to return to `Duke`. In the constructor of `UpdateCommand`, `prepareModification` is called to set the values of the attributes to be updated. The other attributes are set to null by default. + +Step 4. `UpdateCommand#execute` is run to process the update. If the serialNumber attribute is null, a `CommandResult` with a `MISSING_SERIAL_NUMBER` output string will be returned. Otherwise, `EquipmentManager#updateEquipment` is called. + +Step 5. If the update was successful, a `CommandResult` with success message will be returned, else a `CommandResult` with `UPDATE_FAILURE_MESSAGE` will be returned. Upon successful update, the object should be updated with the new attributes as shown in the diagram below. + +![equipment1](images/equipment1.png) + +The *Sequence Diagram* below shows how the objects/classes interact with each other in the case of an update command being issued by the user. + +![sequenceDiagram](images/sequenceDiagram.png) + +Step 6. It is not shown in the sequence diagram but ultimately when the CommandResult is returned to `Duke`, the output of the `CommandResult` gets printed out and displayed to the user. ### Architecture diff --git a/docs/images/equipment0.png b/docs/images/equipment0.png new file mode 100644 index 0000000000000000000000000000000000000000..b0b783ebb463f2f06a2c09b736e0522be363a569 GIT binary patch literal 10177 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 Bt4#m^ literal 0 HcmV?d00001 diff --git a/docs/images/equipment1.png b/docs/images/equipment1.png new file mode 100644 index 0000000000000000000000000000000000000000..594549fc241c1eb4292db563d60e184713647ba4 GIT binary patch literal 9583 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 ?!@<7L;ijp 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 Date: Thu, 24 Mar 2022 20:51:42 +0800 Subject: [PATCH 086/229] Add UML diagram visual paradigm file --- docs/diagrams/.EquipmentManager.vpp.lck | 0 docs/diagrams/EquipmentManager.vpp | Bin 0 -> 720896 bytes docs/diagrams/EquipmentManager.vpp.bak_000f | Bin 0 -> 720896 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/diagrams/.EquipmentManager.vpp.lck create mode 100644 docs/diagrams/EquipmentManager.vpp create mode 100644 docs/diagrams/EquipmentManager.vpp.bak_000f diff --git a/docs/diagrams/.EquipmentManager.vpp.lck b/docs/diagrams/.EquipmentManager.vpp.lck new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/diagrams/EquipmentManager.vpp b/docs/diagrams/EquipmentManager.vpp new file mode 100644 index 0000000000000000000000000000000000000000..9c3c239b251492ac80a93c39fecda7e8bb2ca52f GIT binary patch literal 720896 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 z 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�N^R}`{cbgoKa3m{>MQRw%K+J~8X02X(R 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

27cLGFCG^zja--yT&E_ieo$B-an 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 z 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�N^R}`{cbgoKa3m{>MQRw%K+J~8X02X(R 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

27cLGFCG^zja--yT&E_ieo$B-an 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 Date: Thu, 24 Mar 2022 21:06:44 +0800 Subject: [PATCH 087/229] Reorder sequence in design and implementation --- docs/DeveloperGuide.md | 62 +++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 64dd75608d..0f7964bb4f 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -21,37 +21,6 @@ Our project could not have been possible without the prior work of the following This section describes some noteworthy details on how certain features are designed and implemented. -### Update feature - -#### Current Design and Implementation - -The update feature is facilitated by `UpdateCommand`. It extends `ModificationCommand` and implements the following operations: - -* `UpdateCommand#generateUpdatePairs()` — Generates pairs of attributes and their update values. -* `VersionedAddressBook#generateUpdateString()` — Generates sString with details of the update executed. - -Given below is an example usage scenario and how the update feature behaves at each step. - -Step 1. The user adds an equipment to the system with the help of the `add` command. The added equipment has the following attributes shown below. - -![equipment0](images/equipment0.png) - -Step 2. The user executes `update s/S1404115ASF n/SpeakerC c/2000 pd/2022-01-29` to update equipment with serial number S1404115ASF. `Parser#parseCommand` is called from `Duke` to parse the user's input. - -Step 3. The parser recognises that an `UpdateCommand` is required, and the UpdateCommand is prepared to return to `Duke`. In the constructor of `UpdateCommand`, `prepareModification` is called to set the values of the attributes to be updated. The other attributes are set to null by default. - -Step 4. `UpdateCommand#execute` is run to process the update. If the serialNumber attribute is null, a `CommandResult` with a `MISSING_SERIAL_NUMBER` output string will be returned. Otherwise, `EquipmentManager#updateEquipment` is called. - -Step 5. If the update was successful, a `CommandResult` with success message will be returned, else a `CommandResult` with `UPDATE_FAILURE_MESSAGE` will be returned. Upon successful update, the object should be updated with the new attributes as shown in the diagram below. - -![equipment1](images/equipment1.png) - -The *Sequence Diagram* below shows how the objects/classes interact with each other in the case of an update command being issued by the user. - -![sequenceDiagram](images/sequenceDiagram.png) - -Step 6. It is not shown in the sequence diagram but ultimately when the CommandResult is returned to `Duke`, the output of the `CommandResult` gets printed out and displayed to the user. - ### Architecture Our design draws significant inspiration from the implementation of AddressBook Level 3 (henceforth AddressBook). @@ -95,6 +64,37 @@ Together, this ensured that all argument pairs can be effectively parsed and dis Throughout the `Parser` implementation, exceptions were used to return `IncorrectCommand` classes that can be used to pass error messages to the user. These will be discussed in the following segments. +### Update feature + +#### Current Design and Implementation + +The update feature is facilitated by `UpdateCommand`. It extends `ModificationCommand` and implements the following operations: + +* `UpdateCommand#generateUpdatePairs()` — Generates pairs of attributes and their update values. +* `VersionedAddressBook#generateUpdateString()` — Generates sString with details of the update executed. + +Given below is an example usage scenario and how the update feature behaves at each step. + +Step 1. The user adds an equipment to the system with the help of the `add` command. The added equipment has the following attributes shown below. + +![equipment0](images/equipment0.png) + +Step 2. The user executes `update s/S1404115ASF n/SpeakerC c/2000 pd/2022-01-29` to update equipment with serial number S1404115ASF. `Parser#parseCommand` is called from `Duke` to parse the user's input. + +Step 3. The parser recognises that an `UpdateCommand` is required, and the UpdateCommand is prepared to return to `Duke`. In the constructor of `UpdateCommand`, `prepareModification` is called to set the values of the attributes to be updated. The other attributes are set to null by default. + +Step 4. `UpdateCommand#execute` is run to process the update. If the serialNumber attribute is null, a `CommandResult` with a `MISSING_SERIAL_NUMBER` output string will be returned. Otherwise, `EquipmentManager#updateEquipment` is called. + +Step 5. If the update was successful, a `CommandResult` with success message will be returned, else a `CommandResult` with `UPDATE_FAILURE_MESSAGE` will be returned. Upon successful update, the object should be updated with the new attributes as shown in the diagram below. + +![equipment1](images/equipment1.png) + +The *Sequence Diagram* below shows how the objects/classes interact with each other in the case of an update command being issued by the user. + +![sequenceDiagram](images/sequenceDiagram.png) + +Step 6. It is not shown in the sequence diagram but ultimately when the CommandResult is returned to `Duke`, the output of the `CommandResult` gets printed out and displayed to the user. + -------------------------------------------------------------------------------------------------------------------- ## Product scope ### Target user profile From 1d8c444502e6a19969692181f602e7904f379dfa Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Thu, 24 Mar 2022 21:19:54 +0800 Subject: [PATCH 088/229] Add JavaDocs --- src/main/java/seedu/equipment/Equipment.java | 10 ++++ .../seedu/equipment/EquipmentManager.java | 47 +++++++++++++++++++ src/main/java/seedu/storage/Storage.java | 10 ++++ 3 files changed, 67 insertions(+) diff --git a/src/main/java/seedu/equipment/Equipment.java b/src/main/java/seedu/equipment/Equipment.java index 1a7b1eeb85..3a66ead022 100644 --- a/src/main/java/seedu/equipment/Equipment.java +++ b/src/main/java/seedu/equipment/Equipment.java @@ -10,6 +10,16 @@ public class Equipment { private String purchasedFrom; private String purchasedDate; + /** + * Constructor for the Equipment object. + * + * @param itemName Name of the equipment in String. + * @param serialNumber Unique serial number of equipment in String. + * @param type Type of the equipment in EquipmentType enum. + * @param cost Cost of the equipment in double. + * @param purchasedFrom Where the equipment was purchased in String. + * @param purchasedDate When the equipment was purchased in String. + */ public Equipment(String itemName, String serialNumber, EquipmentType type, double cost, String purchasedFrom, String purchasedDate) { this.itemName = itemName; diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index 926ce18654..fd5b037dda 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -12,6 +12,17 @@ public EquipmentManager() { this.equipmentList = new HashMap<>(); } + /** + * Creates an Equipment object using the parameters and adds it to the equipmentList. + * + * @param itemName Name of the equipment in String. + * @param serialNumber Unique serial number of equipment in String. + * @param type Type of the equipment in EquipmentType enum. + * @param cost Cost of the equipment in double. + * @param purchasedFrom Where the equipment was purchased in String. + * @param purchasedDate When the equipment was purchased in String. + * @throws DuplicateSerialNumberException If the serial number exists in equipmentList. + */ public void addEquipment(String itemName, String serialNumber, EquipmentType type, double cost, String purchasedFrom, String purchasedDate) throws DuplicateSerialNumberException { if (!equipmentList.containsKey(serialNumber)) { @@ -22,6 +33,12 @@ public void addEquipment(String itemName, String serialNumber, EquipmentType typ } } + /** + * Adds the Equipment object into the equipmentList. + * + * @param equipment Equipment object. + * @throws DuplicateSerialNumberException If the serial number exists in equipmentList. + */ public void addEquipment(Equipment equipment) throws DuplicateSerialNumberException { String serialNumber = equipment.getSerialNumber(); if (!equipmentList.containsKey(serialNumber)) { @@ -31,6 +48,12 @@ public void addEquipment(Equipment equipment) throws DuplicateSerialNumberExcept } } + /** + * Searches the equipmentList for Equipments with the item name given. + * + * @param itemName Name of Equipment in String. + * @return An ArrayList of Equipments with the same item name as the parameter. + */ public ArrayList checkEquipment(String itemName) { ArrayList listOfEquipments = new ArrayList<>(); for (Equipment equipment : equipmentList.values()) { @@ -41,10 +64,21 @@ public ArrayList checkEquipment(String itemName) { return listOfEquipments; } + /** + * Creates an ArrayList of all Equipment Objects. + * + * @return An ArrayList of all Equipment Objects in equipmentList. + */ public ArrayList listEquipment() { return new ArrayList<>(equipmentList.values()); } + /** + * Creates an ArrayList of all Equipment with the specified EquipmentType. + * + * @param type Type of equipment in EquipmentType enum. + * @return An ArrayList of Equipment Objects with the specified type in equipmentList. + */ public ArrayList listEquipment(EquipmentType type) { ArrayList listOfEquipments = new ArrayList<>(); for (Equipment equipment : equipmentList.values()) { @@ -59,6 +93,14 @@ public HashMap getEquipmentList() { return equipmentList; } + /** + * Updates the Equipment corresponding to the serial number given. + * Updates are given in the form of ArrayList of Pairs. + * + * @param serialNumber Serial number of Equipment in String. + * @param updatePairs Updates for Equipment with key being an Equipment attribute and value being the updated attribute. + * @return Boolean value based on whether the update succeeded or not. + */ public boolean updateEquipment(String serialNumber, ArrayList> updatePairs) { if (!equipmentList.containsKey(serialNumber)) { return false; @@ -93,6 +135,11 @@ public boolean updateEquipment(String serialNumber, ArrayList equipments = new ArrayList<>(equipmentManager.getEquipmentList().values()); try { From 068000d4cbca41bab096b37f3b7bcf967c85d704 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Thu, 24 Mar 2022 22:19:23 +0800 Subject: [PATCH 089/229] Update DeveloperGuide --- docs/DeveloperGuide.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 0f7964bb4f..5a7b2ecf48 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -95,6 +95,20 @@ The *Sequence Diagram* below shows how the objects/classes interact with each ot Step 6. It is not shown in the sequence diagram but ultimately when the CommandResult is returned to `Duke`, the output of the `CommandResult` gets printed out and displayed to the user. +### EquipmentManager + +The **`EquipmentManager`**, as the name suggests, manages all the equipment that the user has. +When initialised, it creates a HashMap called **`equipmentList`** which is used to save the equipment with their serial numbers as their keys. +The **`EquipmentManager`** has several methods which allow manipulation to said HashMap such as **`addEquipment`**, **`checkEquipment`**, **`listEquipment`**, **`updateEquipment`**, and **`deleteEquipment`**. +These methods are used during the execution of each of the **`Command`** class. +* **`addEquipment`** — Adds an **`Equipment`** to the **`equipmentList`**. +* **`checkEquipment`** — Returns the **`Equipment`** in **`equipmentList`** that has the given **`itemName`**. +* **`listEquipment`** — Returns an ArrayList of all the **`Equipment`** in **`equipmentList`**. +* **`updateEquipment`** — Updates the specified **`Equipment`** with the corresponding updates given in the ArrayList of pairs. +* **`deleteEquipment`** — Deletes the specified **`Equipment`**. + +The **`EquipmentManager`** is implemented as the main storage unit of all the equipments during the execution of the program. + -------------------------------------------------------------------------------------------------------------------- ## Product scope ### Target user profile From 33e156158ee568989da811e5d6ba73d37b66c233 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Thu, 24 Mar 2022 23:12:42 +0800 Subject: [PATCH 090/229] Fix gradle --- src/main/java/seedu/equipment/EquipmentManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index fd5b037dda..e4a9416a9b 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -98,7 +98,8 @@ public HashMap getEquipmentList() { * Updates are given in the form of ArrayList of Pairs. * * @param serialNumber Serial number of Equipment in String. - * @param updatePairs Updates for Equipment with key being an Equipment attribute and value being the updated attribute. + * @param updatePairs Updates for Equipment with key being an Equipment + * attribute and value being the updated attribute. * @return Boolean value based on whether the update succeeded or not. */ public boolean updateEquipment(String serialNumber, ArrayList> updatePairs) { From ab30bb690472ec1a0d9ff825ed7cd3ba8591691d Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Fri, 25 Mar 2022 11:37:30 +0800 Subject: [PATCH 091/229] Update DeveloperGuide to apply theme --- docs/DeveloperGuide.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 5a7b2ecf48..8c17ddd193 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -1,11 +1,19 @@ ---- -layout: page -title: Developer Guide ---- -* Table of Contents - {:toc} +# Table of Content + +- [Acknowledgements](#acknowledgements) +- [Design and Implementation](#**Design-and-Implementation**) + - [Architecture](#Architecture) + - [Parser](#Parser) + - [Update feature](#Update-feature) + - [EquipmentManager](#EquipmentManager) +- [Product scope](#Product scope) + - [Target user profile](#Target-user-profile) + - [Value proposition](#Value-proposition) +- [User stories](#User-Stories) +- [NonFunctional requirements](#NonFunctional Requirements) +- [Glossary](#Glossary) +- [Instructions for manual testing](#Instructions-for-manual-testing) --------------------------------------------------------------------------------------------------------------------- ## Acknowledgements {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well} @@ -128,7 +136,7 @@ The **`EquipmentManager`** is implemented as the main storage unit of all the eq |v2.0|user|find a to-do item by name|locate a to-do without having to go through the entire list| -------------------------------------------------------------------------------------------------------------------- -## Non-Functional Requirements +## NonFunctional Requirements {Give non-functional requirements} From 4b007a335e251cfbf723cd71c49c3ba300a0663c Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Fri, 25 Mar 2022 18:27:43 +0800 Subject: [PATCH 092/229] Update Pair class to support parsing of Double cost and EquipmentType --- src/main/java/seedu/command/AddCommand.java | 6 ++-- .../seedu/command/ModificationCommand.java | 32 ++++++++++++------- .../java/seedu/command/UpdateCommand.java | 12 +++---- .../seedu/equipment/EquipmentManager.java | 4 +-- .../java/seedu/equipment/EquipmentType.java | 10 +++++- src/main/java/seedu/parser/Parser.java | 9 ++++++ .../java/seedu/command/AddCommandTest.java | 3 +- 7 files changed, 49 insertions(+), 27 deletions(-) diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index c9b030a57e..5659948eb1 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -63,10 +63,8 @@ public CommandResult execute() { * @param userInput ArrayList of String which contains the individual attributes of the equipment to be added */ public void addEquipment(ArrayList userInput) throws DuplicateSerialNumberException { - EquipmentType type = EquipmentType.valueOf(this.type); - double cost = Double.parseDouble(this.cost); - Equipment newEquipment = new Equipment(equipmentName, serialNumber, type, cost, purchasedFrom, purchasedDate); + Equipment newEquipment = new Equipment(equipmentName, serialNumber, equipmentType, cost, purchasedFrom, purchasedDate); equipmentManager.addEquipment(newEquipment); } @@ -75,7 +73,7 @@ public void addEquipment(ArrayList userInput) throws DuplicateSerialNumb * @return boolean to indicate whether all attributes are set. */ public boolean checkAttributes() { - if (equipmentName == null || serialNumber == null || type == null || cost == null + if (equipmentName == null || serialNumber == null || equipmentType == null || cost == null || purchasedFrom == null || purchasedDate == null) { return false; } diff --git a/src/main/java/seedu/command/ModificationCommand.java b/src/main/java/seedu/command/ModificationCommand.java index 79b1e37dd7..b9695ab97c 100644 --- a/src/main/java/seedu/command/ModificationCommand.java +++ b/src/main/java/seedu/command/ModificationCommand.java @@ -1,22 +1,26 @@ package seedu.command; +import seedu.equipment.EquipmentType; + import java.util.ArrayList; import java.util.Objects; /** - * Abstract class acting as parent class to AddCommand and UpdateCommand which have use for the - * same prepareModification method. + * Parent class to AddCommand and UpdateCommand which have use for the same prepareModification method. */ public class ModificationCommand extends Command { public static final String IMPLEMENTED_BY_CHILD = "Execute method for Modification should be implemented by " + "child classes AddCommand and UpdateCommand"; + public static final String INVALID_TYPE_MESSAGE = "Equipment Type needs to be one of:" + System.lineSeparator() + + EquipmentType.getAllTypes(); + public static final String INVALID_COST_MESSAGE = "Cost needs to be able to be parsed to a double"; protected final ArrayList commandStrings; protected String serialNumber; protected String equipmentName = null; protected String purchasedDate = null; - protected String type = null; + protected EquipmentType equipmentType = null; protected String purchasedFrom = null; - protected String cost = null; + protected Double cost = null; public ModificationCommand(ArrayList commandStrings) { this.commandStrings = commandStrings; @@ -39,15 +43,15 @@ public void setPurchasedDate(String purchasedDate) { this.purchasedDate = purchasedDate; } - public void setType(String type) { - this.type = type; + public void setEquipmentType(EquipmentType equipmentType) { + this.equipmentType = equipmentType; } public void setPurchasedFrom(String purchasedFrom) { this.purchasedFrom = purchasedFrom; } - public void setCost(String cost) { + public void setCost(Double cost) { this.cost = cost; } @@ -56,8 +60,12 @@ public void setCost(String cost) { * *

Should multiple arguments specifying the same argument parameter (e.g. 'c/1000' and 'c/2000') be given, * the previous arguments passed in will be overwritten by the most recent parameter ('c/2000' in example). + * + * @throws NumberFormatException if cost is invalid + * @throws IllegalArgumentException if EquipmentType is invalid + * */ - protected void prepareModification() throws AssertionError { + protected void prepareModification() throws AssertionError, NumberFormatException, IllegalArgumentException { for (String s : commandStrings) { int delimiterPos = s.indexOf('/'); // the case where delimiterPos = -1 is impossible as @@ -73,13 +81,13 @@ protected void prepareModification() throws AssertionError { setPurchasedDate(argValue); break; case "t": - setType(argValue); + setEquipmentType(EquipmentType.valueOf(argValue)); break; case "pf": setPurchasedFrom(argValue); break; case "c": - setCost(argValue); + setCost(Double.valueOf(argValue)); break; case "s": setSerialNumber(argValue); @@ -102,13 +110,13 @@ public boolean equals(Object o) { return serialNumber.equals(that.serialNumber) && Objects.equals(equipmentName, that.equipmentName) && Objects.equals(purchasedDate, that.purchasedDate) - && Objects.equals(type, that.type) + && Objects.equals(equipmentType, that.equipmentType) && Objects.equals(purchasedFrom, that.purchasedFrom) && Objects.equals(cost, that.cost); } @Override public int hashCode() { - return Objects.hash(serialNumber, equipmentName, purchasedDate, type, purchasedFrom, cost); + return Objects.hash(serialNumber, equipmentName, purchasedDate, equipmentType, purchasedFrom, cost); } } diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java index e27232d847..12b01869d8 100644 --- a/src/main/java/seedu/command/UpdateCommand.java +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -52,8 +52,8 @@ public String getSerialNumber() { if (equipmentName != null) { pairs.add(new Pair<>("itemName", equipmentName)); } - if (type != null) { - pairs.add(new Pair<>("type", type)); + if (equipmentType != null) { + pairs.add(new Pair<>("type", equipmentType)); } if (cost != null) { pairs.add(new Pair<>("cost", cost)); @@ -73,8 +73,8 @@ public String generateUpdateString() { if (equipmentName != null) { updateDetails = updateDetails + System.lineSeparator() + "New name: " + equipmentName; } - if (type != null) { - updateDetails = updateDetails + System.lineSeparator() + "New type: " + type; + if (equipmentType != null) { + updateDetails = updateDetails + System.lineSeparator() + "New type: " + equipmentType; } if (cost != null) { updateDetails = updateDetails + System.lineSeparator() + "New cost: " + cost; @@ -101,13 +101,13 @@ public boolean equals(Object o) { return serialNumber.equals(that.serialNumber) && Objects.equals(equipmentName, that.equipmentName) && Objects.equals(purchasedDate, that.purchasedDate) - && Objects.equals(type, that.type) + && Objects.equals(equipmentType, that.equipmentType) && Objects.equals(purchasedFrom, that.purchasedFrom) && Objects.equals(cost, that.cost); } @Override public int hashCode() { - return Objects.hash(serialNumber, equipmentName, purchasedDate, type, purchasedFrom, cost); + return Objects.hash(serialNumber, equipmentName, purchasedDate, equipmentType, purchasedFrom, cost); } } diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index 271bf869a8..760dd5ee70 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -72,13 +72,13 @@ public boolean updateEquipment(String serialNumber, ArrayList> u break; case "type": try { - updatedEquipment.setType(EquipmentType.valueOf((String)updates.getValue())); + updatedEquipment.setType((EquipmentType) updates.getValue()); } catch (IllegalArgumentException e) { return false; } break; case "cost": - updatedEquipment.setCost(Double.valueOf((String) updates.getValue())); + updatedEquipment.setCost((Double) updates.getValue()); break; case "purchaseDate": updatedEquipment.setPurchasedDate((String) updates.getValue()); diff --git a/src/main/java/seedu/equipment/EquipmentType.java b/src/main/java/seedu/equipment/EquipmentType.java index 6de199deb3..f0bc8d95eb 100644 --- a/src/main/java/seedu/equipment/EquipmentType.java +++ b/src/main/java/seedu/equipment/EquipmentType.java @@ -1,5 +1,13 @@ package seedu.equipment; public enum EquipmentType { - MICROPHONE, SPEAKER, STAND, CABLE + MICROPHONE, SPEAKER, STAND, CABLE; + + public static String getAllTypes() { + StringBuilder sb = new StringBuilder(); + for (EquipmentType type : EquipmentType.values()) { + sb.append(type.name() + ", "); + } + return sb.toString(); + } } diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 355ab86fd6..c94de44999 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import seedu.command.AddCommand; +import seedu.command.ModificationCommand; import seedu.command.UpdateCommand; import seedu.command.ListCommand; import seedu.command.IncorrectCommand; @@ -80,6 +81,10 @@ public Command parseCommand(String userInput) { return new AddCommand(args); } catch (IncompleteCommandException e) { return new IncorrectCommand(AddCommand.COMMAND_WORD + AddCommand.COMMAND_DESCRIPTION); + } catch (NumberFormatException e) { + return new IncorrectCommand(ModificationCommand.INVALID_COST_MESSAGE); + } catch (IllegalArgumentException e) { + return new IncorrectCommand(ModificationCommand.INVALID_TYPE_MESSAGE); } case CheckCommand.COMMAND_WORD: try { @@ -101,6 +106,10 @@ public Command parseCommand(String userInput) { return new UpdateCommand(args); } catch (IncompleteCommandException e) { return new IncorrectCommand(UpdateCommand.COMMAND_WORD + UpdateCommand.COMMAND_DESCRIPTION); + } catch (NumberFormatException e) { + return new IncorrectCommand(ModificationCommand.INVALID_COST_MESSAGE); + } catch (IllegalArgumentException e) { + return new IncorrectCommand(ModificationCommand.INVALID_TYPE_MESSAGE); } case ListCommand.COMMAND_WORD: if (commandAndArgument.get(1) == null) { diff --git a/src/test/java/seedu/command/AddCommandTest.java b/src/test/java/seedu/command/AddCommandTest.java index 2f05a6bf81..783d686dbe 100644 --- a/src/test/java/seedu/command/AddCommandTest.java +++ b/src/test/java/seedu/command/AddCommandTest.java @@ -76,8 +76,7 @@ void execute_incorrectEnumType_exceptionThrown() { addCommand.setEquipmentManager(new EquipmentManager()); EquipmentManager equipmentManager = addCommand.equipmentManager; - CommandResult expectedResult = new CommandResult("Wrong type of equipment. " - + "The allowed types are: MICROPHONE, SPEAKER, STAND, CABLE"); + CommandResult expectedResult = new CommandResult(ModificationCommand.INVALID_TYPE_MESSAGE); CommandResult actualResult = addCommand.execute(); assertEquals(expectedResult, actualResult); } From d9a226003aee583c7f4a0e1991bfc878194c9bb8 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Fri, 25 Mar 2022 21:32:17 +0800 Subject: [PATCH 093/229] Add Parser support for new Save command closes #70 --- src/main/java/seedu/parser/Parser.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index f91c396c88..5a263f2e81 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -120,6 +120,8 @@ public Command parseCommand(String userInput) { } case HelpCommand.COMMAND_WORD: return new HelpCommand(); + case SaveCommand.COMMAND_WORD: + return new SaveCommand(); default: return new IncorrectCommand(INCORRECT_COMMAND_FORMAT); @@ -140,18 +142,25 @@ public Command parseCommand(String userInput) { public ArrayList splitCommandTerm(String userInput) throws IncompleteCommandException { ArrayList resultArrayList = new ArrayList<>(); userInput = userInput.trim(); - // Checks for "list" command word first - if (userInput.toLowerCase(Locale.ROOT).equals(ListCommand.COMMAND_WORD)) { + + // Checks for list/help/save command word first + switch (userInput.toLowerCase(Locale.ROOT)) { + case ListCommand.COMMAND_WORD: resultArrayList.add(ListCommand.COMMAND_WORD); resultArrayList.add(null); return resultArrayList; - } - // Checks for "help" command word next - if (userInput.toLowerCase(Locale.ROOT).equals(HelpCommand.COMMAND_WORD)) { + 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; + default: + break; } + // Match terms against syntax final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput); // Guard against no match From 15083e6a89e26805be56937f40b85c48f5efb84b Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Fri, 25 Mar 2022 21:35:18 +0800 Subject: [PATCH 094/229] Fix Gradle CI/CD check for line exceeding 120 characters --- src/main/java/seedu/command/AddCommand.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index 5b6bac1a11..192176c399 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -64,7 +64,8 @@ public CommandResult execute() { */ public void addEquipment(ArrayList userInput) throws DuplicateSerialNumberException { - Equipment newEquipment = new Equipment(equipmentName, serialNumber, equipmentType, cost, purchasedFrom, purchasedDate); + Equipment newEquipment = new Equipment(equipmentName, serialNumber, equipmentType, cost, purchasedFrom, + purchasedDate); equipmentManager.addEquipment(newEquipment); } From 9aaa4a562b8efe6dd9f74635ba11de2dd9c65282 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 29 Mar 2022 02:06:06 +0800 Subject: [PATCH 095/229] Fix developer guide table of content --- docs/DeveloperGuide.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 8c17ddd193..9cbdb12a28 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -1,18 +1,18 @@ # Table of Content - [Acknowledgements](#acknowledgements) -- [Design and Implementation](#**Design-and-Implementation**) - - [Architecture](#Architecture) - - [Parser](#Parser) - - [Update feature](#Update-feature) - - [EquipmentManager](#EquipmentManager) -- [Product scope](#Product scope) - - [Target user profile](#Target-user-profile) - - [Value proposition](#Value-proposition) -- [User stories](#User-Stories) -- [NonFunctional requirements](#NonFunctional Requirements) -- [Glossary](#Glossary) -- [Instructions for manual testing](#Instructions-for-manual-testing) +- [Design and Implementation](#design-and-implementation) + - [Architecture](#architecture) + - [Parser](#parser) + - [Update feature](#update-feature) + - [EquipmentManager](#equipmentmanager) +- [Product scope](#product-scope) + - [Target user profile](#target-user-profile) + - [Value proposition](#value-proposition) +- [User stories](#user-stories) +- [NonFunctional requirements](#nonfunctional-requirements) +- [Glossary](#glossary) +- [Instructions for manual testing](#instructions-for-manual-testing) ## Acknowledgements From 4ce2fee389b2a6154f9a37c9ad1206e3490b2caf Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 29 Mar 2022 02:37:27 +0800 Subject: [PATCH 096/229] Update user guide, by yuhao --- docs/UserGuide.md | 84 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 16 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index abd9fbe891..2d6f21a80a 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -2,41 +2,93 @@ ## Introduction -{Give a product intro} +EquipmentManager is a Command Line Interface application to help with keeping track of equipment details (e.g. current user, quantity, cost, warranty duration, purchase date) for the AV club. It provides a clean and fast way to manage the inventory as compared to “traditional” methods such as an excel spreadsheet. ## Quick Start -{Give steps to get started quickly} - 1. Ensure that you have Java 11 or above installed. -1. Down the latest version of `Duke` from [here](http://link.to/duke). +2. Download the latest version of `EquipmentManager` from [here](https://github.com/AY2122S2-CS2113-F12-2/tp/releases). ## Features -{Give detailed description of each feature} +- [Adding an equipment: `add`](#adding-an-equipment-add) +- [Checking an equipment: `check`](#checking-an-equipment-check) +- [Listing equipment: `list`](#listing-equipment-list) +- [Updating an equipment: `update`](#updating-an-equipment-update) +- [Deleting an equipment: `delete`](#deleting-an-equipment-delete) +- [Saving application state: `save`](#saving-application-state-save) +- [Getting help: `help`](#getting-help-help) +- [Exiting the application: `bye`](#exiting-the-application-bye) + +### Adding an equipment: `add` +Adds new Equipment to the list of Equipment. + +Format: `add n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE` + +* The `TYPE` must be one of the following types: MICROPHONE, SPEAKER, STAND, CABLE. +* The `COST` cannot contain any symbols. + +Example of usage and output: + +`add n/SpeakerB s/S1404115ASF t/Speaker c/1000 pf/Loud_Technologies pd/2022-02-23` +output: `Equipment successfully added: SpeakerB, serial number S1404115ASF` + +### Checking an equipment: `check` +Check the details of the equipment that has the name specified. + +Format: `check n/ITEM_NAME` + +* Only the `ITEM_NAME` can be used to check for an equipment. + +Example of usage and output: + +`check n/SpeakerB` +output: +`Here are the equipment matching to 'SpeakerB':` + +`1. serialNumber=S1404115ASF,itemName=SpeakerB,type=SPEAKER,cost=1000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-02-23` + +### Listing equipment: `list` +Print a list of all equipment in the inventory. + +Format: `list` + +Example of usage and output: + +`list` +output: +`TOTAL QUANTITY OF EQUIPMENT: 2` + +`1. serialNumber=S89347971ASF,itemName=MixerC,type=MICROPHONE,cost=2000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-01-21` +`2. serialNumber=S1404115ASF,itemName=SpeakerB,type=SPEAKER,cost=1000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-02-23` -### Adding a todo: `todo` -Adds a new item to the list of todo items. +### Listing equipment by type -Format: `todo n/TODO_NAME d/DEADLINE` +### Updating an equipment: `update` -* The `DEADLINE` can be in a natural language format. -* The `TODO_NAME` cannot contain punctuation. +### Deleting an equipment: `delete` -Example of usage: +### Saving application state: `save` -`todo n/Write the rest of the User Guide d/next week` +### Getting help: `help` -`todo n/Refactor the User Guide to remove passive voice d/13/04/2020` +### Exiting the application: `bye` ## FAQ **Q**: How do I transfer my data to another computer? -**A**: {your answer here} +**A**: Copy the data folder from the old computer into the other computer, in the same directory as the JAR file. ## Command Summary -{Give a 'cheat sheet' of commands here} +'Cheat Sheet' of commands here -* Add todo `todo n/TODO_NAME d/DEADLINE` +* Add equipment `todo n/TODO_NAME d/DEADLINE` +* Listing equipment: +* Listing equipment by type: ADD ON HERE +* Updating an equipment: ADD ON HERE +* Deleting an equipment: ADD ON HERE +* Saving application state: ADD ON HERE +* Getting help: ADD ON HERE +* Exiting the application: ADD ON HERE From 48091c4c11fc422c8a79260e299623d78bd45739 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 29 Mar 2022 02:50:49 +0800 Subject: [PATCH 097/229] Update user guide formatting --- docs/UserGuide.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 2d6f21a80a..e81fada848 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -31,6 +31,7 @@ Format: `add n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PUR Example of usage and output: `add n/SpeakerB s/S1404115ASF t/Speaker c/1000 pf/Loud_Technologies pd/2022-02-23` + output: `Equipment successfully added: SpeakerB, serial number S1404115ASF` ### Checking an equipment: `check` @@ -43,7 +44,9 @@ Format: `check n/ITEM_NAME` Example of usage and output: `check n/SpeakerB` + output: + `Here are the equipment matching to 'SpeakerB':` `1. serialNumber=S1404115ASF,itemName=SpeakerB,type=SPEAKER,cost=1000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-02-23` @@ -56,10 +59,13 @@ Format: `list` Example of usage and output: `list` + output: + `TOTAL QUANTITY OF EQUIPMENT: 2` `1. serialNumber=S89347971ASF,itemName=MixerC,type=MICROPHONE,cost=2000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-01-21` + `2. serialNumber=S1404115ASF,itemName=SpeakerB,type=SPEAKER,cost=1000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-02-23` ### Listing equipment by type From 7daddaa5f573deabc265f5709d165f7f608154d0 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 29 Mar 2022 10:53:35 +0800 Subject: [PATCH 098/229] Add SaveCommand --- src/main/java/seedu/command/Command.java | 6 +++++ src/main/java/seedu/command/HelpCommand.java | 2 ++ src/main/java/seedu/command/SaveCommand.java | 23 ++++++++++++++++++++ src/main/java/seedu/duke/Duke.java | 1 + src/main/java/seedu/parser/Parser.java | 1 + 5 files changed, 33 insertions(+) create mode 100644 src/main/java/seedu/command/SaveCommand.java diff --git a/src/main/java/seedu/command/Command.java b/src/main/java/seedu/command/Command.java index e7dfd0b9d7..d4fc6c7f3e 100644 --- a/src/main/java/seedu/command/Command.java +++ b/src/main/java/seedu/command/Command.java @@ -1,6 +1,7 @@ package seedu.command; import seedu.equipment.EquipmentManager; +import seedu.storage.Storage; /** * Abstract parent class for all types of commands. @@ -11,6 +12,7 @@ public abstract class Command { protected String successMessage; public String usageReminder; protected EquipmentManager equipmentManager; + protected Storage storage; protected static final String INCORRECT_ENUM_TYPE = "Wrong type of equipment. The allowed types are: " + "MICROPHONE, SPEAKER, STAND, CABLE"; protected static final String INCORRECT_COST_FORMAT = "Please enter numbers only for cost and omit symbols"; @@ -27,4 +29,8 @@ public String getUsageReminder() { public void setEquipmentManager(EquipmentManager equipmentManager) { this.equipmentManager = equipmentManager; } + + public void setStorage(Storage storage) { + this.storage = storage; + } } diff --git a/src/main/java/seedu/command/HelpCommand.java b/src/main/java/seedu/command/HelpCommand.java index 5b6702ead4..f8f5e99a12 100644 --- a/src/main/java/seedu/command/HelpCommand.java +++ b/src/main/java/seedu/command/HelpCommand.java @@ -28,6 +28,8 @@ public CommandResult execute() { + System.lineSeparator() + System.lineSeparator() + CheckCommand.COMMAND_WORD + CheckCommand.COMMAND_DESCRIPTION + System.lineSeparator() + + System.lineSeparator() + SaveCommand.COMMAND_WORD + SaveCommand.COMMAND_DESCRIPTION + + System.lineSeparator() + System.lineSeparator() + HelpCommand.COMMAND_WORD + HelpCommand.COMMAND_DESCRIPTION); } } diff --git a/src/main/java/seedu/command/SaveCommand.java b/src/main/java/seedu/command/SaveCommand.java new file mode 100644 index 0000000000..01debb1689 --- /dev/null +++ b/src/main/java/seedu/command/SaveCommand.java @@ -0,0 +1,23 @@ +package seedu.command; + +/** + * Subclass of Command. Saves the current state of application into a JSON file. + */ +public class SaveCommand extends Command { + public static final String COMMAND_WORD = "save"; + public static final String COMMAND_DESCRIPTION = ": Saves current state of application. " + + System.lineSeparator() + + "Parameters: NIL" + System.lineSeparator() + + "Example: " + + "save"; + public static final String SUCCESSFUL_SAVE = "Successfully saved."; + + /** + * Saves the current state of application into JSON file. + * @return CommandResult successful save message. + */ + public CommandResult execute() { + storage.saveData(equipmentManager); + return new CommandResult(SUCCESSFUL_SAVE); + } +} diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java index 2d3631555d..9df551cde4 100644 --- a/src/main/java/seedu/duke/Duke.java +++ b/src/main/java/seedu/duke/Duke.java @@ -51,6 +51,7 @@ private void runCommandLoop() { private CommandResult executeCommand(Command command) { command.setEquipmentManager(equipmentInventory); + command.setStorage(storage); CommandResult result = command.execute(); return result; diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 5a263f2e81..888eaba382 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -11,6 +11,7 @@ import seedu.command.DeleteCommand; import seedu.command.HelpCommand; import seedu.command.Command; +import seedu.command.SaveCommand; import java.util.Collections; import java.util.Locale; From 598b834c15f3f3f53c0129556e099f4d0986c384 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 29 Mar 2022 11:21:08 +0800 Subject: [PATCH 099/229] Fix error message which pops up after user inputs bye. Fixes #74 --- src/main/java/seedu/command/ByeCommand.java | 19 +++++++++++++++++++ src/main/java/seedu/command/HelpCommand.java | 3 +++ src/main/java/seedu/command/SaveCommand.java | 2 +- src/main/java/seedu/parser/Parser.java | 8 +++++++- 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 src/main/java/seedu/command/ByeCommand.java diff --git a/src/main/java/seedu/command/ByeCommand.java b/src/main/java/seedu/command/ByeCommand.java new file mode 100644 index 0000000000..f258828f67 --- /dev/null +++ b/src/main/java/seedu/command/ByeCommand.java @@ -0,0 +1,19 @@ +package seedu.command; + +public class ByeCommand extends Command{ + public static final String COMMAND_WORD = "bye"; + public static final String COMMAND_DESCRIPTION = ": Exits the application. " + + System.lineSeparator() + + "Parameters: NIL" + System.lineSeparator() + + "Example: " + + "bye"; + public static final String EXIT_MESSAGE = "Bye, See you again!"; + + /** + * Exits the application. + * @return CommandResult with exit message. + */ + public CommandResult execute() { + return new CommandResult(EXIT_MESSAGE); + } +} diff --git a/src/main/java/seedu/command/HelpCommand.java b/src/main/java/seedu/command/HelpCommand.java index f8f5e99a12..fce376721d 100644 --- a/src/main/java/seedu/command/HelpCommand.java +++ b/src/main/java/seedu/command/HelpCommand.java @@ -30,6 +30,9 @@ public CommandResult execute() { + System.lineSeparator() + System.lineSeparator() + SaveCommand.COMMAND_WORD + SaveCommand.COMMAND_DESCRIPTION + System.lineSeparator() + + System.lineSeparator() + ByeCommand.COMMAND_WORD + ByeCommand.COMMAND_DESCRIPTION + + System.lineSeparator() + System.lineSeparator() + HelpCommand.COMMAND_WORD + HelpCommand.COMMAND_DESCRIPTION); + } } diff --git a/src/main/java/seedu/command/SaveCommand.java b/src/main/java/seedu/command/SaveCommand.java index 01debb1689..c44d44ae32 100644 --- a/src/main/java/seedu/command/SaveCommand.java +++ b/src/main/java/seedu/command/SaveCommand.java @@ -14,7 +14,7 @@ public class SaveCommand extends Command { /** * Saves the current state of application into JSON file. - * @return CommandResult successful save message. + * @return CommandResult with successful save message. */ public CommandResult execute() { storage.saveData(equipmentManager); diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 888eaba382..c55e733cbd 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -12,6 +12,7 @@ import seedu.command.HelpCommand; import seedu.command.Command; import seedu.command.SaveCommand; +import seedu.command.ByeCommand; import java.util.Collections; import java.util.Locale; @@ -123,7 +124,8 @@ public Command parseCommand(String userInput) { return new HelpCommand(); case SaveCommand.COMMAND_WORD: return new SaveCommand(); - + case ByeCommand.COMMAND_WORD: + return new ByeCommand(); default: return new IncorrectCommand(INCORRECT_COMMAND_FORMAT); } @@ -158,6 +160,10 @@ public ArrayList splitCommandTerm(String userInput) throws IncompleteCom 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; } From aff1a94cd070222c0962bf1b577306377030bd90 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 29 Mar 2022 11:30:39 +0800 Subject: [PATCH 100/229] Fix checkstyle error --- src/main/java/seedu/command/ByeCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/command/ByeCommand.java b/src/main/java/seedu/command/ByeCommand.java index f258828f67..2fa8857e19 100644 --- a/src/main/java/seedu/command/ByeCommand.java +++ b/src/main/java/seedu/command/ByeCommand.java @@ -1,6 +1,6 @@ package seedu.command; -public class ByeCommand extends Command{ +public class ByeCommand extends Command { public static final String COMMAND_WORD = "bye"; public static final String COMMAND_DESCRIPTION = ": Exits the application. " + System.lineSeparator() From c899522547cc4929840eea227ad9645e6a041dff Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 29 Mar 2022 12:06:01 +0800 Subject: [PATCH 101/229] Fix gradle error --- .../java/seedu/command/AddCommandTest.java | 20 +++++------------ .../java/seedu/command/UpdateCommandTest.java | 6 ++--- .../seedu/equipment/EquipmentManagerTest.java | 22 ++----------------- 3 files changed, 11 insertions(+), 37 deletions(-) diff --git a/src/test/java/seedu/command/AddCommandTest.java b/src/test/java/seedu/command/AddCommandTest.java index 783d686dbe..cdce06b0c5 100644 --- a/src/test/java/seedu/command/AddCommandTest.java +++ b/src/test/java/seedu/command/AddCommandTest.java @@ -7,6 +7,7 @@ import seedu.equipment.Equipment; import seedu.equipment.EquipmentManager; import seedu.equipment.EquipmentType; +import seedu.parser.IncompleteCommandException; import seedu.parser.Parser; import java.util.ArrayList; @@ -15,6 +16,7 @@ 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 { @@ -49,36 +51,26 @@ void execute_duplicateSerialNumber_exceptionThrown() throws DuplicateSerialNumbe @Test void execute_incorrectCostFormat_exceptionThrown() { - addCommand = new AddCommand(new ArrayList<>( + 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") - )); - - CommandResult expectedResult = new CommandResult("Please enter numbers only for cost and omit symbols"); - CommandResult actualResult = addCommand.execute(); - assertEquals(expectedResult, actualResult); + ))); } @Test void execute_incorrectEnumType_exceptionThrown() { - addCommand = new AddCommand(new ArrayList<>( + 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") - )); - addCommand.setEquipmentManager(new EquipmentManager()); - EquipmentManager equipmentManager = addCommand.equipmentManager; - - CommandResult expectedResult = new CommandResult(ModificationCommand.INVALID_TYPE_MESSAGE); - CommandResult actualResult = addCommand.execute(); - assertEquals(expectedResult, actualResult); + ))); } @Test diff --git a/src/test/java/seedu/command/UpdateCommandTest.java b/src/test/java/seedu/command/UpdateCommandTest.java index 78ba5a22c0..306a19997f 100644 --- a/src/test/java/seedu/command/UpdateCommandTest.java +++ b/src/test/java/seedu/command/UpdateCommandTest.java @@ -44,7 +44,7 @@ void execute_validSerialNumber_success() { + System.lineSeparator() + "New name: Speaker C" + System.lineSeparator() - + "New cost: 2000" + + "New cost: 2000.0" + System.lineSeparator() + "New purchase date: 2022-01-26"); @@ -55,9 +55,9 @@ void execute_validSerialNumber_success() { @Test void generateUpdatePairs_nonNullUpdates_success() { - ArrayList> expectedResult = new ArrayList<>(); + ArrayList> expectedResult = new ArrayList<>(); expectedResult.add(new Pair<>("itemName", "Speaker C")); - expectedResult.add(new Pair<>("cost", "2000")); + expectedResult.add(new Pair<>("cost", 2000.0)); expectedResult.add(new Pair<>("purchasedDate", "2022-01-26")); ArrayList> actualResult = updateCommand.generateUpdatePairs(); diff --git a/src/test/java/seedu/equipment/EquipmentManagerTest.java b/src/test/java/seedu/equipment/EquipmentManagerTest.java index 81ef0400ca..51011613d9 100644 --- a/src/test/java/seedu/equipment/EquipmentManagerTest.java +++ b/src/test/java/seedu/equipment/EquipmentManagerTest.java @@ -21,8 +21,8 @@ public void updateEquipment_success() throws DuplicateSerialNumberException { "2022-02-23"); 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<>("type", EquipmentType.STAND)); + updates.add(new Pair<>("cost", 2000.0)); updates.add(new Pair<>("purchaseDate", "2022-03-17")); updates.add(new Pair<>("purchaseFrom", "Louder Technologies")); equipmentManager.updateEquipment("S1404115ASF", updates); @@ -47,22 +47,4 @@ public void updateEquipment_keyNotFound() { EquipmentManager equipmentManager = new EquipmentManager(); assertFalse(equipmentManager.updateEquipment("WRONG SERIAL NUMBER", updates)); } - - @Test - public void updateEquipment_invalidEquipmentType() throws DuplicateSerialNumberException { - EquipmentManager equipmentManager = new EquipmentManager(); - equipmentManager.addEquipment("Speaker B", - "S1404115ASF", - EquipmentType.valueOf("SPEAKER"), - 1000, - "Loud Technologies", - "2022-02-23"); - ArrayList> updates = new ArrayList<>(); - updates.add(new Pair<>("itemName", "Speaker A")); - updates.add(new Pair<>("type", "INVALID EQUIPMENT TYPE")); - updates.add(new Pair<>("cost", "2000")); - updates.add(new Pair<>("purchaseDate", "2022-03-17")); - updates.add(new Pair<>("purchaseFrom", "Louder Technologies")); - assertFalse(equipmentManager.updateEquipment("S1404115ASF", updates)); - } } From 4cc3cc978dc70727874775e2921b0763cbf95269 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 31 Mar 2022 16:48:08 +0800 Subject: [PATCH 102/229] Minor text edit for better user readability --- src/main/java/seedu/command/UpdateCommand.java | 4 +++- src/main/java/seedu/storage/Storage.java | 4 ++-- src/main/java/seedu/ui/TextUi.java | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java index c01f35a05b..0ded8dbea1 100644 --- a/src/main/java/seedu/command/UpdateCommand.java +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -10,7 +10,9 @@ public class UpdateCommand extends ModificationCommand { public static final String COMMAND_WORD = "update"; public static final String COMMAND_DESCRIPTION = ": Updates the equipment with the specified serial number. " + System.lineSeparator() - + "Parameters: s/SERIAL_NUMBER(required) n/ITEM_NAME t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE" + + "Parameters in [square brackets] are optional." + + System.lineSeparator() + + "Parameters: s/SERIAL_NUMBER [n/ITEM_NAME] [t/TYPE] [c/COST] [pf/PURCHASED_FROM] [pd/PURCHASED_DATE]" + System.lineSeparator() + "Example: " + "update s/SM57-1 n/SpeakerC c/2510 pd/2022-08-21"; diff --git a/src/main/java/seedu/storage/Storage.java b/src/main/java/seedu/storage/Storage.java index ee41d5a169..486d474962 100644 --- a/src/main/java/seedu/storage/Storage.java +++ b/src/main/java/seedu/storage/Storage.java @@ -15,8 +15,8 @@ public class Storage { - public static final String FILE_NOT_FOUND_ERROR_MESSAGE = "File not found! " - + "A new file will be created after this session."; + 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"; diff --git a/src/main/java/seedu/ui/TextUi.java b/src/main/java/seedu/ui/TextUi.java index e2503a4dd5..34275719da 100644 --- a/src/main/java/seedu/ui/TextUi.java +++ b/src/main/java/seedu/ui/TextUi.java @@ -8,7 +8,7 @@ * https://github.com/se-edu/addressbook-level2/blob/master/src/seedu/addressbook/ui/TextUi.java */ public class TextUi { - private static final String LOGO = " _ _" + private static final String LOGO = " _ _" + " \n" + " (_) | | \n" + " ___ __ _ _ _ _ _ __ _ __ ___ ___ _ __ | |_ _ __ ___ __ _ _ __ __ _ __ _ ___ _ __ \n" @@ -22,7 +22,7 @@ public class TextUi { 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)"); + System.out.println("What do you want to do? Enter `help` to see what you can do."); } /** From 74fb528eeec928ae1d39423f913db22f4923a29c Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 31 Mar 2022 16:51:29 +0800 Subject: [PATCH 103/229] Rename prepareView to prepareCheck in line with rest of the application's methods. --- src/main/java/seedu/parser/Parser.java | 4 ++-- src/test/java/seedu/parser/ParserTest.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index c55e733cbd..ca99adda9a 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -90,7 +90,7 @@ public Command parseCommand(String userInput) { } case CheckCommand.COMMAND_WORD: try { - args = prepareView(commandAndArgument.get(1)); + args = prepareCheck(commandAndArgument.get(1)); return new CheckCommand(args); } catch (IncompleteCommandException e) { return new IncorrectCommand(CheckCommand.COMMAND_WORD + CheckCommand.COMMAND_DESCRIPTION); @@ -228,7 +228,7 @@ protected ArrayList prepareAdd(String args) throws IncompleteCommandExce * @return ArrayList of one element (assumes rest of string is item name) * @throws IncompleteCommandException if no match found */ - protected ArrayList prepareView(String args) throws IncompleteCommandException { + protected ArrayList prepareCheck(String args) throws IncompleteCommandException { final Matcher matcher = VIEW_COMMAND_FORMAT.matcher(args.trim()); if (!matcher.matches()) { throw new IncompleteCommandException("View command values are incomplete or missing!"); diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 5980e2e71b..ce70032eae 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -136,7 +136,7 @@ void prepareView_viewStringWithSpaces_success() throws IncompleteCommandExceptio ArrayList expectedResult = new ArrayList<>( Arrays.asList("Speaker B") ); - ArrayList actualResult = parser.prepareView( + ArrayList actualResult = parser.prepareCheck( " n/Speaker B "); assertEquals(expectedResult, actualResult); } @@ -147,7 +147,7 @@ void prepareView_wrongArgumentTag_exceptionThrown() { Arrays.asList("Speaker B") ); try { - ArrayList actualResult = parser.prepareView( + ArrayList actualResult = parser.prepareCheck( "s/Speaker B"); assertEquals(expectedResult, actualResult); fail(); From f83b45502d616940ba7dd5ef4a3f0c69a456cae8 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 31 Mar 2022 17:13:33 +0800 Subject: [PATCH 104/229] Test Markdown block --- docs/UserGuide.md | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index e81fada848..f5698ba6ea 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -2,15 +2,40 @@ ## Introduction -EquipmentManager is a Command Line Interface application to help with keeping track of equipment details (e.g. current user, quantity, cost, warranty duration, purchase date) for the AV club. It provides a clean and fast way to manage the inventory as compared to “traditional” methods such as an excel spreadsheet. +EquipmentManager is a Command Line Interface application to help with keeping track of equipment details (e.g. current user, quantity, cost, warranty duration, purchase date) for an AV club. It provides a clean and fast way to manage the inventory as compared to “traditional” methods such as an Excel spreadsheet. ## Quick Start 1. Ensure that you have Java 11 or above installed. 2. Download the latest version of `EquipmentManager` from [here](https://github.com/AY2122S2-CS2113-F12-2/tp/releases). +3. Copy the file to the folder you want to use as the _home folder_ for your `EquipmentManager` application. +4. Double-click the file to start the app. +5. Type `help` to see the list of available commands. ## Features +

+ + - [Adding an equipment: `add`](#adding-an-equipment-add) - [Checking an equipment: `check`](#checking-an-equipment-check) - [Listing equipment: `list`](#listing-equipment-list) @@ -39,7 +64,7 @@ Check the details of the equipment that has the name specified. Format: `check n/ITEM_NAME` -* Only the `ITEM_NAME` can be used to check for an equipment. +* Only the `ITEM_NAME` can be used to check for a piece of equipment. Example of usage and output: From 193e0cd23b8bf07e565fb8f36b009b720c9b5829 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 31 Mar 2022 17:50:35 +0800 Subject: [PATCH 105/229] Update UserGuide for list, update and delete commands --- docs/UserGuide.md | 94 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 27 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index f5698ba6ea..eb50959fc8 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -14,18 +14,27 @@ EquipmentManager is a Command Line Interface application to help with keeping tr ## Features -
+- [Introduction](#Introduction) +- [Adding an equipment: `add`](#adding-an-equipment-add) +- [Checking an equipment: `check`](#checking-an-equipment-check) +- [Listing equipment: `list`](#listing-equipment-list) +- [Updating an equipment: `update`](#updating-an-equipment-update) +- [Deleting an equipment: `delete`](#deleting-an-equipment-delete) +- [Saving application state: `save`](#saving-application-state-save) +- [Getting help: `help`](#getting-help-help) +- [Exiting the application: `bye`](#exiting-the-application-bye) + -**:information_source: Notes about the command format:**
+### Introduction * Words in `UPPER_CASE` are the parameters to be supplied by the user. Spaces are acceptable.
e.g. in `check n/ITEM_NAME`, `ITEM_NAME` is a parameter which can be used as `check n/SM-57`. -* Items in square brackets are optional.
- e.g. `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe`. +* Items in square brackets are optional.
+ e.g. `s/SERIAL_NUMBER [n/ITEM_NAME] [t/TYPE] ...` can be used as `s/SM57-1 n/SM57 t/MICROPHONE...` or as `s/SM57-1 t/MICROPHONE...`. -* Parameters can be in any order.
- e.g. if the command specifies `s/SERIAL_NUMBER n/ITEM_NAME`, `n/ITEM_NAME s/SERIAL_NUMBER` is also acceptable. +* After the command word (e.g. `add`, `update`), parameters can be in any order.
+ e.g. if the command specifies `... s/SERIAL_NUMBER n/ITEM_NAME...`, `n/ITEM_NAME s/SERIAL_NUMBER` is also acceptable. * Only one attribute/value can be saved per parameter. Where multiple inputs are supplied, the last parameter will be taken instead of the first one.
e.g. `... n/ITEM_NAME_1 n/ITEM_NAME_2` will be interpreted as `... n/ITEM_NAME_2`, omitting `n/ITEM_NAME_1` entirely. @@ -33,22 +42,10 @@ EquipmentManager is a Command Line Interface application to help with keeping tr * Extraneous parameters for commands that do not take in parameters (such as `help`, `bye` and `save`) will be ignored.
e.g. if the command specifies `help 123`, it will be interpreted as `help`. -
- - -- [Adding an equipment: `add`](#adding-an-equipment-add) -- [Checking an equipment: `check`](#checking-an-equipment-check) -- [Listing equipment: `list`](#listing-equipment-list) -- [Updating an equipment: `update`](#updating-an-equipment-update) -- [Deleting an equipment: `delete`](#deleting-an-equipment-delete) -- [Saving application state: `save`](#saving-application-state-save) -- [Getting help: `help`](#getting-help-help) -- [Exiting the application: `bye`](#exiting-the-application-bye) - ### Adding an equipment: `add` Adds new Equipment to the list of Equipment. -Format: `add n/ITEM_NAME sn/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE` +Format: `add n/ITEM_NAME s/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE` * The `TYPE` must be one of the following types: MICROPHONE, SPEAKER, STAND, CABLE. * The `COST` cannot contain any symbols. @@ -77,9 +74,11 @@ output: `1. serialNumber=S1404115ASF,itemName=SpeakerB,type=SPEAKER,cost=1000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-02-23` ### Listing equipment: `list` -Print a list of all equipment in the inventory. +Print a list of all equipment in the inventory. If a parameter is supplied, only the equipment matching to the parameter will be printed. + +Format: `list [PARAMETER_NAME]` -Format: `list` +* `PARAMETER_NAME` can only take on values of `SPEAKER`, `MICROPHONE`, `STAND`, `CABLE`. Example of usage and output: @@ -89,16 +88,57 @@ output: `TOTAL QUANTITY OF EQUIPMENT: 2` -`1. serialNumber=S89347971ASF,itemName=MixerC,type=MICROPHONE,cost=2000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-01-21` +`1. serialNumber=S89347971ASF,itemName=MicrophoneC,type=MICROPHONE,cost=2000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-01-21` `2. serialNumber=S1404115ASF,itemName=SpeakerB,type=SPEAKER,cost=1000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-02-23` -### Listing equipment by type +Example of usage and output: + +`list microphone` + +output: + +`TOTAL QUANTITY OF EQUIPMENT: 1` + +`1. serialNumber=S89347971ASF,itemName=MicrophoneC,type=MICROPHONE,cost=2000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-01-21` ### Updating an equipment: `update` +Equipment can be updated with new information. Every parameter except serial number can be updated. + +Format: `update s/SERIAL_NUMBER [n/ITEM_NAME] [t/TYPE] [c/COST] [pf/PURCHASED_FROM] [pd/PURCHASED_DATE]` + +* The `TYPE` must be one of the following types: MICROPHONE, SPEAKER, STAND, CABLE. +* The `COST` cannot contain any symbols. + +Example of usage and output: + +`update s/S14115ASF c/1200 pf/AVLFX` + +output: + +`Equipment successfully updated for serial number S14115ASF,`
+`Updated details are:`
+`New cost: 1200.0`
+`New purchased from: AVLFX`
+ ### Deleting an equipment: `delete` +Removes an Equipment entry from the list of Equipment entirely. This is irreversible after the file is saved. + +Format: `update s/SERIAL_NUMBER [n/ITEM_NAME] [t/TYPE] [c/COST] [pf/PURCHASED_FROM] [pd/PURCHASED_DATE]` + +* The `TYPE` must be one of the following types: MICROPHONE, SPEAKER, STAND, CABLE. +* The `COST` cannot contain any symbols. + +Example of usage and output: + +`delete s/S14115ASF` + +output: + +`Equipment successfully deleted: SpeakerB, serial number S14115ASF` + ### Saving application state: `save` ### Getting help: `help` @@ -116,10 +156,10 @@ output: 'Cheat Sheet' of commands here * Add equipment `todo n/TODO_NAME d/DEADLINE` -* Listing equipment: -* Listing equipment by type: ADD ON HERE -* Updating an equipment: ADD ON HERE -* Deleting an equipment: ADD ON HERE +* Listing equipment: `list` +* Listing equipment by type: `list MICROPHONE` +* Updating an equipment: `update s/S14115ASF c/1200 pf/AVLFX` +* Deleting an equipment: `delete s/S14115ASF` * Saving application state: ADD ON HERE * Getting help: ADD ON HERE * Exiting the application: ADD ON HERE From 725c9011d87b89e80cb259b526b256925995917e Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 31 Mar 2022 21:54:43 +0800 Subject: [PATCH 106/229] Implement JUnit tests for delete function of app --- .../java/seedu/command/DeleteCommand.java | 12 +++++++++++ src/test/java/seedu/parser/ParserTest.java | 20 ++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/command/DeleteCommand.java b/src/main/java/seedu/command/DeleteCommand.java index 0d16992ec6..a9c1c477b4 100644 --- a/src/main/java/seedu/command/DeleteCommand.java +++ b/src/main/java/seedu/command/DeleteCommand.java @@ -42,4 +42,16 @@ public CommandResult execute() { return new CommandResult(String.format(successMessage, equipmentName, commandStrings.get(0))); } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if (!(other instanceof DeleteCommand)) { + return false; + } + DeleteCommand otherDeleteCommand = (DeleteCommand) other; + return this.commandStrings.equals(otherDeleteCommand.commandStrings); + } } diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index ce70032eae..b6eb367c63 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -4,6 +4,8 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import seedu.command.Command; +import seedu.command.DeleteCommand; +import seedu.command.IncorrectCommand; import seedu.command.ListCommand; import java.util.ArrayList; @@ -260,20 +262,32 @@ void extractArguments_noSpaceBeforeTypeSlashDelimiterFound_exceptionThrown() { } @Test - void extractArguments_wrongArgTypesUsed_exceptionThrown() throws IncompleteCommandException { + void extractArguments_wrongArgTypesUsed_exceptionThrown() { Throwable exception = assertThrows(IncompleteCommandException.class, () -> parser.extractArguments( "x/Speaker B a/Speaker b/1000 d/Loud Technologies e/2022-02-23")); assertEquals("No parameters found!", exception.getMessage()); } @Test - void parseCommand_listEnumTypeConvertedToUpper_success() throws IncompleteCommandException { + void parseCommand_listEnumTypeConvertedToUpper_success() { Command testCommand = parser.parseCommand("list spEAker"); Command expectedCommand = new ListCommand(new ArrayList<>(Collections.singleton("SPEAKER"))); assertEquals(expectedCommand, testCommand); } + @Test + void parseCommand_deleteCommand_success() { + Command testCommand = parser.parseCommand("delete s/S1234567E"); + Command expectedCommand = new DeleteCommand(new ArrayList<>(Collections.singleton("S1234567E"))); + assertEquals(expectedCommand, testCommand); + } - + @Test + void parseCommand_deleteCommand_wrongArgType_exceptionThrown() { + Command expectedCommand = new IncorrectCommand(DeleteCommand.COMMAND_WORD + + DeleteCommand.COMMAND_DESCRIPTION); + Command testCommand = parser.parseCommand("delete x/S1234567E"); + assertEquals(expectedCommand, testCommand); + } } \ No newline at end of file From e7f8d80c6b7a3665676cfa11197b22d84d57e042 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 31 Mar 2022 23:52:11 +0800 Subject: [PATCH 107/229] Improve regex detection by stripping whitespace for one argument commands --- src/main/java/seedu/parser/Parser.java | 8 ++++---- src/test/java/seedu/parser/ParserTest.java | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index ca99adda9a..41bd5602b8 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -39,9 +39,9 @@ public class Parser { + "pf\\/(?.+)" + "\\s+" + "pd\\/(?.+)" ); - public static final Pattern VIEW_COMMAND_FORMAT = Pattern.compile("[Nn]/(?.+)"); - public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("[Ss]/(?.+)"); - public static final Pattern TYPE_ENUM_FORMAT = Pattern.compile("[Tt]/(?\\w+)"); + public static final Pattern CHECK_COMMAND_FORMAT = Pattern.compile("[Nn]/(?.+)\\s*"); + public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("[Ss]/(?.+)\\s*"); + public static final Pattern TYPE_ENUM_FORMAT = Pattern.compile("[Tt]/(?\\w+)\\s*"); // ARGUMENT_FORMAT extracts first n-1 tags, for debugging: https://regex101.com/r/gwjHWD/3 public static final Pattern MODIFICATION_ARGUMENT_FORMAT = Pattern.compile( "((?:[sntcSNTC]|[pP][fF]|[pP][dD])" // argument tag @@ -229,7 +229,7 @@ protected ArrayList prepareAdd(String args) throws IncompleteCommandExce * @throws IncompleteCommandException if no match found */ protected ArrayList prepareCheck(String args) throws IncompleteCommandException { - final Matcher matcher = VIEW_COMMAND_FORMAT.matcher(args.trim()); + final Matcher matcher = CHECK_COMMAND_FORMAT.matcher(args.trim()); if (!matcher.matches()) { throw new IncompleteCommandException("View command values are incomplete or missing!"); } diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index b6eb367c63..2c85cb7cc5 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -282,6 +282,13 @@ void parseCommand_deleteCommand_success() { assertEquals(expectedCommand, testCommand); } + @Test + void parseCommand_trailingWhiteSpace_success() { + Command testCommand = parser.parseCommand("delete s/S1234567E "); + Command expectedCommand = new DeleteCommand(new ArrayList<>(Collections.singleton("S1234567E"))); + assertEquals(expectedCommand, testCommand); + } + @Test void parseCommand_deleteCommand_wrongArgType_exceptionThrown() { Command expectedCommand = new IncorrectCommand(DeleteCommand.COMMAND_WORD From a25a9bdfdb92d475622ece3f917eccf1efec74d2 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Fri, 1 Apr 2022 14:38:20 +0800 Subject: [PATCH 108/229] Add bye, help, and save commands to UserGuide --- docs/UserGuide.md | 77 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index eb50959fc8..5c87c0447f 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -141,10 +141,81 @@ output: ### Saving application state: `save` +Saves the current state of the Equipment list to the equipments.json file. + +Format: `save` + +Example of usage and output: + +`save` + +Output: + +`Successfully saved.` + ### Getting help: `help` +When `help` is called, the application will print a list of all available commands along with their usages and examples. + +Format: `help` + +Example of usage and output: + +`help` + +Output: + +`add: Adds a Equipment to the equipmentInventory.`
+`Parameters: n/ITEM_NAME s/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE`
+`Example: add n/SpeakerB s/S1404115ASF t/Speaker c/1000 pf/Loud_Technologies pd/2022-02-23` + +`delete: Deletes the equipment with the specified serial number.`
+`Parameters: s/SERIAL_NUMBER`
+`Example: delete s/SM57-1`
+ +`update: Updates the equipment with the specified serial number.`
+`Parameters in [square brackets] are optional.`
+`Parameters: s/SERIAL_NUMBER [n/ITEM_NAME] [t/TYPE] [c/COST] [pf/PURCHASED_FROM] [pd/PURCHASED_DATE]`
+`Example: update s/SM57-1 n/SpeakerC c/2510 pd/2022-08-21`
+ +`list: Prints a list of all equipment in the inventory.`
+`Parameters: NIL`
+`Example: list`
+ +`listPrints a list of all equipment in the inventory of the specified type.`
+`Parameters: t/Type`
+`Example: list MICROPHONE`
+ +`check: Gives details of the equipment with the specified name.`
+`Parameters: n/ITEM_NAME`
+`Example: check n/MixerC`
+ +`save: Saves current state of application.`
+`Parameters: NIL`
+`Example: save`
+ +`bye: Exits the application.`
+`Parameters: NIL`
+`Example: bye`
+ +`help: Shows details of available commands to users.`
+`Parameters: NIL`
+`Example: help`
+ ### Exiting the application: `bye` +Exits the application and saves the current state of the Equipment list to the equipments.json file. + +Format: `bye` + +Example of usage and output: + +`bye` + +Output: + +`Bye, See you again!` + ## FAQ **Q**: How do I transfer my data to another computer? @@ -160,6 +231,6 @@ output: * Listing equipment by type: `list MICROPHONE` * Updating an equipment: `update s/S14115ASF c/1200 pf/AVLFX` * Deleting an equipment: `delete s/S14115ASF` -* Saving application state: ADD ON HERE -* Getting help: ADD ON HERE -* Exiting the application: ADD ON HERE +* Saving application state: `save` +* Getting help: `help` +* Exiting the application: `bye` From bfc8d1f6d71820ff30d00d6499e048fc577bb888 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Mon, 4 Apr 2022 01:30:18 +0800 Subject: [PATCH 109/229] Add test case for decimal cost --- src/test/java/seedu/parser/ParserTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 2c85cb7cc5..d961e964e3 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -187,7 +187,7 @@ void prepareDelete_wrongArgumentTag_exceptionThrown() { void extractArguments_validCommands_success() throws IncompleteCommandException { ArrayList testStrings = new ArrayList<>(Arrays.asList( "s/S1404115ASF n/Speaker B t/Speaker c/1000 pf/Loud Technologies pd/2022-02-23", - "s/S1404115ASF c/1000", + "s/S1404115ASF c/1000.3", "s/S1404115ASF n/Speaker B ", "s/S1404115ASF pf/Loud Technologies n/Speaker B", "t/Speaker s/S1404115ASF", @@ -197,7 +197,7 @@ void extractArguments_validCommands_success() throws IncompleteCommandException expectedResults.add(new ArrayList<>(Arrays.asList( "s/S1404115ASF", "n/Speaker B", "t/SPEAKER", "c/1000", "pf/Loud Technologies", "pd/2022-02-23"))); expectedResults.add(new ArrayList<>(Arrays.asList( - "s/S1404115ASF", "c/1000"))); + "s/S1404115ASF", "c/1000.3"))); expectedResults.add(new ArrayList<>(Arrays.asList( "s/S1404115ASF", "n/Speaker B"))); expectedResults.add(new ArrayList<>(Arrays.asList( From b6c4fd44a89db2f2734ce3bdfaf8ed73cd0f49db Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Mon, 4 Apr 2022 01:33:36 +0800 Subject: [PATCH 110/229] Add support for float costs --- src/main/java/seedu/parser/Parser.java | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 41bd5602b8..dd1a4a64ea 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -30,23 +30,14 @@ public class Parser { * passed into arguments. */ public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s+(?.+)"); - @Deprecated - public static final Pattern ADD_COMMAND_FORMAT = Pattern.compile( - "n\\/(?.+)" + "\\s+" - + "s\\/(?.+)" + "\\s+" - + "t\\/(?.+)" + "\\s+" - + "c\\/(?.+)" + "\\s+" - + "pf\\/(?.+)" + "\\s+" - + "pd\\/(?.+)" - ); public static final Pattern CHECK_COMMAND_FORMAT = Pattern.compile("[Nn]/(?.+)\\s*"); public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("[Ss]/(?.+)\\s*"); public static final Pattern TYPE_ENUM_FORMAT = Pattern.compile("[Tt]/(?\\w+)\\s*"); - // ARGUMENT_FORMAT extracts first n-1 tags, for debugging: https://regex101.com/r/gwjHWD/3 + // ARGUMENT_FORMAT extracts first n-1 tags, for debugging: https://regex101.com/r/7rho4H/1 public static final Pattern MODIFICATION_ARGUMENT_FORMAT = Pattern.compile( "((?:[sntcSNTC]|[pP][fF]|[pP][dD])" // argument tag + "\\/" // argument delimiter - + "[\\w\\s\\-]+)" // actual argument value + + "[\\w\\s\\-\\.]+)" // actual argument value + "\\s+" // argument space before next delimiter + "(?=[sntcSNTC]|[pP][fF]|[pP][dD])" // next delimiter ); @@ -55,11 +46,20 @@ public class Parser { "(?.+)" + "\\s+" + + "s\\/(?.+)" + "\\s+" + + "t\\/(?.+)" + "\\s+" + + "c\\/(?.+)" + "\\s+" + + "pf\\/(?.+)" + "\\s+" + + "pd\\/(?.+)" + ); /** * Interpret the command requested by the user and returns a corresponding Command object. From 1e2599332f3810dc86a0d92f2056374b650b109a Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Mon, 4 Apr 2022 14:59:51 +0800 Subject: [PATCH 111/229] Fix documentation bug --- docs/UserGuide.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 5c87c0447f..35ee1a5c97 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -126,10 +126,7 @@ output: Removes an Equipment entry from the list of Equipment entirely. This is irreversible after the file is saved. -Format: `update s/SERIAL_NUMBER [n/ITEM_NAME] [t/TYPE] [c/COST] [pf/PURCHASED_FROM] [pd/PURCHASED_DATE]` - -* The `TYPE` must be one of the following types: MICROPHONE, SPEAKER, STAND, CABLE. -* The `COST` cannot contain any symbols. +Format: `delete s/SERIAL_NUMBER` Example of usage and output: @@ -226,11 +223,12 @@ Output: 'Cheat Sheet' of commands here -* Add equipment `todo n/TODO_NAME d/DEADLINE` +* Add equipment `add n/ITEM_NAME s/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE` +* Check equipment `check n/ITEM_NAME` * Listing equipment: `list` -* Listing equipment by type: `list MICROPHONE` -* Updating an equipment: `update s/S14115ASF c/1200 pf/AVLFX` -* Deleting an equipment: `delete s/S14115ASF` +* Listing equipment by type: `list t/TYPE` +* Updating an equipment: `update s/SERIAL_NUMBER [n/ITEM_NAME] [t/TYPE] [c/COST] [pf/PURCHASED_FROM] [pd/PURCHASED_DATE]` +* Deleting an equipment: `delete s/SERIAL_NUMBER` * Saving application state: `save` * Getting help: `help` * Exiting the application: `bye` From 79516b124a3aa089dc911f4d32131088e2642683 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Mon, 4 Apr 2022 15:09:40 +0800 Subject: [PATCH 112/229] Fix typo in HelpCommand --- src/main/java/seedu/command/ListCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/command/ListCommand.java b/src/main/java/seedu/command/ListCommand.java index 5e0e87990e..9ecc4b8535 100644 --- a/src/main/java/seedu/command/ListCommand.java +++ b/src/main/java/seedu/command/ListCommand.java @@ -18,7 +18,7 @@ public class ListCommand extends Command { + "Example: " + "list"; public static final String COMMAND_DESCRIPTION_WITH_TYPE = - "Prints a list of all equipment in the inventory of the specified type. " + ": Prints a list of all equipment in the inventory of the specified type. " + System.lineSeparator() + "Parameters: t/Type" + System.lineSeparator() + "Example: " From 56f26625cd888e395b6419a416c06c1c627f26fa Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Mon, 4 Apr 2022 15:19:53 +0800 Subject: [PATCH 113/229] Add autosave feature --- src/main/java/seedu/duke/Duke.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java index 9df551cde4..737af95237 100644 --- a/src/main/java/seedu/duke/Duke.java +++ b/src/main/java/seedu/duke/Duke.java @@ -14,6 +14,7 @@ public class Duke { private TextUi ui; private static EquipmentManager equipmentInventory = new EquipmentManager(); private static Storage storage = new Storage(); + private static int commandCount = 0; /** * Main entry-point for the java.duke.Duke application. @@ -46,6 +47,12 @@ private void runCommandLoop() { command = parser.parseCommand(userCommand); result = executeCommand(command); ui.showResultToUser(result); + commandCount++; + if (commandCount % 5 == 0) { + storage.saveData(equipmentInventory); + System.out.print(System.lineSeparator()); + System.out.println("Auto-saved"); + } } while (!userCommand.equals("bye")); } From 914275dda5a5e1b740ae33a94efb8d7ccbf971d0 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Mon, 4 Apr 2022 16:12:10 +0800 Subject: [PATCH 114/229] Refactor code to move deprecated methods, variables to end of class --- src/main/java/seedu/parser/Parser.java | 112 +++++++++++++------------ 1 file changed, 58 insertions(+), 54 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index dd1a4a64ea..33852f7817 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -51,15 +51,6 @@ public class Parser { public static final String MESSAGE_INCOMPLETE_COMMAND_MISSING_DELIMITER = "Please split your command into arguments with each argument seperated by spaces!"; public static final String INCORRECT_COMMAND_FORMAT = "Incorrect Command format! Enter help for more information."; - @Deprecated - public static final Pattern ADD_COMMAND_FORMAT = Pattern.compile( - "n\\/(?.+)" + "\\s+" - + "s\\/(?.+)" + "\\s+" - + "t\\/(?.+)" + "\\s+" - + "c\\/(?.+)" + "\\s+" - + "pf\\/(?.+)" + "\\s+" - + "pd\\/(?.+)" - ); /** * Interpret the command requested by the user and returns a corresponding Command object. @@ -180,47 +171,6 @@ public ArrayList splitCommandTerm(String userInput) throws IncompleteCom return resultArrayList; } - /** - * Prepare arguments for AddCommand by splitting up the arguments into different parts. - * - *

Index: - * - *

0. equipmentName : String of equipment name - * - *

1. serialNumber : String of unique serial number - * - *

2. type : String representation of enumerated class - * - *

3. cost : String representation of double value, "$" optional but "," delimiter forbidden - * - *

4. purchasedFrom : String of vendor name, suggest adhering to one consistent naming scheme - * - *

5. purchasedDate : String representation for now, possibility for future support - * - * @param args String to be split into substrings - * @return ArrayList of arguments - * @throws IncompleteCommandException if no match found - * @deprecated Use extractArguments as it is more robust in conjunction with subclasses of ModificationCommand - */ - @Deprecated - protected ArrayList prepareAdd(String args) throws IncompleteCommandException { - final Matcher matcher = ADD_COMMAND_FORMAT.matcher(args.trim()); - // validate arg string format - int matchCount = matcher.groupCount(); - if (!matcher.matches()) { - throw new IncompleteCommandException("Add command values are incomplete or missing!"); - } - ArrayList results = new ArrayList<>(); - for (int i = 1; i <= matchCount; i++) { - String result = matcher.group(i); - if (hasSlashDelimiter(result)) { - throw new IncompleteCommandException("Use of '/' for purposes other than delimiter is forbidden!"); - } - results.add(result); - } - return results; - } - /** * Prepare argument for CheckCommand by removing the preceding "n/" prefix. * @@ -293,13 +243,67 @@ protected ArrayList extractArguments(String args) throws IncompleteComma return splitArguments; } - private static boolean hasSlashDelimiter(String argument) { - return argument.contains("/"); - } - private static String setArgumentTagsToLower(String argument) { int slashIndex = argument.indexOf("/"); return argument.substring(0, slashIndex).toLowerCase(Locale.ROOT) + argument.substring(slashIndex); } + @Deprecated + public static final Pattern ADD_COMMAND_FORMAT = Pattern.compile( + "n\\/(?.+)" + "\\s+" + + "s\\/(?.+)" + "\\s+" + + "t\\/(?.+)" + "\\s+" + + "c\\/(?.+)" + "\\s+" + + "pf\\/(?.+)" + "\\s+" + + "pd\\/(?.+)" + ); + + /** + * Prepare arguments for AddCommand by splitting up the arguments into different parts. + * + *

Index: + * + *

0. equipmentName : String of equipment name + * + *

1. serialNumber : String of unique serial number + * + *

2. type : String representation of enumerated class + * + *

3. cost : String representation of double value, "$" optional but "," delimiter forbidden + * + *

4. purchasedFrom : String of vendor name, suggest adhering to one consistent naming scheme + * + *

See also {@link Parser#MODIFICATION_ARGUMENT_FORMAT} for Regex demonstration.*/ public static final Pattern MODIFICATION_ARGUMENT_TRAILING_FORMAT = Pattern.compile( "(? Date: Mon, 4 Apr 2022 22:57:04 +0800 Subject: [PATCH 117/229] Refactor code to trim strings in parseCommand --- src/main/java/seedu/parser/Parser.java | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 76d98fe2bb..bc066239a4 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -72,10 +72,14 @@ public Command parseCommand(String userInput) { return new IncorrectCommand(MESSAGE_INCOMPLETE_COMMAND_MISSING_DELIMITER); } - switch (commandAndArgument.get(0)) { + // only arguments is trimmed because commandWord is split on the first space + String commandWord = commandAndArgument.get(0); + String arguments = commandAndArgument.get(1).trim(); + + switch (commandWord) { case AddCommand.COMMAND_WORD: try { - args = extractArguments(commandAndArgument.get(1)); + args = extractArguments(arguments); return new AddCommand(args); } catch (IncompleteCommandException e) { return new IncorrectCommand(AddCommand.COMMAND_WORD + AddCommand.COMMAND_DESCRIPTION); @@ -86,21 +90,21 @@ public Command parseCommand(String userInput) { } case CheckCommand.COMMAND_WORD: try { - args = prepareCheck(commandAndArgument.get(1)); + 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(commandAndArgument.get(1)); + 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(commandAndArgument.get(1)); + args = extractArguments(arguments); return new UpdateCommand(args); } catch (IncompleteCommandException e) { return new IncorrectCommand(UpdateCommand.COMMAND_WORD + UpdateCommand.COMMAND_DESCRIPTION); @@ -110,10 +114,10 @@ public Command parseCommand(String userInput) { return new IncorrectCommand(ModificationCommand.INVALID_TYPE_MESSAGE); } case ListCommand.COMMAND_WORD: - if (commandAndArgument.get(1) == null) { + if (arguments == null) { return new ListCommand(); } else { - args = new ArrayList<>(Collections.singleton(commandAndArgument.get(1).toUpperCase(Locale.ROOT))); + args = new ArrayList<>(Collections.singleton(arguments.toUpperCase(Locale.ROOT))); return new ListCommand(args); } case HelpCommand.COMMAND_WORD: @@ -184,7 +188,7 @@ public ArrayList splitCommandTerm(String userInput) throws IncompleteCom * @throws IncompleteCommandException if no match found */ protected ArrayList prepareCheck(String args) throws IncompleteCommandException { - final Matcher matcher = CHECK_COMMAND_FORMAT.matcher(args.trim()); + final Matcher matcher = CHECK_COMMAND_FORMAT.matcher(args); if (!matcher.matches()) { throw new IncompleteCommandException("Check command values are incomplete or missing!"); } @@ -199,7 +203,7 @@ protected ArrayList prepareCheck(String args) throws IncompleteCommandEx * @throws IncompleteCommandException if no match found */ protected ArrayList prepareDelete(String args) throws IncompleteCommandException { - final Matcher matcher = DELETE_COMMAND_FORMAT.matcher(args.trim()); + final Matcher matcher = DELETE_COMMAND_FORMAT.matcher(args); if (!matcher.matches()) { throw new IncompleteCommandException("Delete command values are incomplete or missing!"); } @@ -219,7 +223,7 @@ protected ArrayList extractArguments(String args) throws IncompleteComma String argument; ArrayList splitArguments = new ArrayList<>(); try { - Matcher matcher = MODIFICATION_ARGUMENT_FORMAT.matcher(args.trim()); + Matcher matcher = MODIFICATION_ARGUMENT_FORMAT.matcher(args); while (matcher.find()) { argument = matcher.group(); argumentToAdd = setArgumentTagsToLower(argument.trim()); From e81593fca209366f11e47a2167de208f02307f1e Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Mon, 4 Apr 2022 22:57:42 +0800 Subject: [PATCH 118/229] Update javadoc for splitCommandTerm --- src/main/java/seedu/parser/Parser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index bc066239a4..00cadcb1b2 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -135,7 +135,7 @@ public Command parseCommand(String userInput) { /** * 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", remainder arguments can be empty, in which case a null + * 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. * * @param userInput String to be split into substrings From 73b98224a7164440a11c02d3922791fc1aed3d9b Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Mon, 4 Apr 2022 22:59:01 +0800 Subject: [PATCH 119/229] Improve user feedback for failed command parsing --- src/main/java/seedu/parser/Parser.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 00cadcb1b2..4ed4ce13e8 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -53,9 +53,13 @@ public class Parser { + "\\/" // argument delimiter + "([\\w\\s\\-\\.]+)" // last argument value ); - public static final String MESSAGE_INCOMPLETE_COMMAND_MISSING_DELIMITER = - "Please split your command into arguments with each argument seperated by spaces!"; - public static final String INCORRECT_COMMAND_FORMAT = "Incorrect Command format! Enter help for more information."; + public static final String INCORRECT_COMMAND_FORMAT = "Command word not recognised. " + System.lineSeparator() + + "Please use one of the following: " + + AddCommand.COMMAND_WORD + ", " + UpdateCommand.COMMAND_WORD + ", " + ListCommand.COMMAND_WORD + ", " + + CheckCommand.COMMAND_WORD + ", " + DeleteCommand.COMMAND_WORD + ", " + HelpCommand.COMMAND_WORD + ", " + + SaveCommand.COMMAND_WORD + ", " + ByeCommand.COMMAND_WORD + "."; + public static final String MISSING_COMMAND_WORD_DELIMITER = INCORRECT_COMMAND_FORMAT + System.lineSeparator() + + "If including additional arguments, please separate them with a space."; /** * Interpret the command requested by the user and returns a corresponding Command object. @@ -69,7 +73,7 @@ public Command parseCommand(String userInput) { try { commandAndArgument = splitCommandTerm(userInput); } catch (IncompleteCommandException e) { - return new IncorrectCommand(MESSAGE_INCOMPLETE_COMMAND_MISSING_DELIMITER); + return new IncorrectCommand(MISSING_COMMAND_WORD_DELIMITER); } // only arguments is trimmed because commandWord is split on the first space From f5c75474e5f05be370cceef6918a454ec519380e Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Mon, 4 Apr 2022 22:59:26 +0800 Subject: [PATCH 120/229] Fix typo with output of HelpCommand being executed Closes #81 --- docs/UserGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 35ee1a5c97..368ab9cedb 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -179,7 +179,7 @@ Output: `Parameters: NIL`
`Example: list`
-`listPrints a list of all equipment in the inventory of the specified type.`
+`list: Prints a list of all equipment in the inventory of the specified type.`
`Parameters: t/Type`
`Example: list MICROPHONE`
From 92f36868210c3b79242db8d0e9d8ce86c46f1aa2 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Mon, 4 Apr 2022 23:05:34 +0800 Subject: [PATCH 121/229] Update instructions in UserGuide on starting the application Closes #80 --- docs/UserGuide.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 368ab9cedb..d0e0c526f4 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -9,8 +9,9 @@ EquipmentManager is a Command Line Interface application to help with keeping tr 1. Ensure that you have Java 11 or above installed. 2. Download the latest version of `EquipmentManager` from [here](https://github.com/AY2122S2-CS2113-F12-2/tp/releases). 3. Copy the file to the folder you want to use as the _home folder_ for your `EquipmentManager` application. -4. Double-click the file to start the app. -5. Type `help` to see the list of available commands. +4. Open the command line and go to the folder mentioned above. +5. Run java -jar tp.jar +6. Type `help` to see the list of available commands. ## Features From 27488027d7647790ae1503947961197838d8d200 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 5 Apr 2022 01:02:57 +0800 Subject: [PATCH 122/229] Fix problem where wrong message occurs when there are missing attributes for AddCommand Fixes #90 --- src/main/java/seedu/command/AddCommand.java | 11 +++++++++-- .../java/seedu/command/ModificationCommand.java | 1 - .../seedu/parser/MissingAttributeException.java | 7 +++++++ src/main/java/seedu/parser/Parser.java | 2 ++ src/test/java/seedu/command/AddCommandTest.java | 17 ++++++++--------- .../seedu/command/ModificationCommandTest.java | 1 + 6 files changed, 27 insertions(+), 12 deletions(-) create mode 100644 src/main/java/seedu/parser/MissingAttributeException.java diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index 192176c399..902fa96efb 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -3,6 +3,7 @@ import seedu.equipment.Equipment; import seedu.equipment.DuplicateSerialNumberException; import seedu.equipment.EquipmentType; +import seedu.parser.MissingAttributeException; import java.util.ArrayList; @@ -20,18 +21,24 @@ public class AddCommand extends ModificationCommand { public static final String DUPLICATE_ITEM_ERROR = "There is already an item with this serial number: %1$s"; public static final String ATTRIBUTE_NOT_SET_ERROR = "Unable to add. " + "One or more than one of the attributes of Equipment is not specified."; + private static final int EXPECTED_NUMBER_OF_TAGS = 6; /** * constructor for AddCommand. Initialises successMessage and usageReminder from Command * * @param commandStrings parsed user input which contains details of equipment to be added */ - public AddCommand(ArrayList commandStrings) { + public AddCommand(ArrayList commandStrings) throws MissingAttributeException { super(commandStrings); successMessage = "Equipment successfully added: %1$s, serial number %2$s"; usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; - prepareModification(); + if (commandStrings.size() < EXPECTED_NUMBER_OF_TAGS) { + throw new MissingAttributeException(ATTRIBUTE_NOT_SET_ERROR); + } else { + prepareModification(); + } + } /** diff --git a/src/main/java/seedu/command/ModificationCommand.java b/src/main/java/seedu/command/ModificationCommand.java index b9695ab97c..0ea72f8fdb 100644 --- a/src/main/java/seedu/command/ModificationCommand.java +++ b/src/main/java/seedu/command/ModificationCommand.java @@ -24,7 +24,6 @@ public class ModificationCommand extends Command { public ModificationCommand(ArrayList commandStrings) { this.commandStrings = commandStrings; - prepareModification(); } public CommandResult execute() { diff --git a/src/main/java/seedu/parser/MissingAttributeException.java b/src/main/java/seedu/parser/MissingAttributeException.java new file mode 100644 index 0000000000..8147c2df6b --- /dev/null +++ b/src/main/java/seedu/parser/MissingAttributeException.java @@ -0,0 +1,7 @@ +package seedu.parser; + +public class MissingAttributeException extends Exception { + public MissingAttributeException(String message) { + super(message); + } +} diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index dd1a4a64ea..278e4b909f 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -87,6 +87,8 @@ public Command parseCommand(String userInput) { return new IncorrectCommand(ModificationCommand.INVALID_COST_MESSAGE); } catch (IllegalArgumentException e) { return new IncorrectCommand(ModificationCommand.INVALID_TYPE_MESSAGE); + } catch (MissingAttributeException e) { + return new IncorrectCommand(e.getMessage()); } case CheckCommand.COMMAND_WORD: try { diff --git a/src/test/java/seedu/command/AddCommandTest.java b/src/test/java/seedu/command/AddCommandTest.java index cdce06b0c5..be8d94898e 100644 --- a/src/test/java/seedu/command/AddCommandTest.java +++ b/src/test/java/seedu/command/AddCommandTest.java @@ -8,6 +8,7 @@ import seedu.equipment.EquipmentManager; import seedu.equipment.EquipmentType; import seedu.parser.IncompleteCommandException; +import seedu.parser.MissingAttributeException; import seedu.parser.Parser; import java.util.ArrayList; @@ -32,7 +33,8 @@ class AddCommandTest { ); @Test - void execute_duplicateSerialNumber_exceptionThrown() throws DuplicateSerialNumberException { + void execute_duplicateSerialNumber_exceptionThrown() throws DuplicateSerialNumberException, + MissingAttributeException { addCommand = new AddCommand(userInput); addCommand.setEquipmentManager(new EquipmentManager()); EquipmentManager equipmentManager = addCommand.equipmentManager; @@ -74,7 +76,7 @@ void execute_incorrectEnumType_exceptionThrown() { } @Test - void addEquipment_validArrayListString_success() throws DuplicateSerialNumberException { + void addEquipment_validArrayListString_success() throws DuplicateSerialNumberException, MissingAttributeException { addCommand = new AddCommand(userInput); addCommand.setEquipmentManager(new EquipmentManager()); EquipmentManager equipmentManager = addCommand.equipmentManager; @@ -94,7 +96,7 @@ void addEquipment_validArrayListString_success() throws DuplicateSerialNumberExc } @Test - void checkAttributes_allAttributesSet_true() { + void checkAttributes_allAttributesSet_true() throws MissingAttributeException { addCommand = new AddCommand(userInput); boolean actualResult = addCommand.checkAttributes(); @@ -102,12 +104,9 @@ void checkAttributes_allAttributesSet_true() { } @Test - void checkAttributes_oneOrMoreNulls_false() { - addCommand = new AddCommand(new ArrayList<>( + void checkAttributes_oneOrMoreNulls_false_exceptionThrown() { + assertThrows(MissingAttributeException.class, () -> new AddCommand(new ArrayList<>( Arrays.asList("n/Speaker B", "s/S1404115ASF", "t/SPEAKER", "pf/Loud Technologies") - )); - boolean actualResult = addCommand.checkAttributes(); - - assertFalse(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 index 49a89ea025..2d12f4a353 100644 --- a/src/test/java/seedu/command/ModificationCommandTest.java +++ b/src/test/java/seedu/command/ModificationCommandTest.java @@ -40,6 +40,7 @@ void prepareModification_mostRecentArgValueUsed_success() throws IncompleteComma 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); From 0266e6469fcee1e013fc114d38cb220f653ca2eb Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 5 Apr 2022 01:08:42 +0800 Subject: [PATCH 123/229] Update the error message to be more detailed when user has arguments squished together Closes #92 --- src/main/java/seedu/command/AddCommand.java | 4 +++- src/main/java/seedu/parser/Parser.java | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index 902fa96efb..95f24168a7 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -48,7 +48,9 @@ public AddCommand(ArrayList commandStrings) throws MissingAttributeExcep */ public CommandResult execute() { if (!checkAttributes()) { - return new CommandResult(ATTRIBUTE_NOT_SET_ERROR); + return new CommandResult(ATTRIBUTE_NOT_SET_ERROR + + System.lineSeparator() + + usageReminder); } try { diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 278e4b909f..e14dba1e6f 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -88,7 +88,10 @@ public Command parseCommand(String userInput) { } catch (IllegalArgumentException e) { return new IncorrectCommand(ModificationCommand.INVALID_TYPE_MESSAGE); } catch (MissingAttributeException e) { - return new IncorrectCommand(e.getMessage()); + return new IncorrectCommand(e.getMessage() + + System.lineSeparator() + + AddCommand.COMMAND_WORD + + AddCommand.COMMAND_DESCRIPTION); } case CheckCommand.COMMAND_WORD: try { From b6434996ce48f0714d00e79bb0bc09d745eeb9c8 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 5 Apr 2022 01:13:39 +0800 Subject: [PATCH 124/229] Update UserGuide on supporting of cost up to $10 million Closes #98 --- docs/UserGuide.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index d0e0c526f4..fca70564dc 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -43,6 +43,8 @@ EquipmentManager is a Command Line Interface application to help with keeping tr * Extraneous parameters for commands that do not take in parameters (such as `help`, `bye` and `save`) will be ignored.
e.g. if the command specifies `help 123`, it will be interpreted as `help`. +* The maximum cost supported is up to $10 million, any specified cost equal or greater than that will be displayed incorrectly. + ### Adding an equipment: `add` Adds new Equipment to the list of Equipment. From 1c6d7e91bd196a9cd184f6cf9de8d980bc1daa61 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 5 Apr 2022 01:39:28 +0800 Subject: [PATCH 125/229] Fix UpdateCommand not updating purchasedDate and purchasedFrom properly Fixes #102 --- src/main/java/seedu/equipment/EquipmentManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index 8141b03b35..1d7f870f71 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -123,10 +123,10 @@ public boolean updateEquipment(String serialNumber, ArrayList> u case "cost": updatedEquipment.setCost((Double) updates.getValue()); break; - case "purchaseDate": + case "purchasedDate": updatedEquipment.setPurchasedDate((String) updates.getValue()); break; - case "purchaseFrom": + case "purchasedFrom": updatedEquipment.setPurchasedFrom((String) updates.getValue()); break; default: From 699f82bf66ac64d2dd2358a54ea3157f912672d0 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 5 Apr 2022 01:48:46 +0800 Subject: [PATCH 126/229] Fix broken JUnit test for EquipmentManager --- src/test/java/seedu/equipment/EquipmentManagerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/seedu/equipment/EquipmentManagerTest.java b/src/test/java/seedu/equipment/EquipmentManagerTest.java index 51011613d9..f307d09cbe 100644 --- a/src/test/java/seedu/equipment/EquipmentManagerTest.java +++ b/src/test/java/seedu/equipment/EquipmentManagerTest.java @@ -23,8 +23,8 @@ public void updateEquipment_success() throws DuplicateSerialNumberException { 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<>("purchaseDate", "2022-03-17")); - updates.add(new Pair<>("purchaseFrom", "Louder Technologies")); + updates.add(new Pair<>("purchasedDate", "2022-03-17")); + updates.add(new Pair<>("purchasedFrom", "Louder Technologies")); equipmentManager.updateEquipment("S1404115ASF", updates); HashMap equipments = equipmentManager.getEquipmentList(); Equipment expectedEquipment = new Equipment("Speaker A", From fcb2c0d4585fa2989e1e8024dd859d7ab90c2b74 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 5 Apr 2022 02:36:41 +0800 Subject: [PATCH 127/229] Refactor Modification commands to require arguments to have backticks enclosed --- .../seedu/command/ModificationCommand.java | 3 +- .../parser/IncompleteCommandException.java | 2 + src/main/java/seedu/parser/Parser.java | 66 +++++++++++-------- .../command/ModificationCommandTest.java | 13 ++++ src/test/java/seedu/parser/ParserTest.java | 38 +++++++---- 5 files changed, 80 insertions(+), 42 deletions(-) diff --git a/src/main/java/seedu/command/ModificationCommand.java b/src/main/java/seedu/command/ModificationCommand.java index b9695ab97c..00a51f7f1d 100644 --- a/src/main/java/seedu/command/ModificationCommand.java +++ b/src/main/java/seedu/command/ModificationCommand.java @@ -3,6 +3,7 @@ import seedu.equipment.EquipmentType; import java.util.ArrayList; +import java.util.Locale; import java.util.Objects; /** @@ -81,7 +82,7 @@ protected void prepareModification() throws AssertionError, NumberFormatExceptio setPurchasedDate(argValue); break; case "t": - setEquipmentType(EquipmentType.valueOf(argValue)); + setEquipmentType(EquipmentType.valueOf(argValue.toUpperCase(Locale.ROOT))); break; case "pf": setPurchasedFrom(argValue); diff --git a/src/main/java/seedu/parser/IncompleteCommandException.java b/src/main/java/seedu/parser/IncompleteCommandException.java index fea4ab9732..9d509b9c44 100644 --- a/src/main/java/seedu/parser/IncompleteCommandException.java +++ b/src/main/java/seedu/parser/IncompleteCommandException.java @@ -1,6 +1,8 @@ package seedu.parser; public class IncompleteCommandException extends Exception { + public static final String NO_PARAMETERS_FOUND = "No parameters found!"; + public IncompleteCommandException(String message) { super(message); } diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 4ed4ce13e8..4aa8d21594 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -30,29 +30,43 @@ public class Parser { * passed into arguments. */ public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s+(?.+)"); - public static final Pattern CHECK_COMMAND_FORMAT = Pattern.compile("[Nn]/(?.+)\\s*"); - public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("[Ss]/(?.+)\\s*"); - public static final Pattern TYPE_ENUM_FORMAT = Pattern.compile("[Tt]/(?\\w+)\\s*"); + public static final Pattern CHECK_COMMAND_FORMAT = Pattern.compile("[Nn]/(?.+)"); + public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("[Ss]/(?.+)"); + + /** + * Defines regex used to match argument pairs in the command line. + * + *

An argument pair is defined as an argument tag, a slash "/", minimally a backtick "`", + * an argument value and minimally a final backtick "`". + * + *

See also {@link Parser#MODIFICATION_ARGUMENT_FORMAT} for Regex use and demonstration. + */ + private static final String ARGUMENT_PAIR_REGEX = + "(?:[sntcSNTC]|[pP][fF]|[pP][dD])" // non-capturing group for argument tag + + "\\/" // argument delimiter + + "`+" // backticks to enclose string + + "[\\w\\s\\-\\.]+" // actual argument value + + "`+"; // backticks to enclose string /** * Extracts first n-1 tags for debugging and assumes that the last tag contains the whole string, refer to: - * Regex101 for demo.*/ + * Regex101 for demo. + */ public static final Pattern MODIFICATION_ARGUMENT_FORMAT = Pattern.compile( - "((?:[sntcSNTC]|[pP][fF]|[pP][dD])" // argument tag - + "\\/" // argument delimiter - + "[\\w\\s\\-\\.]+)" // actual argument value + "(" + ARGUMENT_PAIR_REGEX + ")" + "\\s+" // argument space before next delimiter - + "(?=[sntcSNTC]|[pP][fF]|[pP][dD])" // next delimiter + + "(?=[sntcSNTC]|[pP][fF]|[pP][dD])" // positive lookahead to mandate next delimiter ); /** * Extracts last tag for debugging. * - *

See also {@link Parser#MODIFICATION_ARGUMENT_FORMAT} for Regex demonstration.*/ + *

See also {@link Parser#MODIFICATION_ARGUMENT_FORMAT} for Regex use and demonstration. + */ public static final Pattern MODIFICATION_ARGUMENT_TRAILING_FORMAT = Pattern.compile( - "(? extractArguments(String args) throws IncompleteComma Matcher matcher = MODIFICATION_ARGUMENT_FORMAT.matcher(args); while (matcher.find()) { argument = matcher.group(); - argumentToAdd = setArgumentTagsToLower(argument.trim()); + argumentToAdd = reformatArgumentPair(argument.trim()); splitArguments.add(argumentToAdd); lastIndex = matcher.end(); } matcher.usePattern(MODIFICATION_ARGUMENT_TRAILING_FORMAT); matcher.find(lastIndex); argument = matcher.group(); - argumentToAdd = setArgumentTagsToLower(argument.trim()); + argumentToAdd = reformatArgumentPair(argument.trim()); splitArguments.add(argumentToAdd); } catch (IllegalStateException e) { - throw new IncompleteCommandException("No parameters found!"); - } - - for (int i = splitArguments.size() - 1; i >= 0; i--) { - String argumentPair = splitArguments.get(i); - Matcher matcher = TYPE_ENUM_FORMAT.matcher(argumentPair); - if (matcher.matches()) { - splitArguments.remove(argumentPair); - splitArguments.add("t/" + matcher.group("equipmentType").toUpperCase(Locale.ROOT)); - return splitArguments; - } + throw new IncompleteCommandException(IncompleteCommandException.NO_PARAMETERS_FOUND); } return splitArguments; } - private static String setArgumentTagsToLower(String argument) { + private static String reformatArgumentPair(String argument) { int slashIndex = argument.indexOf("/"); - return argument.substring(0, slashIndex).toLowerCase(Locale.ROOT) + argument.substring(slashIndex); + String newString = argument.substring(0, slashIndex).toLowerCase(Locale.ROOT) + argument.substring(slashIndex); + return newString.replace("`", ""); } @Deprecated diff --git a/src/test/java/seedu/command/ModificationCommandTest.java b/src/test/java/seedu/command/ModificationCommandTest.java index 49a89ea025..5fd18833eb 100644 --- a/src/test/java/seedu/command/ModificationCommandTest.java +++ b/src/test/java/seedu/command/ModificationCommandTest.java @@ -44,4 +44,17 @@ void prepareModification_mostRecentArgValueUsed_success() throws IncompleteComma 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") + )); + ModificationCommand actualCommand = new ModificationCommand(testArrayList); + actualCommand.prepareModification(); + assertEquals(expectedCommand, actualCommand); + } + } \ No newline at end of file diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 5bdc5d89f8..92c061b4f9 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -29,10 +29,12 @@ void setup() { @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") + 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"); + "add n/`ITEM_NAME` s/`SERIAL_NUMBER` t/`TYPE` c/`COST` pf/`PURCHASED_FROM` " + + "pd/`PURCHASED_DATE`"); assertEquals(expectedResult, actualResult); assertEquals(expectedResult.get(0), actualResult.get(0)); assertEquals(expectedResult.get(1), actualResult.get(1)); @@ -41,11 +43,12 @@ void splitCommandTerm_validCommand_success() throws IncompleteCommandException { @Test void splitCommandTerm_noSpaceDelimiter_exceptionThrown() { ArrayList unexpectedResult = new ArrayList<>( - Arrays.asList("add", "n/ITEM_NAMEs/SERIAL_NUMBERt/TYPEc/COSTpf/PURCHASED_FROMpd/PURCHASED_DATE") + 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_NAMEs/SERIAL_NUMBERt/TYPEc/COSTpf/PURCHASED_FROMpd/PURCHASED_DATE"); + "addn/`ITEM_NAME`s/`SERIAL_NUMBER`t/`TYPE`c/`COST`pf/`PURCHASED_FROM`pd/`PURCHASED_DATE`"); assertEquals(unexpectedResult, actualResult); fail(); } catch (IncompleteCommandException e) { @@ -139,7 +142,7 @@ void prepareCheck_viewStringWithSpaces_success() throws IncompleteCommandExcepti Arrays.asList("Speaker B") ); ArrayList actualResult = parser.prepareCheck( - " n/Speaker B "); + "n/Speaker B"); assertEquals(expectedResult, actualResult); } @@ -164,7 +167,7 @@ void prepareDelete_deleteStringWithSpaces_success() throws IncompleteCommandExce Arrays.asList("SM58-1") ); ArrayList actualResult = parser.prepareDelete( - " s/SM58-1 "); + "s/SM58-1"); assertEquals(expectedResult, actualResult); } @@ -175,7 +178,7 @@ void prepareDelete_wrongArgumentTag_exceptionThrown() { ); try { ArrayList actualResult = parser.prepareDelete( - " n/Speaker B "); + "n/Speaker B"); assertEquals(expectedResult, actualResult); fail(); } catch (IncompleteCommandException e) { @@ -183,6 +186,7 @@ void prepareDelete_wrongArgumentTag_exceptionThrown() { } } + @Disabled @Test void extractArguments_validCommands_success() throws IncompleteCommandException { ArrayList testStrings = new ArrayList<>(Arrays.asList( @@ -215,6 +219,7 @@ void extractArguments_validCommands_success() throws IncompleteCommandException } } + @Disabled @Test void extractArguments_mixedCaseText_success() throws IncompleteCommandException { ArrayList testStrings = new ArrayList<>(Arrays.asList( @@ -250,22 +255,31 @@ void extractArguments_mixedCaseText_success() throws IncompleteCommandException @Test void extractArguments_noSpaceBeforeTypeSlashDelimiterFound_exceptionThrown() { ArrayList expectedResult = new ArrayList<>(Arrays.asList( - "x/Speaker B", "t/Speaker", "c/1000", "pf/Loud Technologies", "pd/2022-02-23")); + "n/Speaker B", "t/Speaker", "c/1000", "pf/Loud Technologies", "pd/2022-02-23")); try { ArrayList actualResult = parser.extractArguments( - "x/Speaker Bt/Speakerc/1000pf/Loud Technologiespd/2022-02-23"); + "n/`Speaker B`t/`Speaker`c/`1000`pf/`Loud Technologies`pd/`2022-02-23`"); assertEquals(expectedResult, actualResult); fail(); } catch (IncompleteCommandException e) { - assertEquals("No parameters found!", e.getMessage()); + 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_wrongArgTypesUsed_exceptionThrown() { Throwable exception = assertThrows(IncompleteCommandException.class, () -> parser.extractArguments( - "x/Speaker B a/Speaker b/1000 d/Loud Technologies e/2022-02-23")); - assertEquals("No parameters found!", exception.getMessage()); + "x/`Speaker B` a/`Speaker` b/`1000` d/`Loud Technologies` e/`2022-02-23`")); + assertEquals(IncompleteCommandException.NO_PARAMETERS_FOUND, exception.getMessage()); } @Test From 97449e55e845ab0cf6c1f35ac7af7d6e027cf020 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 5 Apr 2022 02:57:03 +0800 Subject: [PATCH 128/229] Update test cases to reflect shift trim() to parseCommand --- src/test/java/seedu/parser/ParserTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 5bdc5d89f8..92dab11adf 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -139,7 +139,7 @@ void prepareCheck_viewStringWithSpaces_success() throws IncompleteCommandExcepti Arrays.asList("Speaker B") ); ArrayList actualResult = parser.prepareCheck( - " n/Speaker B "); + "n/Speaker B"); assertEquals(expectedResult, actualResult); } @@ -161,10 +161,10 @@ void prepareCheck_wrongArgumentTag_exceptionThrown() { @Test void prepareDelete_deleteStringWithSpaces_success() throws IncompleteCommandException { ArrayList expectedResult = new ArrayList<>( - Arrays.asList("SM58-1") + Arrays.asList("SM58 - 1") ); ArrayList actualResult = parser.prepareDelete( - " s/SM58-1 "); + "s/SM58 - 1"); assertEquals(expectedResult, actualResult); } @@ -175,7 +175,7 @@ void prepareDelete_wrongArgumentTag_exceptionThrown() { ); try { ArrayList actualResult = parser.prepareDelete( - " n/Speaker B "); + "n/Speaker B"); assertEquals(expectedResult, actualResult); fail(); } catch (IncompleteCommandException e) { From 83ab598f0fd0bdf2588ead3228c9c928586450c3 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 5 Apr 2022 03:22:21 +0800 Subject: [PATCH 129/229] Update prepareCheck, prepareDelete to align with new backtick syntax --- src/main/java/seedu/parser/Parser.java | 16 +++-- src/test/java/seedu/parser/ParserTest.java | 82 +++++++++++++++++++--- 2 files changed, 81 insertions(+), 17 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 4aa8d21594..297a912aa8 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -30,8 +30,8 @@ public class Parser { * passed into arguments. */ public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s+(?.+)"); - public static final Pattern CHECK_COMMAND_FORMAT = Pattern.compile("[Nn]/(?.+)"); - public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("[Ss]/(?.+)"); + public static final Pattern CHECK_COMMAND_FORMAT = Pattern.compile("^(?[Nn]/`.+`)$"); + public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("^(?[Ss]/`.+`)$"); /** * Defines regex used to match argument pairs in the command line. @@ -202,7 +202,8 @@ public ArrayList splitCommandTerm(String userInput) throws IncompleteCom } /** - * Prepare argument for CheckCommand by removing the preceding "n/" prefix. + * Prepare argument for CheckCommand by matching the preceding "n/" prefix, setting it to lowercase 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) @@ -213,11 +214,13 @@ protected ArrayList prepareCheck(String args) throws IncompleteCommandEx if (!matcher.matches()) { throw new IncompleteCommandException("Check command values are incomplete or missing!"); } - return new ArrayList<>(Collections.singleton(matcher.group("itemName"))); + String argumentPair = reformatArgumentPair(matcher.group("itemName")); + return new ArrayList<>(Collections.singleton(argumentPair)); } /** - * Prepare argument for DeleteCommand by removing the preceding "s/" prefix. + * Prepare argument for DeleteCommand by matching the preceding "s/" prefix, setting it to lowercase 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) @@ -228,7 +231,8 @@ protected ArrayList prepareDelete(String args) throws IncompleteCommandE if (!matcher.matches()) { throw new IncompleteCommandException("Delete command values are incomplete or missing!"); } - return new ArrayList<>(Collections.singleton(matcher.group("serialNumber"))); + String argumentPair = reformatArgumentPair(matcher.group("serialNumber")); + return new ArrayList<>(Collections.singleton(argumentPair)); } /** diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 92c061b4f9..5c6220a685 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -139,21 +139,51 @@ void prepareAdd_argumentIncludesSlashB_exceptionThrown() { @Test void prepareCheck_viewStringWithSpaces_success() throws IncompleteCommandException { ArrayList expectedResult = new ArrayList<>( - Arrays.asList("Speaker B") + Arrays.asList("n/Speaker B") ); ArrayList actualResult = parser.prepareCheck( - "n/Speaker B"); + "n/`Speaker B`"); assertEquals(expectedResult, actualResult); } @Test void prepareCheck_wrongArgumentTag_exceptionThrown() { ArrayList expectedResult = new ArrayList<>( - Arrays.asList("Speaker B") + Arrays.asList("s/Speaker B") ); try { ArrayList actualResult = parser.prepareCheck( - "s/Speaker B"); + "s/`Speaker B`"); + assertEquals(expectedResult, actualResult); + fail(); + } catch (IncompleteCommandException e) { + assertEquals("Check command values are incomplete or missing!", e.getMessage()); + } + } + + @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) { @@ -164,17 +194,17 @@ void prepareCheck_wrongArgumentTag_exceptionThrown() { @Test void prepareDelete_deleteStringWithSpaces_success() throws IncompleteCommandException { ArrayList expectedResult = new ArrayList<>( - Arrays.asList("SM58-1") + Arrays.asList("s/SM58 - 1") ); ArrayList actualResult = parser.prepareDelete( - "s/SM58-1"); + "s/`SM58 - 1`"); assertEquals(expectedResult, actualResult); } @Test void prepareDelete_wrongArgumentTag_exceptionThrown() { ArrayList expectedResult = new ArrayList<>( - Arrays.asList("Speaker B") + Arrays.asList("n/Speaker B") ); try { ArrayList actualResult = parser.prepareDelete( @@ -186,6 +216,36 @@ void prepareDelete_wrongArgumentTag_exceptionThrown() { } } + @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()); + } + } + @Disabled @Test void extractArguments_validCommands_success() throws IncompleteCommandException { @@ -291,15 +351,15 @@ void parseCommand_listEnumTypeConvertedToUpper_success() { @Test void parseCommand_deleteCommand_success() { - Command testCommand = parser.parseCommand("delete s/S1234567E"); - Command expectedCommand = new DeleteCommand(new ArrayList<>(Collections.singleton("S1234567E"))); + 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("S1234567E"))); + Command testCommand = parser.parseCommand("delete s/`S1234567E` "); + Command expectedCommand = new DeleteCommand(new ArrayList<>(Collections.singleton("s/S1234567E"))); assertEquals(expectedCommand, testCommand); } From 61085ef93a593b2dceccea93eb41cd5fbab3cf54 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 5 Apr 2022 04:14:06 +0800 Subject: [PATCH 130/229] Update regex101 link --- src/main/java/seedu/parser/Parser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 297a912aa8..c5bcc3de7b 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -49,7 +49,7 @@ public class Parser { + "`+"; // backticks to enclose string /** * Extracts first n-1 tags for debugging and assumes that the last tag contains the whole string, refer to: - * Regex101 for demo. + * Regex101 for demo. */ public static final Pattern MODIFICATION_ARGUMENT_FORMAT = Pattern.compile( "(" + ARGUMENT_PAIR_REGEX + ")" From 76ade6dfb3da3e390fa286c3088850808207d5ec Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 5 Apr 2022 04:35:12 +0800 Subject: [PATCH 131/229] Update command help tips to include backtick requirement --- src/main/java/seedu/command/AddCommand.java | 4 ++-- src/main/java/seedu/command/ListCommand.java | 2 +- src/main/java/seedu/command/UpdateCommand.java | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/command/AddCommand.java b/src/main/java/seedu/command/AddCommand.java index 192176c399..efd5bbce50 100644 --- a/src/main/java/seedu/command/AddCommand.java +++ b/src/main/java/seedu/command/AddCommand.java @@ -13,10 +13,10 @@ public class AddCommand extends ModificationCommand { public static final String COMMAND_WORD = "add"; public static final String COMMAND_DESCRIPTION = ": Adds a Equipment to the equipmentInventory. " + System.lineSeparator() - + "Parameters: n/ITEM_NAME s/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE" + + "Parameters: n/`ITEM NAME` s/`SERIAL NUMBER` t/`TYPE` c/`COST` pf/`PURCHASED FROM` pd/`PURCHASED DATE`" + System.lineSeparator() + "Example: " - + "add n/SpeakerB s/S1404115ASF t/Speaker c/1000 pf/Loud_Technologies pd/2022-02-23"; + + "add n/`SpeakerB` s/`S1404115ASF` t/`Speaker` c/`1000` pf/`Loud_Technologies` pd/`2022-02-23`"; public static final String DUPLICATE_ITEM_ERROR = "There is already an item with this serial number: %1$s"; public static final String ATTRIBUTE_NOT_SET_ERROR = "Unable to add. " + "One or more than one of the attributes of Equipment is not specified."; diff --git a/src/main/java/seedu/command/ListCommand.java b/src/main/java/seedu/command/ListCommand.java index 9ecc4b8535..ee1b031e5c 100644 --- a/src/main/java/seedu/command/ListCommand.java +++ b/src/main/java/seedu/command/ListCommand.java @@ -20,7 +20,7 @@ public class ListCommand extends Command { public static final String COMMAND_DESCRIPTION_WITH_TYPE = ": Prints a list of all equipment in the inventory of the specified type. " + System.lineSeparator() - + "Parameters: t/Type" + System.lineSeparator() + + "Parameters: `Type`" + System.lineSeparator() + "Example: " + "list MICROPHONE"; diff --git a/src/main/java/seedu/command/UpdateCommand.java b/src/main/java/seedu/command/UpdateCommand.java index 0ded8dbea1..20f91c30ca 100644 --- a/src/main/java/seedu/command/UpdateCommand.java +++ b/src/main/java/seedu/command/UpdateCommand.java @@ -12,10 +12,11 @@ public class UpdateCommand extends ModificationCommand { + System.lineSeparator() + "Parameters in [square brackets] are optional." + System.lineSeparator() - + "Parameters: s/SERIAL_NUMBER [n/ITEM_NAME] [t/TYPE] [c/COST] [pf/PURCHASED_FROM] [pd/PURCHASED_DATE]" + + "Parameters: s/`SERIAL NUMBER` [n/`ITEM NAME`] [t/`TYPE`] [c/`COST`] [pf/`PURCHASED FROM`] " + + "[pd/`PURCHASED DATE`]" + System.lineSeparator() + "Example: " - + "update s/SM57-1 n/SpeakerC c/2510 pd/2022-08-21"; + + "update s/`SM57-1` n/`SpeakerC` c/`2510` pd/`2022-08-21`"; /** From 9e0b760e02a00e123acf98268104f6de2ce46b63 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 5 Apr 2022 16:01:39 +0800 Subject: [PATCH 132/229] Update check command to allow any argument pair, but just one. --- src/main/java/seedu/parser/Parser.java | 2 +- src/test/java/seedu/parser/ParserTest.java | 13 ++++--------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index c5bcc3de7b..31882e86c9 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -30,7 +30,6 @@ public class Parser { * passed into arguments. */ public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s+(?.+)"); - public static final Pattern CHECK_COMMAND_FORMAT = Pattern.compile("^(?[Nn]/`.+`)$"); public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("^(?[Ss]/`.+`)$"); /** @@ -67,6 +66,7 @@ public class Parser { + "$" // require end of string ); + public static final Pattern CHECK_COMMAND_FORMAT = Pattern.compile("^(?" + ARGUMENT_PAIR_REGEX + ")$"); public static final String INCORRECT_COMMAND_FORMAT = "Command word not recognised. " + System.lineSeparator() + "Please use one of the following: " + AddCommand.COMMAND_WORD + ", " + UpdateCommand.COMMAND_WORD + ", " + ListCommand.COMMAND_WORD + ", " diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 5c6220a685..d68996b7a9 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -147,18 +147,13 @@ void prepareCheck_viewStringWithSpaces_success() throws IncompleteCommandExcepti } @Test - void prepareCheck_wrongArgumentTag_exceptionThrown() { + void prepareCheck_checkUsingSerialNum_success() throws IncompleteCommandException { ArrayList expectedResult = new ArrayList<>( Arrays.asList("s/Speaker B") ); - try { - ArrayList actualResult = parser.prepareCheck( - "s/`Speaker B`"); - assertEquals(expectedResult, actualResult); - fail(); - } catch (IncompleteCommandException e) { - assertEquals("Check command values are incomplete or missing!", e.getMessage()); - } + ArrayList actualResult = parser.prepareCheck( + "s/`Speaker B`"); + assertEquals(expectedResult, actualResult); } @Test From 7393dbd1bada0f76466c10f3d27b9d324a8a5655 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Tue, 5 Apr 2022 16:02:11 +0800 Subject: [PATCH 133/229] Refine delete command to accept a more narrow range of characters --- src/main/java/seedu/parser/Parser.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 31882e86c9..5f8271fea6 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -30,7 +30,6 @@ public class Parser { * passed into arguments. */ public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s+(?.+)"); - public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("^(?[Ss]/`.+`)$"); /** * Defines regex used to match argument pairs in the command line. @@ -67,6 +66,12 @@ public class Parser { ); public static final Pattern CHECK_COMMAND_FORMAT = Pattern.compile("^(?" + ARGUMENT_PAIR_REGEX + ")$"); + public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("^(?" + "[Ss]" + + "\\/" // argument delimiter + + "`+" // backticks to enclose string + + "[\\w\\s\\-\\.]+" // actual argument value + + "`+" // backticks to enclose string + + ")$"); public static final String INCORRECT_COMMAND_FORMAT = "Command word not recognised. " + System.lineSeparator() + "Please use one of the following: " + AddCommand.COMMAND_WORD + ", " + UpdateCommand.COMMAND_WORD + ", " + ListCommand.COMMAND_WORD + ", " From 70c957641e6b7cd4101d29e72368ce3441bc964b Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 5 Apr 2022 16:32:10 +0800 Subject: [PATCH 134/229] Fix broken JUnit test in ModificationCommandTest --- src/test/java/seedu/command/ModificationCommandTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/seedu/command/ModificationCommandTest.java b/src/test/java/seedu/command/ModificationCommandTest.java index 29d3562681..bacabee74d 100644 --- a/src/test/java/seedu/command/ModificationCommandTest.java +++ b/src/test/java/seedu/command/ModificationCommandTest.java @@ -53,6 +53,7 @@ void prepareModification_typeEnumsChangedToCaps_success() throws IncompleteComma ModificationCommand expectedCommand = new ModificationCommand(new ArrayList<>( Arrays.asList("s/S1404115ASF", "t/SPEAKER", "n/Speaker A") )); + expectedCommand.prepareModification(); ModificationCommand actualCommand = new ModificationCommand(testArrayList); actualCommand.prepareModification(); assertEquals(expectedCommand, actualCommand); From 3fad73720917faa3976da6f29bbdd04beb1fd842 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Tue, 5 Apr 2022 16:46:39 +0800 Subject: [PATCH 135/229] Change CheckCommand#execute to pass a Pair to EquipmentManager#checkEquipment instead of a String. --- src/main/java/seedu/command/CheckCommand.java | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index 88502f8963..d43647bc71 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -1,8 +1,11 @@ package seedu.command; +import seedu.Pair; import seedu.equipment.Equipment; +import seedu.equipment.EquipmentType; import java.util.ArrayList; +import java.util.Locale; /** * Subclass of Command. Handles checking of details of a specified equipment from equipmentInventory. @@ -33,8 +36,52 @@ public CheckCommand(ArrayList commandStrings) { * @return CommandResult with message from execution of this command */ public CommandResult execute() { - ArrayList equipment = equipmentManager.checkEquipment(commandStrings.get(0)); + Pair checkPair = generateCheckPair(); + ArrayList equipment = equipmentManager.checkEquipment(checkPair); return new CommandResult(String.format(successMessage, commandStrings.get(0)), equipment); } + + /** + * Generates a Pair containing the attribute for the check to be based on. + * Pair is a class that was implemented to match each attribute to its value. + * By using pair, we are able to specify the attribute to be checked. + * @return Pair of value to be checked and its matching attribute. + */ + public Pair generateCheckPair() { + Pair pair = null; + + for (String s : commandStrings) { + int delimiterPos = s.indexOf('/'); + // the case where delimiterPos = -1 is impossible as + // ARGUMENT_FORMAT and ARGUMENT_TRAILING_FORMAT regex requires a '/' + assert delimiterPos != -1 : "Each args will need to include minimally a '/' to split arg and value upon"; + String argType = s.substring(0, delimiterPos); + String argValue = s.substring(delimiterPos + 1); + switch (argType) { + case "n": + pair = new Pair<>("itemName", commandStrings.get(0)); + break; + case "pd": + pair = new Pair<>("purchasedDate", commandStrings.get(0)); + break; + case "t": + pair = new Pair<>("type", commandStrings.get(0)); + break; + case "pf": + pair = new Pair<>("purchasedFrom", commandStrings.get(0)); + break; + case "c": + pair = new Pair<>("cost", commandStrings.get(0)); + break; + case "s": + pair = new Pair<>("serialNumber", commandStrings.get(0)); + break; + default: + System.out.println("`" + argValue + "` not accepted for type " + argType + ": Unrecognised Tag"); + } + } + + return pair; + } } From 6e0cd553f2b2edaaad078804ffbb7efb3f350363 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Wed, 6 Apr 2022 00:11:30 +0800 Subject: [PATCH 136/229] Fix some broken JUnit tests --- .../java/seedu/command/DeleteCommand.java | 34 ++++++++++++++++--- .../java/seedu/command/DeleteCommandTest.java | 2 +- .../command/ModificationCommandTest.java | 1 + 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/command/DeleteCommand.java b/src/main/java/seedu/command/DeleteCommand.java index a9c1c477b4..e09807668d 100644 --- a/src/main/java/seedu/command/DeleteCommand.java +++ b/src/main/java/seedu/command/DeleteCommand.java @@ -1,6 +1,9 @@ package seedu.command; +import seedu.equipment.EquipmentType; + import java.util.ArrayList; +import java.util.Locale; /** * Subclass of Command. Handles deleting of equipment from equipmentInventory. @@ -13,6 +16,7 @@ public class DeleteCommand extends Command { + "Parameters: s/SERIAL_NUMBER" + System.lineSeparator() + "Example: " + "delete s/SM57-1"; + public static final String ONLY_SN_ACCEPTED = "Only serial number accepted for deleting equipment"; /** * constructor for DeleteCommand. Initialises successMessage and usageReminder from Command. @@ -31,16 +35,23 @@ public DeleteCommand(ArrayList commandStrings) { * @return CommandResult with message from execution of this command */ public CommandResult execute() { - String equipmentName; + String equipmentName, serialNumber; + try { - equipmentName = equipmentManager.getEquipmentList().get(commandStrings.get(0)).getItemName(); + serialNumber = prepareDelete(); + if (serialNumber.equals("")) { + return new CommandResult(ONLY_SN_ACCEPTED); + } + equipmentName = equipmentManager.getEquipmentList().get(serialNumber).getItemName(); } catch (NullPointerException e) { return new CommandResult(INVALID_SERIAL_NUMBER); + } catch (AssertionError e) { + return new CommandResult(ONLY_SN_ACCEPTED); } - equipmentManager.deleteEquipment(commandStrings.get(0)); + equipmentManager.deleteEquipment(serialNumber); - return new CommandResult(String.format(successMessage, equipmentName, commandStrings.get(0))); + return new CommandResult(String.format(successMessage, equipmentName, serialNumber)); } @Override @@ -54,4 +65,19 @@ public boolean equals(Object other) { DeleteCommand otherDeleteCommand = (DeleteCommand) other; return this.commandStrings.equals(otherDeleteCommand.commandStrings); } + + protected String prepareDelete() throws AssertionError { + String argString = commandStrings.get(0); + int delimiterPos = argString.indexOf('/'); + // the case where delimiterPos = -1 is impossible as + // ARGUMENT_FORMAT and ARGUMENT_TRAILING_FORMAT regex requires a '/' + assert delimiterPos != -1 : "Each args will need to include minimally a '/' to split arg and value upon"; + String argType = argString.substring(0, delimiterPos); + String argValue = argString.substring(delimiterPos + 1); + assert argType.equals("s") : ONLY_SN_ACCEPTED; + if (argType.equals("s")) { + return argValue; + } + return ""; + } } diff --git a/src/test/java/seedu/command/DeleteCommandTest.java b/src/test/java/seedu/command/DeleteCommandTest.java index e8034eae8e..f93de372fd 100644 --- a/src/test/java/seedu/command/DeleteCommandTest.java +++ b/src/test/java/seedu/command/DeleteCommandTest.java @@ -17,7 +17,7 @@ class DeleteCommandTest { @Test void execute_validSerialNumber_success() { deleteCommand = new DeleteCommand(new ArrayList<>( - Arrays.asList("S1404115ASF") + Arrays.asList("s/S1404115ASF") )); deleteCommand.setEquipmentManager(new EquipmentManager()); EquipmentManager equipmentManager = deleteCommand.equipmentManager; diff --git a/src/test/java/seedu/command/ModificationCommandTest.java b/src/test/java/seedu/command/ModificationCommandTest.java index 29d3562681..bacabee74d 100644 --- a/src/test/java/seedu/command/ModificationCommandTest.java +++ b/src/test/java/seedu/command/ModificationCommandTest.java @@ -53,6 +53,7 @@ void prepareModification_typeEnumsChangedToCaps_success() throws IncompleteComma ModificationCommand expectedCommand = new ModificationCommand(new ArrayList<>( Arrays.asList("s/S1404115ASF", "t/SPEAKER", "n/Speaker A") )); + expectedCommand.prepareModification(); ModificationCommand actualCommand = new ModificationCommand(testArrayList); actualCommand.prepareModification(); assertEquals(expectedCommand, actualCommand); From 04f3dc7a3b3f461452db2a81c02d5d8340f42923 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Wed, 6 Apr 2022 01:20:17 +0800 Subject: [PATCH 137/229] Add JUnit tests for DeleteCommand --- .../java/seedu/command/DeleteCommand.java | 4 ++- .../java/seedu/command/DeleteCommandTest.java | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/command/DeleteCommand.java b/src/main/java/seedu/command/DeleteCommand.java index e09807668d..b15b13ae2e 100644 --- a/src/main/java/seedu/command/DeleteCommand.java +++ b/src/main/java/seedu/command/DeleteCommand.java @@ -35,7 +35,8 @@ public DeleteCommand(ArrayList commandStrings) { * @return CommandResult with message from execution of this command */ public CommandResult execute() { - String equipmentName, serialNumber; + String equipmentName; + String serialNumber; try { serialNumber = prepareDelete(); @@ -66,6 +67,7 @@ public boolean equals(Object other) { return this.commandStrings.equals(otherDeleteCommand.commandStrings); } + protected String prepareDelete() throws AssertionError { String argString = commandStrings.get(0); int delimiterPos = argString.indexOf('/'); diff --git a/src/test/java/seedu/command/DeleteCommandTest.java b/src/test/java/seedu/command/DeleteCommandTest.java index f93de372fd..3088f2b8b7 100644 --- a/src/test/java/seedu/command/DeleteCommandTest.java +++ b/src/test/java/seedu/command/DeleteCommandTest.java @@ -41,4 +41,33 @@ void execute_validSerialNumber_success() { 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("No such serial number, please enter an existing " + + "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 serial number accepted for deleting equipment"); + + assertEquals(expectedResult, actualResult); + } } \ No newline at end of file From f57d3aa923253fe21e83fb8b13ffd2ec601c8102 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Wed, 6 Apr 2022 01:41:23 +0800 Subject: [PATCH 138/229] Update messages to show backticks in examples of Commands usage --- docs/UserGuide.md | 44 +++++++++---------- src/main/java/seedu/command/CheckCommand.java | 4 +- .../java/seedu/command/DeleteCommand.java | 4 +- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index fca70564dc..1f8b0a85c8 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -48,27 +48,27 @@ EquipmentManager is a Command Line Interface application to help with keeping tr ### Adding an equipment: `add` Adds new Equipment to the list of Equipment. -Format: `add n/ITEM_NAME s/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE` +Format: ``add n/`ITEM_NAME` s/`SERIAL_NUMBER` t/`TYPE c/COST` pf/`PURCHASED_FROM` pd/`PURCHASED_DATE` `` * The `TYPE` must be one of the following types: MICROPHONE, SPEAKER, STAND, CABLE. * The `COST` cannot contain any symbols. Example of usage and output: -`add n/SpeakerB s/S1404115ASF t/Speaker c/1000 pf/Loud_Technologies pd/2022-02-23` +``add n/`SpeakerB` s/`S1404115ASF` t/`Speaker` c/`1000` pf/`Loud_Technologies` pd/`2022-02-23` `` output: `Equipment successfully added: SpeakerB, serial number S1404115ASF` ### Checking an equipment: `check` Check the details of the equipment that has the name specified. -Format: `check n/ITEM_NAME` +Format: ``check n/`ITEM_NAME` `` * Only the `ITEM_NAME` can be used to check for a piece of equipment. Example of usage and output: -`check n/SpeakerB` +``check n/`SpeakerB` `` output: @@ -109,14 +109,14 @@ output: Equipment can be updated with new information. Every parameter except serial number can be updated. -Format: `update s/SERIAL_NUMBER [n/ITEM_NAME] [t/TYPE] [c/COST] [pf/PURCHASED_FROM] [pd/PURCHASED_DATE]` +Format: ``update s/`SERIAL_NUMBER` [n/`ITEM_NAME`] [t/`TYPE`] [c/`COST`] [pf/`PURCHASED_FROM`] [pd/`PURCHASED_DATE`]`` * The `TYPE` must be one of the following types: MICROPHONE, SPEAKER, STAND, CABLE. * The `COST` cannot contain any symbols. Example of usage and output: -`update s/S14115ASF c/1200 pf/AVLFX` +``update s/`S14115ASF` c/`1200` pf/`AVLFX` `` output: @@ -129,11 +129,11 @@ output: Removes an Equipment entry from the list of Equipment entirely. This is irreversible after the file is saved. -Format: `delete s/SERIAL_NUMBER` +Format: ``delete s/`SERIAL_NUMBER` `` Example of usage and output: -`delete s/S14115ASF` +``delete s/`S14115ASF` `` output: @@ -166,29 +166,29 @@ Example of usage and output: Output: `add: Adds a Equipment to the equipmentInventory.`
-`Parameters: n/ITEM_NAME s/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE`
-`Example: add n/SpeakerB s/S1404115ASF t/Speaker c/1000 pf/Loud_Technologies pd/2022-02-23` +``Parameters: n/`ITEM NAME` s/`SERIAL NUMBER` t/`TYPE` c/`COST` pf/`PURCHASED FROM` pd/`PURCHASED DATE` ``
+``Example: add n/`SpeakerB` s/`S1404115ASF` t/`Speaker` c/`1000` pf/`Loud_Technologies` pd/`2022-02-23` ``
`delete: Deletes the equipment with the specified serial number.`
-`Parameters: s/SERIAL_NUMBER`
-`Example: delete s/SM57-1`
+``Parameters: s/`SERIAL_NUMBER` ``
+``Example: delete s/`SM57-1` ``
`update: Updates the equipment with the specified serial number.`
`Parameters in [square brackets] are optional.`
-`Parameters: s/SERIAL_NUMBER [n/ITEM_NAME] [t/TYPE] [c/COST] [pf/PURCHASED_FROM] [pd/PURCHASED_DATE]`
-`Example: update s/SM57-1 n/SpeakerC c/2510 pd/2022-08-21`
+``Parameters: s/`SERIAL NUMBER` [n/`ITEM NAME`] [t/`TYPE`] [c/`COST`] [pf/`PURCHASED FROM`] [pd/`PURCHASED DATE`]``
+``Example: update s/`SM57-1` n/`SpeakerC` c/`2510` pd/`2022-08-21` ``
`list: Prints a list of all equipment in the inventory.`
`Parameters: NIL`
`Example: list`
`list: Prints a list of all equipment in the inventory of the specified type.`
-`Parameters: t/Type`
+``Parameters: `Type` ``
`Example: list MICROPHONE`
`check: Gives details of the equipment with the specified name.`
-`Parameters: n/ITEM_NAME`
-`Example: check n/MixerC`
+``Parameters: n/`ITEM_NAME` ``
+``Example: check n/`MixerC` ``
`save: Saves current state of application.`
`Parameters: NIL`
@@ -226,12 +226,12 @@ Output: 'Cheat Sheet' of commands here -* Add equipment `add n/ITEM_NAME s/SERIAL_NUMBER t/TYPE c/COST pf/PURCHASED_FROM pd/PURCHASED_DATE` -* Check equipment `check n/ITEM_NAME` +* Add equipment ``add n/`ITEM_NAME` s/`SERIAL_NUMBER` t/`TYPE` c/`COST` pf/`PURCHASED_FROM` pd/`PURCHASED_DATE` `` +* Check equipment ``check n/`ITEM_NAME` `` * Listing equipment: `list` -* Listing equipment by type: `list t/TYPE` -* Updating an equipment: `update s/SERIAL_NUMBER [n/ITEM_NAME] [t/TYPE] [c/COST] [pf/PURCHASED_FROM] [pd/PURCHASED_DATE]` -* Deleting an equipment: `delete s/SERIAL_NUMBER` +* Listing equipment by type: ``list t/`TYPE` `` +* Updating an equipment: ``update s/`SERIAL_NUMBER` [n/`ITEM_NAME`] [t/`TYPE`] [c/`COST`] [pf/`PURCHASED_FROM`] [pd/`PURCHASED_DATE`]`` +* Deleting an equipment: ``delete s/`SERIAL_NUMBER` `` * Saving application state: `save` * Getting help: `help` * Exiting the application: `bye` diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index 88502f8963..67ae0149bf 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -12,9 +12,9 @@ public class CheckCommand extends Command { public static final String COMMAND_WORD = "check"; public static final String COMMAND_DESCRIPTION = ": Gives details of the equipment with the specified name. " + System.lineSeparator() - + "Parameters: n/ITEM_NAME" + System.lineSeparator() + + "Parameters: n/`ITEM_NAME`" + System.lineSeparator() + "Example: " - + "check n/MixerC"; + + "check n/`MixerC`"; /** * constructor for CheckCommand. Initialises successMessage and usageReminder from Command diff --git a/src/main/java/seedu/command/DeleteCommand.java b/src/main/java/seedu/command/DeleteCommand.java index a9c1c477b4..b62bea0818 100644 --- a/src/main/java/seedu/command/DeleteCommand.java +++ b/src/main/java/seedu/command/DeleteCommand.java @@ -10,9 +10,9 @@ public class DeleteCommand extends Command { public static final String COMMAND_WORD = "delete"; public static final String COMMAND_DESCRIPTION = ": Deletes the equipment with the specified serial number. " + System.lineSeparator() - + "Parameters: s/SERIAL_NUMBER" + System.lineSeparator() + + "Parameters: s/`SERIAL_NUMBER`" + System.lineSeparator() + "Example: " - + "delete s/SM57-1"; + + "delete s/`SM57-1`"; /** * constructor for DeleteCommand. Initialises successMessage and usageReminder from Command. From 0bf0196a97555a910701b2f23a038eb2a4833fc5 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Wed, 6 Apr 2022 16:00:43 +0800 Subject: [PATCH 139/229] Unbold code to reduce emphasis, in line with rest of DG --- docs/DeveloperGuide.md | 56 +++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 9cbdb12a28..dbf294a4b9 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -34,41 +34,41 @@ This section describes some noteworthy details on how certain features are desig Our design draws significant inspiration from the implementation of AddressBook Level 3 (henceforth AddressBook). As the program was initially conceptualised to be a text-based command-line interface, heavy consideration was given to the design and user interactions when it came to the text input to be parsed by the user. -As such, we referenced AddressBook to segment the program into **`Parser`**, **`Command`** and **`Equipment`** classes. +As such, we referenced AddressBook to segment the program into `Parser`, `Command` and `Equipment` classes. **Main components of the architecture** -- **`Duke`** is the Main class and entry-point for the program. -- **`Parser`** serves as the first filter to split raw text input and pass in arguments to the **`Command`** for further processing. -- **`Command`**, together with its various subclasses serve as specific implementations to pass the arguments taken in to the various methods of the **`EquipmentManager`** class. -- **`EquipmentManager`** keeps track of actual **`Equipment`** instances created by our program. -- **`Storage`** performs File I/O functions. +- `Duke` is the Main class and entry-point for the program. +- `Parser` serves as the first filter to split raw text input and pass in arguments to the `Command` for further processing. +- `Command`, together with its various subclasses serve as specific implementations to pass the arguments taken in to the various methods of the `EquipmentManager` class. +- `EquipmentManager` keeps track of actual `Equipment` instances created by our program. +- `Storage` performs File I/O functions. ### Parser -**`Parser`** is the first filter for text inputs read to the user. +`Parser` is the first filter for text inputs read to the user. As alluded to prior, one major consideration was to build it in a manner that can parse text input as effectively as possible. In considering text input, we divided the parsing into the following segments: #### `commandWord` `argumentTag/argumentValue` `argumentTag/argumentValue` `...` -To dispatch `argumentTag/argumentValue` strings to the correct **`Command`** class, the following logic is employed throughout **`Parser`** by **`parseCommand`**. +To dispatch `argumentTag/argumentValue` strings to the correct `Command` class, the following logic is employed throughout `Parser` by `parseCommand`. **1. Parse the correct Command Word** -**`splitCommandTerm`** splits the input string upon the first space. -The first substring is used to decide which **`Command`** to dispatch while the second is used for its arguments. -In the case where a second substring is not required, as in the case of **`help`** and **`list`**, a null String is used. +`splitCommandTerm` splits the input string upon the first space. +The first substring is used to decide which `Command` to dispatch while the second is used for its arguments. +In the case where a second substring is not required, as in the case of `help` and `list`, a null String is used. **2. Split Arguments** -For simpler command words such as **`delete`** and **`check`**, only one pair of **`argumentType`** and **`argumentValue`** were required. -As such, these will be passed in directly to their **`Command`** classes without a **`argumentType`** pair. +For simpler command words such as `delete` and `check`, only one pair of `argumentType` and `argumentValue` were required. +As such, these will be passed in directly to their `Command` classes without a `argumentType` pair. -More complex command words such as **`add`** and **`update`** necessitated multiple arguments. -To implement this while ensuring that multi-word strings are acceptable input, **`extractArguments`** was implemented. -Without specifically explaining the main regular expression ([details here](https://regex101.com/r/gwjHWD/3)), the approach sought to match **`argumentTag/argumentValue`** pairs with a positive lookahead. +More complex command words such as `add` and `update` necessitated multiple arguments. +To implement this while ensuring that multi-word strings are acceptable input, `extractArguments` was implemented. +Without specifically explaining the main regular expression ([details here](https://regex101.com/r/gwjHWD/3)), the approach sought to match `argumentTag/argumentValue` pairs with a positive lookahead. The final argument pair will then be extracted using a separate regex. -Together, this ensured that all argument pairs can be effectively parsed and dispatched to each **`Command`** class. +Together, this ensured that all argument pairs can be effectively parsed and dispatched to each `Command` class. Throughout the `Parser` implementation, exceptions were used to return `IncorrectCommand` classes that can be used to pass error messages to the user. These will be discussed in the following segments. @@ -105,17 +105,17 @@ Step 6. It is not shown in the sequence diagram but ultimately when the CommandR ### EquipmentManager -The **`EquipmentManager`**, as the name suggests, manages all the equipment that the user has. -When initialised, it creates a HashMap called **`equipmentList`** which is used to save the equipment with their serial numbers as their keys. -The **`EquipmentManager`** has several methods which allow manipulation to said HashMap such as **`addEquipment`**, **`checkEquipment`**, **`listEquipment`**, **`updateEquipment`**, and **`deleteEquipment`**. -These methods are used during the execution of each of the **`Command`** class. -* **`addEquipment`** — Adds an **`Equipment`** to the **`equipmentList`**. -* **`checkEquipment`** — Returns the **`Equipment`** in **`equipmentList`** that has the given **`itemName`**. -* **`listEquipment`** — Returns an ArrayList of all the **`Equipment`** in **`equipmentList`**. -* **`updateEquipment`** — Updates the specified **`Equipment`** with the corresponding updates given in the ArrayList of pairs. -* **`deleteEquipment`** — Deletes the specified **`Equipment`**. - -The **`EquipmentManager`** is implemented as the main storage unit of all the equipments during the execution of the program. +The `EquipmentManager`, as the name suggests, manages all the equipment that the user has. +When initialised, it creates a HashMap called `equipmentList` which is used to save the equipment with their serial numbers as their keys. +The `EquipmentManager` has several methods which allow manipulation to said HashMap such as `addEquipment`, `checkEquipment`, `listEquipment`, `updateEquipment`, and `deleteEquipment`. +These methods are used during the execution of each of the `Command` class. +* `addEquipment` — Adds an `Equipment` to the `equipmentList`. +* `checkEquipment` — Returns the `Equipment` in `equipmentList` that has the given `itemName`. +* `listEquipment` — Returns an ArrayList of all the `Equipment` in `equipmentList`. +* `updateEquipment` — Updates the specified `Equipment` with the corresponding updates given in the ArrayList of pairs. +* `deleteEquipment` — Deletes the specified `Equipment`. + +The `EquipmentManager` is implemented as the main storage unit of all the equipments during the execution of the program. -------------------------------------------------------------------------------------------------------------------- ## Product scope From 11dce75b8ec4bdbb682b3fd98a389acf5d47cc55 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Wed, 6 Apr 2022 16:05:27 +0800 Subject: [PATCH 140/229] Update regex101 link --- docs/DeveloperGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index dbf294a4b9..27ef360127 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -66,7 +66,7 @@ As such, these will be passed in directly to their `Command` classes without a ` More complex command words such as `add` and `update` necessitated multiple arguments. To implement this while ensuring that multi-word strings are acceptable input, `extractArguments` was implemented. -Without specifically explaining the main regular expression ([details here](https://regex101.com/r/gwjHWD/3)), the approach sought to match `argumentTag/argumentValue` pairs with a positive lookahead. +Without specifically explaining the main regular expression ([details here](https://regex101.com/r/dMwMWw/1)), the approach sought to match `argumentTag/argumentValue` pairs with a positive lookahead. The final argument pair will then be extracted using a separate regex. Together, this ensured that all argument pairs can be effectively parsed and dispatched to each `Command` class. From 95e5c71af9f9fbecd4f1307eb976d45e9506f446 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Wed, 6 Apr 2022 16:09:57 +0800 Subject: [PATCH 141/229] Revert "Update regex101 link": should be in parser-backtick instead This reverts commit 11dce75b8ec4bdbb682b3fd98a389acf5d47cc55. --- docs/DeveloperGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 27ef360127..dbf294a4b9 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -66,7 +66,7 @@ As such, these will be passed in directly to their `Command` classes without a ` More complex command words such as `add` and `update` necessitated multiple arguments. To implement this while ensuring that multi-word strings are acceptable input, `extractArguments` was implemented. -Without specifically explaining the main regular expression ([details here](https://regex101.com/r/dMwMWw/1)), the approach sought to match `argumentTag/argumentValue` pairs with a positive lookahead. +Without specifically explaining the main regular expression ([details here](https://regex101.com/r/gwjHWD/3)), the approach sought to match `argumentTag/argumentValue` pairs with a positive lookahead. The final argument pair will then be extracted using a separate regex. Together, this ensured that all argument pairs can be effectively parsed and dispatched to each `Command` class. From d113b1a0a600938763501eb99c125122efbb1c1e Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Wed, 6 Apr 2022 16:25:59 +0800 Subject: [PATCH 142/229] Attempt to center code --- docs/DeveloperGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index dbf294a4b9..19dec476d2 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -49,7 +49,7 @@ As such, we referenced AddressBook to segment the program into `Parser`, `Comman `Parser` is the first filter for text inputs read to the user. As alluded to prior, one major consideration was to build it in a manner that can parse text input as effectively as possible. In considering text input, we divided the parsing into the following segments: -#### `commandWord` `argumentTag/argumentValue` `argumentTag/argumentValue` `...` +

`commandWord` `argumentTag/argumentValue` `[argumentTag/argumentValue]` `[...]`

To dispatch `argumentTag/argumentValue` strings to the correct `Command` class, the following logic is employed throughout `Parser` by `parseCommand`. From 15ab1e1637602ab14ebab738207689b118922f00 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Wed, 6 Apr 2022 16:28:11 +0800 Subject: [PATCH 143/229] Attempt to center formatted code --- docs/DeveloperGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 19dec476d2..18afea6a54 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -49,7 +49,7 @@ As such, we referenced AddressBook to segment the program into `Parser`, `Comman `Parser` is the first filter for text inputs read to the user. As alluded to prior, one major consideration was to build it in a manner that can parse text input as effectively as possible. In considering text input, we divided the parsing into the following segments: -

`commandWord` `argumentTag/argumentValue` `[argumentTag/argumentValue]` `[...]`

+

`commandWord` `argumentTag/argumentValue` `[argumentTag/argumentValue]` `[...]`<\code>

To dispatch `argumentTag/argumentValue` strings to the correct `Command` class, the following logic is employed throughout `Parser` by `parseCommand`. From 4d2813a5a4df55583cc167ee5b0a3363f83f58c0 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Wed, 6 Apr 2022 16:29:56 +0800 Subject: [PATCH 144/229] Fix code formatting for Parsr --- docs/DeveloperGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 18afea6a54..90362a150f 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -49,7 +49,7 @@ As such, we referenced AddressBook to segment the program into `Parser`, `Comman `Parser` is the first filter for text inputs read to the user. As alluded to prior, one major consideration was to build it in a manner that can parse text input as effectively as possible. In considering text input, we divided the parsing into the following segments: -

`commandWord` `argumentTag/argumentValue` `[argumentTag/argumentValue]` `[...]`<\code>

+

commandWord argumentTag/argumentValue [argumentTag/argumentValue] [...] <\code> <\p> To dispatch `argumentTag/argumentValue` strings to the correct `Command` class, the following logic is employed throughout `Parser` by `parseCommand`. From bc5c8b940627bfa875debe0d9d9d18c5a8ec36e6 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Wed, 6 Apr 2022 16:30:50 +0800 Subject: [PATCH 145/229] Test code formatting for Parser --- docs/DeveloperGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 90362a150f..9202dd8b0a 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -49,7 +49,7 @@ As such, we referenced AddressBook to segment the program into `Parser`, `Comman `Parser` is the first filter for text inputs read to the user. As alluded to prior, one major consideration was to build it in a manner that can parse text input as effectively as possible. In considering text input, we divided the parsing into the following segments: -

commandWord argumentTag/argumentValue [argumentTag/argumentValue] [...] <\code> <\p> +

commandWord argumentTag/argumentValue [argumentTag/argumentValue] [...]<\code><\p> To dispatch `argumentTag/argumentValue` strings to the correct `Command` class, the following logic is employed throughout `Parser` by `parseCommand`. From e7b19e6f82a3dcf6f5cd867b92708ad6b8e70ec0 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Wed, 6 Apr 2022 16:31:12 +0800 Subject: [PATCH 146/229] Test code formatting for Parser --- docs/DeveloperGuide.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 9202dd8b0a..b35222a3d4 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -49,7 +49,9 @@ As such, we referenced AddressBook to segment the program into `Parser`, `Comman `Parser` is the first filter for text inputs read to the user. As alluded to prior, one major consideration was to build it in a manner that can parse text input as effectively as possible. In considering text input, we divided the parsing into the following segments: -

commandWord argumentTag/argumentValue [argumentTag/argumentValue] [...]<\code><\p> +

commandWord argumentTag/argumentValue [argumentTag/argumentValue] [...] + +<\p> To dispatch `argumentTag/argumentValue` strings to the correct `Command` class, the following logic is employed throughout `Parser` by `parseCommand`. From cfb213274870793466a82af31815267835d910f4 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Wed, 6 Apr 2022 16:31:44 +0800 Subject: [PATCH 147/229] Test code formatting for Parser --- docs/DeveloperGuide.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index b35222a3d4..38ece0a8ef 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -49,9 +49,7 @@ As such, we referenced AddressBook to segment the program into `Parser`, `Comman `Parser` is the first filter for text inputs read to the user. As alluded to prior, one major consideration was to build it in a manner that can parse text input as effectively as possible. In considering text input, we divided the parsing into the following segments: -

commandWord argumentTag/argumentValue [argumentTag/argumentValue] [...] - -<\p> +

commandWord [argumentTag/argumentValue] [...] To dispatch `argumentTag/argumentValue` strings to the correct `Command` class, the following logic is employed throughout `Parser` by `parseCommand`. From 2ecb645a8ee7b7b944566fc1f66baaf86d75b8c4 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Wed, 6 Apr 2022 16:33:29 +0800 Subject: [PATCH 148/229] Test code formatting for Parser --- docs/DeveloperGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 38ece0a8ef..589948bdb8 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -49,7 +49,7 @@ As such, we referenced AddressBook to segment the program into `Parser`, `Comman `Parser` is the first filter for text inputs read to the user. As alluded to prior, one major consideration was to build it in a manner that can parse text input as effectively as possible. In considering text input, we divided the parsing into the following segments: -

commandWord [argumentTag/argumentValue] [...] +

commandWord [argumentTag/argumentValue] [...]

To dispatch `argumentTag/argumentValue` strings to the correct `Command` class, the following logic is employed throughout `Parser` by `parseCommand`. From ebba1c5f722e0cb454c45f25788425f77ee206e0 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Wed, 6 Apr 2022 16:34:27 +0800 Subject: [PATCH 149/229] Test code formatting for Parser --- docs/DeveloperGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 589948bdb8..20cbbe7956 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -49,7 +49,7 @@ As such, we referenced AddressBook to segment the program into `Parser`, `Comman `Parser` is the first filter for text inputs read to the user. As alluded to prior, one major consideration was to build it in a manner that can parse text input as effectively as possible. In considering text input, we divided the parsing into the following segments: -

commandWord [argumentTag/argumentValue] [...]

+

commandWord [argumentTag/argumentValue] [...]

To dispatch `argumentTag/argumentValue` strings to the correct `Command` class, the following logic is employed throughout `Parser` by `parseCommand`. From 7c6648541644bcd8cbccee7fcbaab3e2b69c0636 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Wed, 6 Apr 2022 17:26:38 +0800 Subject: [PATCH 150/229] Include backticks in DG --- docs/DeveloperGuide.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 20cbbe7956..e250098c33 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -49,9 +49,9 @@ As such, we referenced AddressBook to segment the program into `Parser`, `Comman `Parser` is the first filter for text inputs read to the user. As alluded to prior, one major consideration was to build it in a manner that can parse text input as effectively as possible. In considering text input, we divided the parsing into the following segments: -

commandWord [argumentTag/argumentValue] [...]

+

commandWord [argumentType/`argumentValue`] [...]

-To dispatch `argumentTag/argumentValue` strings to the correct `Command` class, the following logic is employed throughout `Parser` by `parseCommand`. +To dispatch argumentType/\`argumentValue\` strings to the correct `Command` class, the following logic is employed throughout `Parser` by `parseCommand`. **1. Parse the correct Command Word** @@ -61,12 +61,12 @@ In the case where a second substring is not required, as in the case of `help` a **2. Split Arguments** -For simpler command words such as `delete` and `check`, only one pair of `argumentType` and `argumentValue` were required. +For simpler command words such as `delete` and `check`, only one pair of `argumentType` and \`argumentValue\` are required. As such, these will be passed in directly to their `Command` classes without a `argumentType` pair. More complex command words such as `add` and `update` necessitated multiple arguments. To implement this while ensuring that multi-word strings are acceptable input, `extractArguments` was implemented. -Without specifically explaining the main regular expression ([details here](https://regex101.com/r/gwjHWD/3)), the approach sought to match `argumentTag/argumentValue` pairs with a positive lookahead. +Without specifically explaining the main regular expression ([details here](https://regex101.com/r/gwjHWD/3)), the approach sought to match `argumentType` and \`argumentValue\` pairs with a positive lookahead. The final argument pair will then be extracted using a separate regex. Together, this ensured that all argument pairs can be effectively parsed and dispatched to each `Command` class. From 77f00bfde99675f9b5c21ed903a35db2752ebef0 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Wed, 6 Apr 2022 17:43:20 +0800 Subject: [PATCH 151/229] Rewrite Parser DG documentation for v2.1 --- docs/DeveloperGuide.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index e250098c33..c58b3c4701 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -61,15 +61,20 @@ In the case where a second substring is not required, as in the case of `help` a **2. Split Arguments** -For simpler command words such as `delete` and `check`, only one pair of `argumentType` and \`argumentValue\` are required. -As such, these will be passed in directly to their `Command` classes without a `argumentType` pair. - -More complex command words such as `add` and `update` necessitated multiple arguments. -To implement this while ensuring that multi-word strings are acceptable input, `extractArguments` was implemented. +Complex commands such as `add` and `update` necessitate multiple arguments. +To implement this while ensuring that multi-word strings are acceptable input, `extractArguments` is implemented. Without specifically explaining the main regular expression ([details here](https://regex101.com/r/gwjHWD/3)), the approach sought to match `argumentType` and \`argumentValue\` pairs with a positive lookahead. The final argument pair will then be extracted using a separate regex. Together, this ensured that all argument pairs can be effectively parsed and dispatched to each `Command` class. +
Special delete implementation +

+ +For added safeguards in equipment deletion, the delete command implements a more stringent regex to match one argument pair of s/\`SERIAL_NUMBER\`. + +

+
+ Throughout the `Parser` implementation, exceptions were used to return `IncorrectCommand` classes that can be used to pass error messages to the user. These will be discussed in the following segments. ### Update feature From dff07118f5e62a1004ba712f8612c55880b0f678 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 7 Apr 2022 12:37:59 +0800 Subject: [PATCH 152/229] Rewrite Update command to be more general for Command --- docs/DeveloperGuide.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index c58b3c4701..5faf0f5c00 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -63,7 +63,7 @@ In the case where a second substring is not required, as in the case of `help` a Complex commands such as `add` and `update` necessitate multiple arguments. To implement this while ensuring that multi-word strings are acceptable input, `extractArguments` is implemented. -Without specifically explaining the main regular expression ([details here](https://regex101.com/r/gwjHWD/3)), the approach sought to match `argumentType` and \`argumentValue\` pairs with a positive lookahead. +Without specifically explaining the main regular expression ([details here](https://regex101.com/r/gwjHWD/3)), the approach sought to match `argumentType` and \`argumentValue\` pairs with a positive lookahead. The final argument pair will then be extracted using a separate regex. Together, this ensured that all argument pairs can be effectively parsed and dispatched to each `Command` class. @@ -77,10 +77,12 @@ For added safeguards in equipment deletion, the delete command implements a more Throughout the `Parser` implementation, exceptions were used to return `IncorrectCommand` classes that can be used to pass error messages to the user. These will be discussed in the following segments. -### Update feature +### Command classes #### Current Design and Implementation +Command classes are largely similar to each other. The most complex command 'update' will be explained here. + The update feature is facilitated by `UpdateCommand`. It extends `ModificationCommand` and implements the following operations: * `UpdateCommand#generateUpdatePairs()` — Generates pairs of attributes and their update values. From 62792212c74555d604041222b91b11b31b4d64e4 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 7 Apr 2022 12:38:23 +0800 Subject: [PATCH 153/229] Remove acknowledgements placeholder --- docs/DeveloperGuide.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 5faf0f5c00..393ecf2053 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -16,8 +16,6 @@ ## Acknowledgements -{list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well} - Our project could not have been possible without the prior work of the following: - [SE-EDU project team](https://se-education.org/docs/team.html) for their work on [AddressBook Level 3](https://github.com/se-edu/addressbook-level3), for which we referenced ideas as well as code snippets. From a31a215c8918c10b47b8749a9d579907060d4e5a Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 7 Apr 2022 12:45:12 +0800 Subject: [PATCH 154/229] Reword Design and Implementation for better flow --- docs/DeveloperGuide.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 393ecf2053..c1fd91911d 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -53,12 +53,16 @@ To dispatch argumentType/\`argumentValue\` strings to the correct ` **1. Parse the correct Command Word** +

commandWord

+ `splitCommandTerm` splits the input string upon the first space. The first substring is used to decide which `Command` to dispatch while the second is used for its arguments. -In the case where a second substring is not required, as in the case of `help` and `list`, a null String is used. +In the case where a second substring is not required, as in the case of `help` and `list`, a null String is used and the following step is skipped entirely. **2. Split Arguments** +

[argumentType/`argumentValue`] [...]

+ Complex commands such as `add` and `update` necessitate multiple arguments. To implement this while ensuring that multi-word strings are acceptable input, `extractArguments` is implemented. Without specifically explaining the main regular expression ([details here](https://regex101.com/r/gwjHWD/3)), the approach sought to match `argumentType` and \`argumentValue\` pairs with a positive lookahead. @@ -79,7 +83,7 @@ Throughout the `Parser` implementation, exceptions were used to return `Incorrec #### Current Design and Implementation -Command classes are largely similar to each other. The most complex command 'update' will be explained here. +`Command` classes are largely similar to each other. The most complex command, `UpdateCommand` will be explained here. The update feature is facilitated by `UpdateCommand`. It extends `ModificationCommand` and implements the following operations: From 338f29a8f6083af0d1e137c14ee7323af3893ed9 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 7 Apr 2022 12:55:00 +0800 Subject: [PATCH 155/229] Draft product scope --- docs/DeveloperGuide.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index c1fd91911d..8f8b5977b8 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -130,11 +130,13 @@ The `EquipmentManager` is implemented as the main storage unit of all the equipm ## Product scope ### Target user profile -{Describe the target user profile} +The target user is the logistics chief of an event support club. He is responsible for the logistics of the club and the equipment that is used during events. ### Value proposition -{Describe the value proposition: what problem does it solve?} +Equipment for the club differ in terms of shape and size. Owing to the climate-sensitive and fragile nature of some of these equipment, they are often stored in opaque containers, which may not be easily accessible given space constraints. By keeping records of this information on our application, the logistics chief can easily access and retrieve this information without having to make a physical trip down to the storeroom. + +Further, maintaining a record of the equipment is a time-consuming task given that they often need to be referred to by both the model number and a short alias used by club members. As the post of logistics chief is changed every year when passed down to a new member, this member will need to be acquainted with both the common name and the model number of the relevant equipment. Our application thus provides a convenient way to search by both specifications. -------------------------------------------------------------------------------------------------------------------- ## User Stories From a36ec57dfd4fe10b097e770aeb35b0d21adf1d44 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 7 Apr 2022 13:52:23 +0800 Subject: [PATCH 156/229] Add prepareModification() to test case call --- src/test/java/seedu/command/ModificationCommandTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/seedu/command/ModificationCommandTest.java b/src/test/java/seedu/command/ModificationCommandTest.java index 29d3562681..5e326f464b 100644 --- a/src/test/java/seedu/command/ModificationCommandTest.java +++ b/src/test/java/seedu/command/ModificationCommandTest.java @@ -54,6 +54,7 @@ void prepareModification_typeEnumsChangedToCaps_success() throws IncompleteComma Arrays.asList("s/S1404115ASF", "t/SPEAKER", "n/Speaker A") )); ModificationCommand actualCommand = new ModificationCommand(testArrayList); + expectedCommand.prepareModification(); actualCommand.prepareModification(); assertEquals(expectedCommand, actualCommand); } From ef4927fd63af561a7804031bb6e093c03e1ba7e1 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Thu, 7 Apr 2022 16:23:06 +0800 Subject: [PATCH 157/229] Refactor checkEquipment to take Pair as parameter --- .../seedu/equipment/EquipmentManager.java | 52 +++++++++++++++++-- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index 1d7f870f71..76dbadf3d8 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -51,15 +51,57 @@ public void addEquipment(Equipment equipment) throws DuplicateSerialNumberExcept /** * Searches the equipmentList for Equipments with the item name given. * - * @param itemName Name of Equipment in String. + * @param checkParam Name of Equipment in String. * @return An ArrayList of Equipments with the same item name as the parameter. */ - public ArrayList checkEquipment(String itemName) { + public ArrayList checkEquipment(Pair checkParam){ ArrayList listOfEquipments = new ArrayList<>(); - for (Equipment equipment : equipmentList.values()) { - if (equipment.getItemName().equals(itemName)) { - listOfEquipments.add(equipment); + String arg = checkParam.getKey(); + switch (arg) { + case "itemName": + for (Equipment equipment : equipmentList.values()) { + if (equipment.getItemName().equals(checkParam.getValue())) { + listOfEquipments.add(equipment); + } + } + break; + case "serialNumber": + for (Equipment equipment : equipmentList.values()) { + if (equipment.getSerialNumber().equals(checkParam.getValue())) { + listOfEquipments.add(equipment); + } + } + break; + case "type": + for (Equipment equipment : equipmentList.values()) { + if (equipment.getType().equals(checkParam.getValue())) { + listOfEquipments.add(equipment); + } + } + break; + case "cost": + for (Equipment equipment : equipmentList.values()) { + if (equipment.getCost() == (double) checkParam.getValue()) { + listOfEquipments.add(equipment); + } + } + break; + case "purchasedFrom": + for (Equipment equipment : equipmentList.values()) { + if (equipment.getPurchasedFrom().equals(checkParam.getValue())) { + listOfEquipments.add(equipment); + } + } + break; + case "purchasedDate": + for (Equipment equipment : equipmentList.values()) { + if (equipment.getPurchasedDate().equals(checkParam.getValue())) { + listOfEquipments.add(equipment); + } } + break; + default: + break; } return listOfEquipments; } From e64321dce22abb356ec3be8afaeac63f2a1171b2 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Thu, 7 Apr 2022 17:17:27 +0800 Subject: [PATCH 158/229] Made changes according to @shunyao643 comments on pull request #119 --- src/main/java/seedu/command/DeleteCommand.java | 12 ++---------- src/test/java/seedu/command/DeleteCommandTest.java | 3 ++- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/main/java/seedu/command/DeleteCommand.java b/src/main/java/seedu/command/DeleteCommand.java index b15b13ae2e..6b52a7bf7d 100644 --- a/src/main/java/seedu/command/DeleteCommand.java +++ b/src/main/java/seedu/command/DeleteCommand.java @@ -1,9 +1,6 @@ package seedu.command; -import seedu.equipment.EquipmentType; - import java.util.ArrayList; -import java.util.Locale; /** * Subclass of Command. Handles deleting of equipment from equipmentInventory. @@ -40,9 +37,6 @@ public CommandResult execute() { try { serialNumber = prepareDelete(); - if (serialNumber.equals("")) { - return new CommandResult(ONLY_SN_ACCEPTED); - } equipmentName = equipmentManager.getEquipmentList().get(serialNumber).getItemName(); } catch (NullPointerException e) { return new CommandResult(INVALID_SERIAL_NUMBER); @@ -77,9 +71,7 @@ protected String prepareDelete() throws AssertionError { String argType = argString.substring(0, delimiterPos); String argValue = argString.substring(delimiterPos + 1); assert argType.equals("s") : ONLY_SN_ACCEPTED; - if (argType.equals("s")) { - return argValue; - } - return ""; + + return argValue; } } diff --git a/src/test/java/seedu/command/DeleteCommandTest.java b/src/test/java/seedu/command/DeleteCommandTest.java index 3088f2b8b7..aaee10ec94 100644 --- a/src/test/java/seedu/command/DeleteCommandTest.java +++ b/src/test/java/seedu/command/DeleteCommandTest.java @@ -10,6 +10,7 @@ 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; @@ -66,7 +67,7 @@ void execute_notSerialNumber_fail() { CommandResult actualResult = deleteCommand.execute(); CommandResult expectedResult = - new CommandResult("Only serial number accepted for deleting equipment"); + new CommandResult(ONLY_SN_ACCEPTED); assertEquals(expectedResult, actualResult); } From 4567f8cb09d73c259113f6c813e15b49b97ea930 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Thu, 7 Apr 2022 20:49:48 +0800 Subject: [PATCH 159/229] Update value to be used in Pair for CheckCommand --- src/main/java/seedu/command/CheckCommand.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index d43647bc71..3f0d9c2882 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -39,7 +39,7 @@ public CommandResult execute() { Pair checkPair = generateCheckPair(); ArrayList equipment = equipmentManager.checkEquipment(checkPair); - return new CommandResult(String.format(successMessage, commandStrings.get(0)), equipment); + return new CommandResult(String.format(successMessage, checkPair.getValue()), equipment); } /** @@ -60,22 +60,22 @@ public CommandResult execute() { String argValue = s.substring(delimiterPos + 1); switch (argType) { case "n": - pair = new Pair<>("itemName", commandStrings.get(0)); + pair = new Pair<>("itemName", argValue); break; case "pd": - pair = new Pair<>("purchasedDate", commandStrings.get(0)); + pair = new Pair<>("purchasedDate", argValue); break; case "t": - pair = new Pair<>("type", commandStrings.get(0)); + pair = new Pair<>("type", argValue); break; case "pf": - pair = new Pair<>("purchasedFrom", commandStrings.get(0)); + pair = new Pair<>("purchasedFrom", argValue); break; case "c": - pair = new Pair<>("cost", commandStrings.get(0)); + pair = new Pair<>("cost", argValue); break; case "s": - pair = new Pair<>("serialNumber", commandStrings.get(0)); + pair = new Pair<>("serialNumber", argValue); break; default: System.out.println("`" + argValue + "` not accepted for type " + argType + ": Unrecognised Tag"); From 927f7240260f5e380093fe118429d2fc20529cd4 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Thu, 7 Apr 2022 21:18:04 +0800 Subject: [PATCH 160/229] Fix broken JUnit test for CheckCommand --- src/test/java/seedu/command/CheckCommandTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/seedu/command/CheckCommandTest.java b/src/test/java/seedu/command/CheckCommandTest.java index 9949639fab..add179fece 100644 --- a/src/test/java/seedu/command/CheckCommandTest.java +++ b/src/test/java/seedu/command/CheckCommandTest.java @@ -18,7 +18,7 @@ class CheckCommandTest { @Test void execute_validEquipmentName_success() { checkCommand = new CheckCommand(new ArrayList<>( - Arrays.asList("Speaker B") + Arrays.asList("n/Speaker B") )); checkCommand.setEquipmentManager(new EquipmentManager()); EquipmentManager equipmentManager = checkCommand.equipmentManager; From ee03f623ff2fbbbded042a3c370a6952acd2a3ee Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Thu, 7 Apr 2022 21:24:23 +0800 Subject: [PATCH 161/229] Modify EquipmentManger#checkEquipment to use `contains` instead of `equals` for some of the attributes Fix CheckCommand#generateCheckPair not putting the appropriate class for Cost and EquipmentType into the Pair --- src/main/java/seedu/command/CheckCommand.java | 8 ++++---- src/main/java/seedu/command/Command.java | 8 ++++---- src/main/java/seedu/equipment/EquipmentManager.java | 10 +++++----- src/main/java/seedu/parser/Parser.java | 4 ++++ src/test/java/seedu/command/CheckCommandTest.java | 2 +- 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index 3a0e34dcf1..132ac4baab 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -39,7 +39,7 @@ public CommandResult execute() { Pair checkPair = generateCheckPair(); ArrayList equipment = equipmentManager.checkEquipment(checkPair); - return new CommandResult(String.format(successMessage, checkPair.getValue()), equipment); + return new CommandResult(String.format(successMessage, commandStrings.get(0)), equipment); } /** @@ -48,7 +48,7 @@ public CommandResult execute() { * By using pair, we are able to specify the attribute to be checked. * @return Pair of value to be checked and its matching attribute. */ - public Pair generateCheckPair() { + public Pair generateCheckPair() throws AssertionError, NumberFormatException, IllegalArgumentException { Pair pair = null; for (String s : commandStrings) { @@ -66,13 +66,13 @@ public CommandResult execute() { pair = new Pair<>("purchasedDate", argValue); break; case "t": - pair = new Pair<>("type", argValue); + pair = new Pair<>("type", EquipmentType.valueOf(argValue.toUpperCase(Locale.ROOT))); break; case "pf": pair = new Pair<>("purchasedFrom", argValue); break; case "c": - pair = new Pair<>("cost", argValue); + pair = new Pair<>("cost", Double.valueOf(argValue)); break; case "s": pair = new Pair<>("serialNumber", argValue); diff --git a/src/main/java/seedu/command/Command.java b/src/main/java/seedu/command/Command.java index d4fc6c7f3e..8c3a039881 100644 --- a/src/main/java/seedu/command/Command.java +++ b/src/main/java/seedu/command/Command.java @@ -13,12 +13,12 @@ public abstract class Command { public String usageReminder; protected EquipmentManager equipmentManager; protected Storage storage; - protected static final String INCORRECT_ENUM_TYPE = "Wrong type of equipment. The allowed types are: " + public static final String INCORRECT_ENUM_TYPE = "Wrong type of equipment. The allowed types are: " + "MICROPHONE, SPEAKER, STAND, CABLE"; - protected static final String INCORRECT_COST_FORMAT = "Please enter numbers only for cost and omit symbols"; - protected static final String INVALID_SERIAL_NUMBER = "No such serial number, please enter an existing " + public static final String INCORRECT_COST_FORMAT = "Please enter numbers only for cost and omit symbols"; + public static final String INVALID_SERIAL_NUMBER = "No such serial number, please enter an existing " + "serial number"; - protected static final String MISSING_SERIAL_NUMBER = "Serial Number is required to run this command"; + public static final String MISSING_SERIAL_NUMBER = "Serial Number is required to run this command"; public abstract CommandResult execute(); diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index 76dbadf3d8..962f1488fb 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -54,20 +54,20 @@ public void addEquipment(Equipment equipment) throws DuplicateSerialNumberExcept * @param checkParam Name of Equipment in String. * @return An ArrayList of Equipments with the same item name as the parameter. */ - public ArrayList checkEquipment(Pair checkParam){ + public ArrayList checkEquipment(Pair checkParam) { ArrayList listOfEquipments = new ArrayList<>(); String arg = checkParam.getKey(); switch (arg) { case "itemName": for (Equipment equipment : equipmentList.values()) { - if (equipment.getItemName().equals(checkParam.getValue())) { + if (equipment.getItemName().contains((String) checkParam.getValue())) { listOfEquipments.add(equipment); } } break; case "serialNumber": for (Equipment equipment : equipmentList.values()) { - if (equipment.getSerialNumber().equals(checkParam.getValue())) { + if (equipment.getSerialNumber().contains((String) checkParam.getValue())) { listOfEquipments.add(equipment); } } @@ -88,14 +88,14 @@ public ArrayList checkEquipment(Pair checkParam){ break; case "purchasedFrom": for (Equipment equipment : equipmentList.values()) { - if (equipment.getPurchasedFrom().equals(checkParam.getValue())) { + if (equipment.getPurchasedFrom().contains((String) checkParam.getValue())) { listOfEquipments.add(equipment); } } break; case "purchasedDate": for (Equipment equipment : equipmentList.values()) { - if (equipment.getPurchasedDate().equals(checkParam.getValue())) { + if (equipment.getPurchasedDate().contains((String) checkParam.getValue())) { listOfEquipments.add(equipment); } } diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 4a707ab01b..d2fe3b151e 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -125,6 +125,10 @@ public Command parseCommand(String userInput) { return new CheckCommand(args); } catch (IncompleteCommandException e) { return new IncorrectCommand(CheckCommand.COMMAND_WORD + CheckCommand.COMMAND_DESCRIPTION); + } catch (NumberFormatException e) { + return new IncorrectCommand(Command.INCORRECT_ENUM_TYPE); + } catch (IllegalArgumentException e) { + return new IncorrectCommand(Command.INCORRECT_COST_FORMAT); } case DeleteCommand.COMMAND_WORD: try { diff --git a/src/test/java/seedu/command/CheckCommandTest.java b/src/test/java/seedu/command/CheckCommandTest.java index add179fece..37b8c7e870 100644 --- a/src/test/java/seedu/command/CheckCommandTest.java +++ b/src/test/java/seedu/command/CheckCommandTest.java @@ -42,7 +42,7 @@ void execute_validEquipmentName_success() { CommandResult actualResult = checkCommand.execute(); CommandResult expectedResult = new CommandResult( - "Here are the equipment matching to 'Speaker B':" + System.lineSeparator(), + "Here are the equipment matching to 'n/Speaker B':" + System.lineSeparator(), listOfEquipments); assertEquals(expectedResult, actualResult); From fffeae27991fc57ac26dd9e2a4f1996d6c2c22d8 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 7 Apr 2022 22:25:54 +0800 Subject: [PATCH 162/229] Fix checkstyle --- src/main/java/seedu/equipment/EquipmentManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index 76dbadf3d8..4983e24418 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -54,7 +54,7 @@ public void addEquipment(Equipment equipment) throws DuplicateSerialNumberExcept * @param checkParam Name of Equipment in String. * @return An ArrayList of Equipments with the same item name as the parameter. */ - public ArrayList checkEquipment(Pair checkParam){ + public ArrayList checkEquipment(Pair checkParam) { ArrayList listOfEquipments = new ArrayList<>(); String arg = checkParam.getKey(); switch (arg) { From 6c90b2e2a4de88b55f42a2c2b2243f5f792a1104 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 7 Apr 2022 22:57:19 +0800 Subject: [PATCH 163/229] Draft date implementation --- .../seedu/command/ModificationCommand.java | 25 +++++++++++-------- src/main/java/seedu/equipment/Equipment.java | 10 ++++---- .../seedu/equipment/EquipmentManager.java | 7 +++--- src/main/java/seedu/parser/Parser.java | 3 +++ .../java/seedu/command/AddCommandTest.java | 5 ++-- .../java/seedu/command/CheckCommandTest.java | 3 ++- .../java/seedu/command/DeleteCommandTest.java | 3 ++- .../java/seedu/command/ListCommandTest.java | 5 ++-- .../java/seedu/command/UpdateCommandTest.java | 5 ++-- .../seedu/equipment/EquipmentManagerTest.java | 9 ++++--- 10 files changed, 45 insertions(+), 30 deletions(-) diff --git a/src/main/java/seedu/command/ModificationCommand.java b/src/main/java/seedu/command/ModificationCommand.java index 6dfb361d51..fa138ecf43 100644 --- a/src/main/java/seedu/command/ModificationCommand.java +++ b/src/main/java/seedu/command/ModificationCommand.java @@ -2,6 +2,8 @@ import seedu.equipment.EquipmentType; +import java.time.LocalDate; +import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.Locale; import java.util.Objects; @@ -15,10 +17,12 @@ public class ModificationCommand extends Command { public static final String INVALID_TYPE_MESSAGE = "Equipment Type needs to be one of:" + System.lineSeparator() + EquipmentType.getAllTypes(); public static final String INVALID_COST_MESSAGE = "Cost needs to be able to be parsed to a double"; + public static final String INVALID_DATE_MESSAGE = "Date needs to be able to be parsed, make sure you're using " + + "YYYY-MM-DD format"; protected final ArrayList commandStrings; protected String serialNumber; protected String equipmentName = null; - protected String purchasedDate = null; + protected LocalDate purchasedDate = null; protected EquipmentType equipmentType = null; protected String purchasedFrom = null; protected Double cost = null; @@ -39,20 +43,20 @@ public void setEquipmentName(String equipmentName) { this.equipmentName = equipmentName; } - public void setPurchasedDate(String purchasedDate) { - this.purchasedDate = purchasedDate; + public void setPurchasedDate(String purchasedDate) throws DateTimeParseException { + this.purchasedDate = LocalDate.parse(purchasedDate); } - public void setEquipmentType(EquipmentType equipmentType) { - this.equipmentType = equipmentType; + public void setEquipmentType(String equipmentType) throws IllegalArgumentException { + this.equipmentType = EquipmentType.valueOf(equipmentType.toUpperCase(Locale.ROOT)); } public void setPurchasedFrom(String purchasedFrom) { this.purchasedFrom = purchasedFrom; } - public void setCost(Double cost) { - this.cost = cost; + public void setCost(String cost) throws NumberFormatException { + this.cost = Double.valueOf(cost); } /** @@ -65,7 +69,8 @@ public void setCost(Double cost) { * @throws IllegalArgumentException if EquipmentType is invalid * */ - protected void prepareModification() throws AssertionError, NumberFormatException, IllegalArgumentException { + protected void prepareModification() throws AssertionError, NumberFormatException, IllegalArgumentException, + DateTimeParseException { for (String s : commandStrings) { int delimiterPos = s.indexOf('/'); // the case where delimiterPos = -1 is impossible as @@ -81,13 +86,13 @@ protected void prepareModification() throws AssertionError, NumberFormatExceptio setPurchasedDate(argValue); break; case "t": - setEquipmentType(EquipmentType.valueOf(argValue.toUpperCase(Locale.ROOT))); + setEquipmentType(argValue); break; case "pf": setPurchasedFrom(argValue); break; case "c": - setCost(Double.valueOf(argValue)); + setCost(argValue); break; case "s": setSerialNumber(argValue); diff --git a/src/main/java/seedu/equipment/Equipment.java b/src/main/java/seedu/equipment/Equipment.java index 3a66ead022..0d03b75fad 100644 --- a/src/main/java/seedu/equipment/Equipment.java +++ b/src/main/java/seedu/equipment/Equipment.java @@ -1,5 +1,6 @@ package seedu.equipment; +import java.time.LocalDate; import java.util.Objects; public class Equipment { @@ -8,11 +9,10 @@ public class Equipment { private EquipmentType type; private double cost; private String purchasedFrom; - private String purchasedDate; + private LocalDate purchasedDate; /** * Constructor for the Equipment object. - * * @param itemName Name of the equipment in String. * @param serialNumber Unique serial number of equipment in String. * @param type Type of the equipment in EquipmentType enum. @@ -21,7 +21,7 @@ public class Equipment { * @param purchasedDate When the equipment was purchased in String. */ public Equipment(String itemName, String serialNumber, EquipmentType type, double cost, String purchasedFrom, - String purchasedDate) { + LocalDate purchasedDate) { this.itemName = itemName; this.serialNumber = serialNumber; this.type = type; @@ -70,11 +70,11 @@ public void setPurchasedFrom(String purchasedFrom) { this.purchasedFrom = purchasedFrom; } - public String getPurchasedDate() { + public LocalDate getPurchasedDate() { return this.purchasedDate; } - public void setPurchasedDate(String purchasedDate) { + public void setPurchasedDate(LocalDate purchasedDate) { this.purchasedDate = purchasedDate; } diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index 962f1488fb..d00ca03900 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -2,6 +2,7 @@ import seedu.Pair; +import java.time.LocalDate; import java.util.ArrayList; import java.util.HashMap; @@ -24,7 +25,7 @@ public EquipmentManager() { * @throws DuplicateSerialNumberException If the serial number exists in equipmentList. */ public void addEquipment(String itemName, String serialNumber, EquipmentType type, double cost, - String purchasedFrom, String purchasedDate) throws DuplicateSerialNumberException { + String purchasedFrom, LocalDate purchasedDate) throws DuplicateSerialNumberException { if (!equipmentList.containsKey(serialNumber)) { Equipment equipment = new Equipment(itemName, serialNumber, type, cost, purchasedFrom, purchasedDate); equipmentList.put(serialNumber, equipment); @@ -95,7 +96,7 @@ public ArrayList checkEquipment(Pair checkParam) { break; case "purchasedDate": for (Equipment equipment : equipmentList.values()) { - if (equipment.getPurchasedDate().contains((String) checkParam.getValue())) { + if (equipment.getPurchasedDate().equals(checkParam.getValue())) { listOfEquipments.add(equipment); } } @@ -166,7 +167,7 @@ public boolean updateEquipment(String serialNumber, ArrayList> u updatedEquipment.setCost((Double) updates.getValue()); break; case "purchasedDate": - updatedEquipment.setPurchasedDate((String) updates.getValue()); + updatedEquipment.setPurchasedDate((LocalDate) updates.getValue()); break; case "purchasedFrom": updatedEquipment.setPurchasedFrom((String) updates.getValue()); diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index d2fe3b151e..ce2025aebc 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -1,5 +1,6 @@ package seedu.parser; +import java.time.format.DateTimeParseException; import java.util.ArrayList; import seedu.command.AddCommand; @@ -118,6 +119,8 @@ public Command parseCommand(String userInput) { + System.lineSeparator() + AddCommand.COMMAND_WORD + AddCommand.COMMAND_DESCRIPTION); + } catch (DateTimeParseException e) { + return new IncorrectCommand(ModificationCommand.INVALID_DATE_MESSAGE); } case CheckCommand.COMMAND_WORD: try { diff --git a/src/test/java/seedu/command/AddCommandTest.java b/src/test/java/seedu/command/AddCommandTest.java index be8d94898e..c4d3a1491b 100644 --- a/src/test/java/seedu/command/AddCommandTest.java +++ b/src/test/java/seedu/command/AddCommandTest.java @@ -11,6 +11,7 @@ import seedu.parser.MissingAttributeException; import seedu.parser.Parser; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; @@ -43,7 +44,7 @@ void execute_duplicateSerialNumber_exceptionThrown() throws DuplicateSerialNumbe EquipmentType.valueOf("SPEAKER"), 1000, "Loud Technologies", - "2022-02-23"); + LocalDate.parse("2022-02-23")); CommandResult expectedResult = new CommandResult("There is already an item with this serial number: S1404115ASF"); @@ -86,7 +87,7 @@ void addEquipment_validArrayListString_success() throws DuplicateSerialNumberExc EquipmentType.valueOf("SPEAKER"), 1000, "Loud Technologies", - "2022-02-23"); + LocalDate.parse("2022-02-23")); addCommand.addEquipment(userInput); Equipment actualEquipment = equipmentManager.listEquipment().get(equipmentListOriginalSize); diff --git a/src/test/java/seedu/command/CheckCommandTest.java b/src/test/java/seedu/command/CheckCommandTest.java index 37b8c7e870..6a8ed9c26f 100644 --- a/src/test/java/seedu/command/CheckCommandTest.java +++ b/src/test/java/seedu/command/CheckCommandTest.java @@ -6,6 +6,7 @@ import seedu.equipment.EquipmentManager; import seedu.equipment.EquipmentType; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; @@ -28,7 +29,7 @@ void execute_validEquipmentName_success() { EquipmentType.valueOf("SPEAKER"), 1000, "Loud Technologies", - "2022-02-23"); + LocalDate.parse("2022-02-23")); } catch (DuplicateSerialNumberException e) { fail(); } diff --git a/src/test/java/seedu/command/DeleteCommandTest.java b/src/test/java/seedu/command/DeleteCommandTest.java index aaee10ec94..80285dd2a6 100644 --- a/src/test/java/seedu/command/DeleteCommandTest.java +++ b/src/test/java/seedu/command/DeleteCommandTest.java @@ -5,6 +5,7 @@ import seedu.equipment.EquipmentManager; import seedu.equipment.EquipmentType; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; @@ -28,7 +29,7 @@ void execute_validSerialNumber_success() { EquipmentType.valueOf("SPEAKER"), 1000, "Loud Technologies", - "2022-02-23"); + LocalDate.parse("2022-02-23")); } catch (DuplicateSerialNumberException e) { fail(); } diff --git a/src/test/java/seedu/command/ListCommandTest.java b/src/test/java/seedu/command/ListCommandTest.java index 9825931a32..751c228e58 100644 --- a/src/test/java/seedu/command/ListCommandTest.java +++ b/src/test/java/seedu/command/ListCommandTest.java @@ -5,6 +5,7 @@ import seedu.equipment.EquipmentManager; import seedu.equipment.EquipmentType; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; @@ -27,7 +28,7 @@ void execute_specifiedType_success() { EquipmentType.valueOf("SPEAKER"), 1000, "Loud Technologies", - "2022-02-23"); + LocalDate.parse("2022-02-23")); } catch (DuplicateSerialNumberException e) { fail(); } @@ -51,7 +52,7 @@ void execute_noSpecifiedType_success() { EquipmentType.valueOf("SPEAKER"), 1000, "Loud Technologies", - "2022-02-23"); + LocalDate.parse("2022-02-23")); } catch (DuplicateSerialNumberException e) { fail(); } diff --git a/src/test/java/seedu/command/UpdateCommandTest.java b/src/test/java/seedu/command/UpdateCommandTest.java index 306a19997f..8fb60a67ab 100644 --- a/src/test/java/seedu/command/UpdateCommandTest.java +++ b/src/test/java/seedu/command/UpdateCommandTest.java @@ -7,6 +7,7 @@ import seedu.equipment.EquipmentManager; import seedu.equipment.EquipmentType; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; @@ -25,7 +26,7 @@ void setup() { EquipmentType.valueOf("SPEAKER"), 1000, "Loud Technologies", - "2022-02-23"); + LocalDate.parse("2022-02-23")); } catch (DuplicateSerialNumberException e) { fail(); } @@ -58,7 +59,7 @@ 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", "2022-01-26")); + expectedResult.add(new Pair<>("purchasedDate", LocalDate.parse("2022-01-26"))); ArrayList> actualResult = updateCommand.generateUpdatePairs(); diff --git a/src/test/java/seedu/equipment/EquipmentManagerTest.java b/src/test/java/seedu/equipment/EquipmentManagerTest.java index f307d09cbe..e00c9563f7 100644 --- a/src/test/java/seedu/equipment/EquipmentManagerTest.java +++ b/src/test/java/seedu/equipment/EquipmentManagerTest.java @@ -3,6 +3,7 @@ import org.junit.jupiter.api.Test; import seedu.Pair; +import java.time.LocalDate; import java.util.ArrayList; import java.util.HashMap; @@ -18,12 +19,12 @@ public void updateEquipment_success() throws DuplicateSerialNumberException { EquipmentType.valueOf("SPEAKER"), 1000, "Loud Technologies", - "2022-02-23"); + 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", "2022-03-17")); + 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(); @@ -32,7 +33,7 @@ public void updateEquipment_success() throws DuplicateSerialNumberException { EquipmentType.valueOf("STAND"), 2000, "Louder Technologies", - "2022-03-17"); + LocalDate.parse("2022-03-17")); assertEquals(expectedEquipment, equipments.get("S1404115ASF")); } @@ -42,7 +43,7 @@ public void updateEquipment_keyNotFound() { updates.add(new Pair<>("itemName", "Speaker A")); updates.add(new Pair<>("type", "STAND")); updates.add(new Pair<>("cost", "2000")); - updates.add(new Pair<>("purchaseDate", "2022-03-17")); + 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)); From 19fa96c22425578c154d075509354d911f6cefee Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Thu, 7 Apr 2022 23:50:03 +0800 Subject: [PATCH 164/229] Add LocalDate parsing to CheckCommand --- src/main/java/seedu/command/CheckCommand.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index 132ac4baab..ebd3989756 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -4,6 +4,7 @@ import seedu.equipment.Equipment; import seedu.equipment.EquipmentType; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Locale; @@ -63,7 +64,7 @@ public CommandResult execute() { pair = new Pair<>("itemName", argValue); break; case "pd": - pair = new Pair<>("purchasedDate", argValue); + pair = new Pair<>("purchasedDate", LocalDate.parse(argValue)); break; case "t": pair = new Pair<>("type", EquipmentType.valueOf(argValue.toUpperCase(Locale.ROOT))); From fc74fb33c32e31a0504956077970c67fde5e5817 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Fri, 8 Apr 2022 10:00:48 +0800 Subject: [PATCH 165/229] Remove for loop in CheckCommand#generateCheckPair --- src/main/java/seedu/command/CheckCommand.java | 57 +++++++++---------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index 132ac4baab..060d749876 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -51,35 +51,34 @@ public CommandResult execute() { public Pair generateCheckPair() throws AssertionError, NumberFormatException, IllegalArgumentException { Pair pair = null; - for (String s : commandStrings) { - int delimiterPos = s.indexOf('/'); - // the case where delimiterPos = -1 is impossible as - // ARGUMENT_FORMAT and ARGUMENT_TRAILING_FORMAT regex requires a '/' - assert delimiterPos != -1 : "Each args will need to include minimally a '/' to split arg and value upon"; - String argType = s.substring(0, delimiterPos); - String argValue = s.substring(delimiterPos + 1); - switch (argType) { - case "n": - pair = new Pair<>("itemName", argValue); - break; - case "pd": - pair = new Pair<>("purchasedDate", argValue); - break; - case "t": - pair = new Pair<>("type", EquipmentType.valueOf(argValue.toUpperCase(Locale.ROOT))); - break; - case "pf": - pair = new Pair<>("purchasedFrom", argValue); - break; - case "c": - pair = new Pair<>("cost", Double.valueOf(argValue)); - break; - case "s": - pair = new Pair<>("serialNumber", argValue); - break; - default: - System.out.println("`" + argValue + "` not accepted for type " + argType + ": Unrecognised Tag"); - } + String s = commandStrings.get(0); + int delimiterPos = s.indexOf('/'); + // the case where delimiterPos = -1 is impossible as + // ARGUMENT_FORMAT and ARGUMENT_TRAILING_FORMAT regex requires a '/' + assert delimiterPos != -1 : "Each args will need to include minimally a '/' to split arg and value upon"; + String argType = s.substring(0, delimiterPos); + String argValue = s.substring(delimiterPos + 1); + switch (argType) { + case "n": + pair = new Pair<>("itemName", argValue); + break; + case "pd": + pair = new Pair<>("purchasedDate", argValue); + break; + case "t": + pair = new Pair<>("type", EquipmentType.valueOf(argValue.toUpperCase(Locale.ROOT))); + break; + case "pf": + pair = new Pair<>("purchasedFrom", argValue); + break; + case "c": + pair = new Pair<>("cost", Double.valueOf(argValue)); + break; + case "s": + pair = new Pair<>("serialNumber", argValue); + break; + default: + System.out.println("`" + argValue + "` not accepted for type " + argType + ": Unrecognised Tag"); } return pair; From b883a130975aeee0235c923a3aea7da62e7a3705 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Fri, 8 Apr 2022 14:02:58 +0800 Subject: [PATCH 166/229] Update Project Portfolio Page --- docs/team/yuhao.md | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/docs/team/yuhao.md b/docs/team/yuhao.md index 8b5397fb64..ca18c4044e 100644 --- a/docs/team/yuhao.md +++ b/docs/team/yuhao.md @@ -1,6 +1,37 @@ # Yu Hao - Project Portfolio Page ## Overview +EquipmentManager is a Command Line Interface application to help with keeping track of equipment details (e.g. current user, quantity, cost, warranty duration, purchase date) for an AV club. It provides a clean and fast way to manage the inventory as compared to “traditional” methods such as an Excel spreadsheet. -### Summary of Contributions +## Summary of Contributions +### Code contributed +Code contribution can be found [here](https://nus-cs2113-ay2122s2.github.io/tp-dashboard/?search=yuhaochua&breakdown=true&sort=groupTitle&sortWithin=title&since=2022-02-18&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other). + +### Enhancements implemented +* Mainly in charge of Command classes. Implemented the logic for different commands to call different methods from EquipmentManager to query or make changes to data. +* Implemented UI which displays messages to users and read input from them. + +### Contributions to UG +* Wrote the `Quick Start` section. +* Created table of content. +* Wrote example usage for `Add`, `Check` and `List` commands. +* Drafted cheat sheet for commands. + +### Contributions to DG +* Wrote explanation for the implementation of Command classes. +* Added object and sequence diagrams used in explaining flow of updating equipment. + +### Contributions to team-based tasks +* Took meeting minutes and tracked to-do tasks for the team. + +### Review/mentoring contributions +* Pull requests reviewed (only listed those with significant comments/discussion): + - [Reviewed implementation of Equipment related classes](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/29) + - [Reviewed implementation of Parser](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/31) + - [Reviewed Storage implementation](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/53) + - [Reviewed usage of Pair class in EquipmentManager](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/63) + - [Reviewed implementation of Date format](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/124) + +### Contributions beyond the project team +* Filed bug reports for another team [here](https://github.com/AY2122S2-CS2113T-T09-1/tp/issues/101) and [here](https://github.com/AY2122S2-CS2113T-T09-1/tp/issues/109) \ No newline at end of file From 309230c9f2de5aec86932df63c191d27cff2123e Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Fri, 8 Apr 2022 14:03:26 +0800 Subject: [PATCH 167/229] Minor edit to documentation in DeveloperGuide and UserGuide --- docs/DeveloperGuide.md | 2 +- docs/UserGuide.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 8f8b5977b8..f13e9f0ae6 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -88,7 +88,7 @@ Throughout the `Parser` implementation, exceptions were used to return `Incorrec The update feature is facilitated by `UpdateCommand`. It extends `ModificationCommand` and implements the following operations: * `UpdateCommand#generateUpdatePairs()` — Generates pairs of attributes and their update values. -* `VersionedAddressBook#generateUpdateString()` — Generates sString with details of the update executed. +* `UpdateCommand#generateUpdateString()` — Generates String with details of the update executed. Given below is an example usage scenario and how the update feature behaves at each step. diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 1f8b0a85c8..ec5bfffe44 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -1,6 +1,6 @@ # User Guide -## Introduction +## Overview EquipmentManager is a Command Line Interface application to help with keeping track of equipment details (e.g. current user, quantity, cost, warranty duration, purchase date) for an AV club. It provides a clean and fast way to manage the inventory as compared to “traditional” methods such as an Excel spreadsheet. @@ -15,7 +15,7 @@ EquipmentManager is a Command Line Interface application to help with keeping tr ## Features -- [Introduction](#Introduction) +- [Introduction](#introduction) - [Adding an equipment: `add`](#adding-an-equipment-add) - [Checking an equipment: `check`](#checking-an-equipment-check) - [Listing equipment: `list`](#listing-equipment-list) From 45d952075759bd81d154e0f15960ebe3b441409a Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Fri, 8 Apr 2022 14:10:22 +0800 Subject: [PATCH 168/229] Edit sublist style for review contributions --- docs/team/yuhao.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/team/yuhao.md b/docs/team/yuhao.md index ca18c4044e..8f2e9f13c0 100644 --- a/docs/team/yuhao.md +++ b/docs/team/yuhao.md @@ -27,11 +27,11 @@ Code contribution can be found [here](https://nus-cs2113-ay2122s2.github.io/tp-d ### Review/mentoring contributions * Pull requests reviewed (only listed those with significant comments/discussion): - - [Reviewed implementation of Equipment related classes](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/29) - - [Reviewed implementation of Parser](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/31) - - [Reviewed Storage implementation](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/53) - - [Reviewed usage of Pair class in EquipmentManager](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/63) - - [Reviewed implementation of Date format](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/124) + 1.[Reviewed implementation of Equipment related classes](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/29) + 2. [Reviewed implementation of Parser](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/31) + 3. [Reviewed Storage implementation](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/53) + 4. [Reviewed usage of Pair class in EquipmentManager](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/63) + 5. [Reviewed implementation of Date format](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/124) ### Contributions beyond the project team * Filed bug reports for another team [here](https://github.com/AY2122S2-CS2113T-T09-1/tp/issues/101) and [here](https://github.com/AY2122S2-CS2113T-T09-1/tp/issues/109) \ No newline at end of file From fc54558514e20676089a7026d5c20a9280c23573 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Fri, 8 Apr 2022 14:12:27 +0800 Subject: [PATCH 169/229] Update sublist --- docs/team/yuhao.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/team/yuhao.md b/docs/team/yuhao.md index 8f2e9f13c0..682df59731 100644 --- a/docs/team/yuhao.md +++ b/docs/team/yuhao.md @@ -27,7 +27,7 @@ Code contribution can be found [here](https://nus-cs2113-ay2122s2.github.io/tp-d ### Review/mentoring contributions * Pull requests reviewed (only listed those with significant comments/discussion): - 1.[Reviewed implementation of Equipment related classes](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/29) + 1. [Reviewed implementation of Equipment related classes](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/29) 2. [Reviewed implementation of Parser](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/31) 3. [Reviewed Storage implementation](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/53) 4. [Reviewed usage of Pair class in EquipmentManager](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/63) From 0468964e2b706c708edf9045577158e5bfa63f03 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Fri, 8 Apr 2022 14:22:05 +0800 Subject: [PATCH 170/229] Fix references to Project Portfolio Pages --- docs/AboutUs.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 5b04a53b87..77f80b0c01 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,7 +1,7 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:------------:|:---------------------------------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | Bryan Christopher | [Github](https://github.com/Bryan-BC) | [Portfolio](docs/team/bryanchristopher.md) -![](https://via.placeholder.com/100.png?text=Photo) | Bai Shun Yao | [Github](https://github.com/shunyao643) | [Portfolio](docs/team/shunyao.md) -![](https://via.placeholder.com/100.png?text=Photo) | Yu Hao | [Github](https://github.com/yuhaochua) | [Portfolio](docs/team/yuhao.md) +| Display | Name | Github Profile | Portfolio | +|-----------------------------------------------------|:-----------------:|:---------------------------------------:|:-------------------------------------:| +| ![](https://via.placeholder.com/100.png?text=Photo) | Bryan Christopher | [Github](https://github.com/Bryan-BC) | [Portfolio](team/bryanchristopher.md) | +| ![](https://via.placeholder.com/100.png?text=Photo) | Bai Shun Yao | [Github](https://github.com/shunyao643) | [Portfolio](team/shunyao.md) | +| ![](https://via.placeholder.com/100.png?text=Photo) | Yu Hao | [Github](https://github.com/yuhaochua) | [Portfolio](team/yuhao.md) | From d89d1023746ad80c5cd9b207b693aa3194ede2ec Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Fri, 8 Apr 2022 15:44:48 +0800 Subject: [PATCH 171/229] Refactor UserGuide.md to include code blocks and update some command details. --- docs/UserGuide.md | 144 ++++++++++-------- src/main/java/seedu/command/CheckCommand.java | 6 +- src/main/java/seedu/command/ListCommand.java | 4 +- 3 files changed, 86 insertions(+), 68 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 1f8b0a85c8..beb79920ad 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -28,17 +28,17 @@ EquipmentManager is a Command Line Interface application to help with keeping tr ### Introduction -* Words in `UPPER_CASE` are the parameters to be supplied by the user. Spaces are acceptable.
- e.g. in `check n/ITEM_NAME`, `ITEM_NAME` is a parameter which can be used as `check n/SM-57`. +* Words in `UPPER_CASE` are the parameters to be supplied by the user. Spaces are acceptable. However, the parameter must be enclosed in backtick.
+ e.g. in ``check n/`ITEM_NAME` ``, `ITEM_NAME` is a parameter which can be used as ``check n/`SM-57` ``. * Items in square brackets are optional.
- e.g. `s/SERIAL_NUMBER [n/ITEM_NAME] [t/TYPE] ...` can be used as `s/SM57-1 n/SM57 t/MICROPHONE...` or as `s/SM57-1 t/MICROPHONE...`. + e.g. ``s/`SERIAL_NUMBER` [n/`ITEM_NAME`] [t/`TYPE`] ...`` can be used as ``s/`SM57-1` n/`SM57` t/`MICROPHONE`...`` or as ``s/`SM57-1` t/`MICROPHONE`...``. * After the command word (e.g. `add`, `update`), parameters can be in any order.
- e.g. if the command specifies `... s/SERIAL_NUMBER n/ITEM_NAME...`, `n/ITEM_NAME s/SERIAL_NUMBER` is also acceptable. + e.g. if the command specifies ``... s/`SERIAL_NUMBER` n/`ITEM_NAME`...``, ``n/`ITEM_NAME` s/`SERIAL_NUMBER` `` is also acceptable. * Only one attribute/value can be saved per parameter. Where multiple inputs are supplied, the last parameter will be taken instead of the first one.
- e.g. `... n/ITEM_NAME_1 n/ITEM_NAME_2` will be interpreted as `... n/ITEM_NAME_2`, omitting `n/ITEM_NAME_1` entirely. + e.g. ``... n/`ITEM_NAME_1` n/`ITEM_NAME_2` `` will be interpreted as ``... n/`ITEM_NAME_2` ``, omitting ``n/`ITEM_NAME_1` `` entirely. * Extraneous parameters for commands that do not take in parameters (such as `help`, `bye` and `save`) will be ignored.
e.g. if the command specifies `help 123`, it will be interpreted as `help`. @@ -57,53 +57,61 @@ Example of usage and output: ``add n/`SpeakerB` s/`S1404115ASF` t/`Speaker` c/`1000` pf/`Loud_Technologies` pd/`2022-02-23` `` -output: `Equipment successfully added: SpeakerB, serial number S1404115ASF` +Output: + +``` +Equipment successfully added: SpeakerB, serial number S1404115ASF +``` ### Checking an equipment: `check` -Check the details of the equipment that has the name specified. +Check the details of the equipments that matches the specified parameter. + +Format: ``check parameter/`PARAMETER_VALUE` `` -Format: ``check n/`ITEM_NAME` `` +e.g. ``check n/`ITEM_NAME` `` or ``check s/`SERIAL_NUMBER` `` or ``check t/`TYPE` `` -* Only the `ITEM_NAME` can be used to check for a piece of equipment. +* Only one parameter can be used to check for a piece of equipment. Example of usage and output: ``check n/`SpeakerB` `` -output: +Output: -`Here are the equipment matching to 'SpeakerB':` - -`1. serialNumber=S1404115ASF,itemName=SpeakerB,type=SPEAKER,cost=1000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-02-23` +``` +Here are the equipment matching to 'SpeakerB': +1. serialNumber=S1404115ASF,itemName=SpeakerB,type=SPEAKER,cost=1000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-02-23 +``` ### Listing equipment: `list` Print a list of all equipment in the inventory. If a parameter is supplied, only the equipment matching to the parameter will be printed. -Format: `list [PARAMETER_NAME]` +Format: ``list [t/`TYPE`]`` -* `PARAMETER_NAME` can only take on values of `SPEAKER`, `MICROPHONE`, `STAND`, `CABLE`. +* `TYPE` can only take on values of `SPEAKER`, `MICROPHONE`, `STAND`, `CABLE`. Example of usage and output: `list` -output: - -`TOTAL QUANTITY OF EQUIPMENT: 2` - -`1. serialNumber=S89347971ASF,itemName=MicrophoneC,type=MICROPHONE,cost=2000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-01-21` +Output: -`2. serialNumber=S1404115ASF,itemName=SpeakerB,type=SPEAKER,cost=1000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-02-23` +``` +TOTAL QUANTITY OF EQUIPMENT: 2 +1. serialNumber=S89347971ASF,itemName=MicrophoneC,type=MICROPHONE,cost=2000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-01-21 +2. serialNumber=S1404115ASF,itemName=SpeakerB,type=SPEAKER,cost=1000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-02-23 +``` Example of usage and output: -`list microphone` - -output: +``list t/`MICROPHONE` `` -`TOTAL QUANTITY OF EQUIPMENT: 1` +Output: -`1. serialNumber=S89347971ASF,itemName=MicrophoneC,type=MICROPHONE,cost=2000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-01-21` +``` +TOTAL QUANTITY OF EQUIPMENT: 1 +1. serialNumber=S89347971ASF,itemName=MicrophoneC,type=MICROPHONE,cost=2000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-01-21 +``` ### Updating an equipment: `update` @@ -118,12 +126,14 @@ Example of usage and output: ``update s/`S14115ASF` c/`1200` pf/`AVLFX` `` -output: +Output: -`Equipment successfully updated for serial number S14115ASF,`
-`Updated details are:`
-`New cost: 1200.0`
-`New purchased from: AVLFX`
+``` +Equipment successfully updated for serial number S14115ASF, +Updated details are: +New cost: 1200.0 +New purchased from: AVLFX +``` ### Deleting an equipment: `delete` @@ -135,9 +145,11 @@ Example of usage and output: ``delete s/`S14115ASF` `` -output: +Output: -`Equipment successfully deleted: SpeakerB, serial number S14115ASF` +``` +Equipment successfully deleted: SpeakerB, serial number S14115ASF +``` ### Saving application state: `save` @@ -151,7 +163,9 @@ Example of usage and output: Output: -`Successfully saved.` +``` +Successfully saved. +``` ### Getting help: `help` @@ -165,42 +179,44 @@ Example of usage and output: Output: -`add: Adds a Equipment to the equipmentInventory.`
-``Parameters: n/`ITEM NAME` s/`SERIAL NUMBER` t/`TYPE` c/`COST` pf/`PURCHASED FROM` pd/`PURCHASED DATE` ``
-``Example: add n/`SpeakerB` s/`S1404115ASF` t/`Speaker` c/`1000` pf/`Loud_Technologies` pd/`2022-02-23` ``
+``` +add: Adds a Equipment to the equipmentInventory. +Parameters: n/`ITEM NAME` s/`SERIAL NUMBER` t/`TYPE` c/`COST` pf/`PURCHASED FROM` pd/`PURCHASED DATE` +Example: add n/`SpeakerB` s/`S1404115ASF` t/`Speaker` c/`1000` pf/`Loud_Technologies` pd/`2022-02-23` -`delete: Deletes the equipment with the specified serial number.`
-``Parameters: s/`SERIAL_NUMBER` ``
-``Example: delete s/`SM57-1` ``
+delete: Deletes the equipment with the specified serial number. +Parameters: s/`SERIAL_NUMBER` +Example: delete s/`SM57-1` -`update: Updates the equipment with the specified serial number.`
-`Parameters in [square brackets] are optional.`
-``Parameters: s/`SERIAL NUMBER` [n/`ITEM NAME`] [t/`TYPE`] [c/`COST`] [pf/`PURCHASED FROM`] [pd/`PURCHASED DATE`]``
-``Example: update s/`SM57-1` n/`SpeakerC` c/`2510` pd/`2022-08-21` ``
+update: Updates the equipment with the specified serial number. +Parameters in [square brackets] are optional. +Parameters: s/`SERIAL NUMBER` [n/`ITEM NAME`] [t/`TYPE`] [c/`COST`] [pf/`PURCHASED FROM`] [pd/`PURCHASED DATE`] +Example: update s/`SM57-1` n/`SpeakerC` c/`2510` pd/`2022-08-21` -`list: Prints a list of all equipment in the inventory.`
-`Parameters: NIL`
-`Example: list`
+list: Prints a list of all equipment in the inventory. +Parameters: NIL +Example: list -`list: Prints a list of all equipment in the inventory of the specified type.`
-``Parameters: `Type` ``
-`Example: list MICROPHONE`
+list: Prints a list of all equipment in the inventory of the specified type. +Parameters: `TYPE` +Example: list t/`MICROPHONE` -`check: Gives details of the equipment with the specified name.`
-``Parameters: n/`ITEM_NAME` ``
-``Example: check n/`MixerC` ``
+check: Check the details of the equipments that matches the specified parameter. +Parameters: parameter/`PARAMETER_VALUE` +Example: check n/`MixerC` or check s/`SM57-1` or check t/`MICROPHONE` -`save: Saves current state of application.`
-`Parameters: NIL`
-`Example: save`
+save: Saves current state of application. +Parameters: NIL +Example: save -`bye: Exits the application.`
-`Parameters: NIL`
-`Example: bye`
+bye: Exits the application. +Parameters: NIL +Example: bye -`help: Shows details of available commands to users.`
-`Parameters: NIL`
-`Example: help`
+help: Shows details of available commands to users. +Parameters: NIL +Example: help +``` ### Exiting the application: `bye` @@ -214,7 +230,9 @@ Example of usage and output: Output: -`Bye, See you again!` +``` +Bye, See you again! +``` ## FAQ diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index 88016f6978..11e94fc8af 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -14,11 +14,11 @@ public class CheckCommand extends Command { private final ArrayList commandStrings; public static final String COMMAND_WORD = "check"; - public static final String COMMAND_DESCRIPTION = ": Gives details of the equipment with the specified name. " + public static final String COMMAND_DESCRIPTION = ": Check the details of the equipments that matches the specified parameter. " + System.lineSeparator() - + "Parameters: n/`ITEM_NAME`" + System.lineSeparator() + + "Parameters: parameter/`PARAMETER_VALUE`" + System.lineSeparator() + "Example: " - + "check n/`MixerC`"; + + "check n/`MixerC` or check s/`SM57-1` or check t/`MICROPHONE`"; /** * constructor for CheckCommand. Initialises successMessage and usageReminder from Command diff --git a/src/main/java/seedu/command/ListCommand.java b/src/main/java/seedu/command/ListCommand.java index ee1b031e5c..05b318039e 100644 --- a/src/main/java/seedu/command/ListCommand.java +++ b/src/main/java/seedu/command/ListCommand.java @@ -20,9 +20,9 @@ public class ListCommand extends Command { public static final String COMMAND_DESCRIPTION_WITH_TYPE = ": Prints a list of all equipment in the inventory of the specified type. " + System.lineSeparator() - + "Parameters: `Type`" + System.lineSeparator() + + "Parameters: `TYPE`" + System.lineSeparator() + "Example: " - + "list MICROPHONE"; + + "list t/`MICROPHONE`"; /** * constructor for ListCommand with NO specified type. Initialises successMessage and usageReminder from Command From 8966f2ecb01e61372b9a4b1b7b6450b59a9cd743 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Fri, 8 Apr 2022 15:52:58 +0800 Subject: [PATCH 172/229] Update Shun Yao's PPP --- docs/team/shunyao.md | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/docs/team/shunyao.md b/docs/team/shunyao.md index ae8473018a..8188ab2db9 100644 --- a/docs/team/shunyao.md +++ b/docs/team/shunyao.md @@ -1,6 +1,42 @@ # Bai Shun Yao - Project Portfolio Page ## Overview +EquipmentManager is a Command Line Interface application to help with keeping track of equipment details (e.g. current user, quantity, cost, warranty duration, purchase date) for an AV club. It provides a clean and fast way to manage the inventory as compared to “traditional” methods such as an Excel spreadsheet. -### Summary of Contributions +## Summary of Contributions +### Code contributed +Code contribution can be found [here](https://nus-cs2113-ay2122s2.github.io/tp-dashboard/?search=shunyao643&breakdown=true&sort=groupTitle&sortWithin=title&since=2022-02-18&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other). + +### Enhancements implemented +* In charge of the parsing of commands prior to command execution. Parser implements a regex-based approach to parsing commands. + +### Contributions to UG +* Add top-level introduction summary. +* Draft example usage for `Update`, `Delete` and `List` (by type) commands. +* Supplement cheat sheet for commands. + +### Contributions to DG +* Wrote Acknowledgements, Architecture summary, Parser and Product Scope. +* Update user-stories and non-functional requirements in line with progress of the project. + +### Contributions to team-based tasks +* Set up GitHub team organisation and repository. +* Maintain issue tracker throughout project with the use of assignees, labels, closing statements and milestones. +* Manage release of v1.0 of the project. + +### Review/mentoring contributions +* Pull requests reviewed (only listed those with significant comments/discussion): + 1. [Reviewed implementation of Commands](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/24) + 2. [Reviewed unordered tag implementation for add command](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/57) + 3. [Reviewed revisions to check command](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/118) + 4. [Reviewed revisions to delete command](https://github.com/AY2122S2-CS2113-F12-2/tp/pull/119) +* Suggest usage of GSON library for file I/O. + +### Contributions beyond the project team +* Reviewed DeveloperGuide.md for another team [here](https://github.com/nus-cs2113-AY2122S2/tp/pull/5) +* Filed bug reports for another team. Examples: + * [Inconsistent usage of code formatting](https://github.com/AY2122S2-CS2113-T11-4/tp/issues/119) + * [No option for multi-step commands](https://github.com/AY2122S2-CS2113-T11-4/tp/issues/129) + * [Salary information required but cannot be accessed or used at all](https://github.com/AY2122S2-CS2113-T11-4/tp/issues/133) + * [Staff are required to memorise order menu by index](https://github.com/AY2122S2-CS2113-T11-4/tp/issues/125) \ No newline at end of file From d16e4687e2aa6826f31585dca95aad2a5c718883 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Fri, 8 Apr 2022 15:56:00 +0800 Subject: [PATCH 173/229] Update portfolio for bryanchristopher.md --- docs/team/bryanchristopher.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/team/bryanchristopher.md b/docs/team/bryanchristopher.md index 3d1def5983..9db3627ee9 100644 --- a/docs/team/bryanchristopher.md +++ b/docs/team/bryanchristopher.md @@ -1,6 +1,20 @@ # Bryan Christopher - Project Portfolio Page ## Overview +EquipmentManager is a Command Line Interface application to help with keeping track of equipment details (e.g. current user, quantity, cost, warranty duration, purchase date) for an AV club. It provides a clean and fast way to manage the inventory as compared to “traditional” methods such as an Excel spreadsheet. +## Summary of Contributions +Besides reviewing pull requests and participating in discussions during meetings, below are the main contributions made to the project: -### Summary of Contributions +## Contributions to the Codebase +* Implementation of the classes in the equipment package. +* Implementation of the classes in the storage package. +* Implementation of Gson for serialization and deserialization of the data. + +### Contributions to the UG +* Updated the documentation to reflect the changes made to the codebase. +* Wrote the `list`, `help`, `save`, and `delete` commands in UG + +### Contributions to the DG +* Wrote the `Equipment Manager` part of DG. +* Wrote the `Storage` part of DG. From 27e0955a36132d431fefa6c455ebad1bc7e2f742 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Fri, 8 Apr 2022 21:32:20 +0800 Subject: [PATCH 174/229] Refactor error messages from ModificationCommand into Command --- src/main/java/seedu/command/Command.java | 7 +++++-- src/main/java/seedu/command/ModificationCommand.java | 5 ----- src/main/java/seedu/parser/Parser.java | 11 +++++------ 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/main/java/seedu/command/Command.java b/src/main/java/seedu/command/Command.java index 8c3a039881..3a0b284832 100644 --- a/src/main/java/seedu/command/Command.java +++ b/src/main/java/seedu/command/Command.java @@ -1,6 +1,7 @@ package seedu.command; import seedu.equipment.EquipmentManager; +import seedu.equipment.EquipmentType; import seedu.storage.Storage; /** @@ -13,11 +14,13 @@ public abstract class Command { public String usageReminder; protected EquipmentManager equipmentManager; protected Storage storage; - public static final String INCORRECT_ENUM_TYPE = "Wrong type of equipment. The allowed types are: " - + "MICROPHONE, SPEAKER, STAND, CABLE"; + public static final String INCORRECT_ENUM_TYPE = "Equipment Type needs to be one of:" + System.lineSeparator() + + EquipmentType.getAllTypes(); public static final String INCORRECT_COST_FORMAT = "Please enter numbers only for cost and omit symbols"; public static final String INVALID_SERIAL_NUMBER = "No such serial number, please enter an existing " + "serial number"; + public static final String INVALID_DATE_MESSAGE = "Date needs to be able to be parsed, make sure you're using " + + "YYYY-MM-DD format"; public static final String MISSING_SERIAL_NUMBER = "Serial Number is required to run this command"; public abstract CommandResult execute(); diff --git a/src/main/java/seedu/command/ModificationCommand.java b/src/main/java/seedu/command/ModificationCommand.java index fa138ecf43..88efa03025 100644 --- a/src/main/java/seedu/command/ModificationCommand.java +++ b/src/main/java/seedu/command/ModificationCommand.java @@ -14,11 +14,6 @@ public class ModificationCommand extends Command { public static final String IMPLEMENTED_BY_CHILD = "Execute method for Modification should be implemented by " + "child classes AddCommand and UpdateCommand"; - public static final String INVALID_TYPE_MESSAGE = "Equipment Type needs to be one of:" + System.lineSeparator() - + EquipmentType.getAllTypes(); - public static final String INVALID_COST_MESSAGE = "Cost needs to be able to be parsed to a double"; - public static final String INVALID_DATE_MESSAGE = "Date needs to be able to be parsed, make sure you're using " - + "YYYY-MM-DD format"; protected final ArrayList commandStrings; protected String serialNumber; protected String equipmentName = null; diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index ce2025aebc..9fa9c50513 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import seedu.command.AddCommand; -import seedu.command.ModificationCommand; import seedu.command.UpdateCommand; import seedu.command.ListCommand; import seedu.command.IncorrectCommand; @@ -111,16 +110,16 @@ public Command parseCommand(String userInput) { } catch (IncompleteCommandException e) { return new IncorrectCommand(AddCommand.COMMAND_WORD + AddCommand.COMMAND_DESCRIPTION); } catch (NumberFormatException e) { - return new IncorrectCommand(ModificationCommand.INVALID_COST_MESSAGE); + return new IncorrectCommand(Command.INCORRECT_COST_FORMAT); } catch (IllegalArgumentException e) { - return new IncorrectCommand(ModificationCommand.INVALID_TYPE_MESSAGE); + 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(ModificationCommand.INVALID_DATE_MESSAGE); + return new IncorrectCommand(Command.INVALID_DATE_MESSAGE); } case CheckCommand.COMMAND_WORD: try { @@ -147,9 +146,9 @@ public Command parseCommand(String userInput) { } catch (IncompleteCommandException e) { return new IncorrectCommand(UpdateCommand.COMMAND_WORD + UpdateCommand.COMMAND_DESCRIPTION); } catch (NumberFormatException e) { - return new IncorrectCommand(ModificationCommand.INVALID_COST_MESSAGE); + return new IncorrectCommand(Command.INCORRECT_COST_FORMAT); } catch (IllegalArgumentException e) { - return new IncorrectCommand(ModificationCommand.INVALID_TYPE_MESSAGE); + return new IncorrectCommand(Command.INCORRECT_ENUM_TYPE); } case ListCommand.COMMAND_WORD: if (arguments == null) { From ec2760932cb7c101cd0e5b1917ab1407272a07d5 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Fri, 8 Apr 2022 22:01:45 +0800 Subject: [PATCH 175/229] Rename Shun Yao's PPP in line with requirements --- docs/team/{shunyao.md => shunyao643.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/team/{shunyao.md => shunyao643.md} (100%) diff --git a/docs/team/shunyao.md b/docs/team/shunyao643.md similarity index 100% rename from docs/team/shunyao.md rename to docs/team/shunyao643.md From f31eed43d17bcb8b8ebcf74225ac7ab91cbf83b3 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Fri, 8 Apr 2022 22:49:10 +0800 Subject: [PATCH 176/229] Add support for LocalDate in Storage --- .../java/seedu/storage/LocalDateAdapter.java | 44 +++++++++++++++++++ src/main/java/seedu/storage/Storage.java | 15 ++++++- 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 src/main/java/seedu/storage/LocalDateAdapter.java diff --git a/src/main/java/seedu/storage/LocalDateAdapter.java b/src/main/java/seedu/storage/LocalDateAdapter.java new file mode 100644 index 0000000000..cb4bf28143 --- /dev/null +++ b/src/main/java/seedu/storage/LocalDateAdapter.java @@ -0,0 +1,44 @@ +package seedu.storage; + +import com.google.gson.*; +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 index 486d474962..ed2feeeb4e 100644 --- a/src/main/java/seedu/storage/Storage.java +++ b/src/main/java/seedu/storage/Storage.java @@ -1,6 +1,7 @@ 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; @@ -10,6 +11,8 @@ 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; @@ -20,7 +23,13 @@ public class Storage { 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 final Gson gson = new Gson(); + 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 @@ -38,6 +47,10 @@ public void loadData(EquipmentManager equipmentManager) { 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); } } From 0bf50e988924ed2830d76e1768c835210ecf7172 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Fri, 8 Apr 2022 22:49:10 +0800 Subject: [PATCH 177/229] Add support for LocalDate in Storage --- .../java/seedu/storage/LocalDateAdapter.java | 44 +++++++++++++++++++ src/main/java/seedu/storage/Storage.java | 15 ++++++- 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 src/main/java/seedu/storage/LocalDateAdapter.java diff --git a/src/main/java/seedu/storage/LocalDateAdapter.java b/src/main/java/seedu/storage/LocalDateAdapter.java new file mode 100644 index 0000000000..cb4bf28143 --- /dev/null +++ b/src/main/java/seedu/storage/LocalDateAdapter.java @@ -0,0 +1,44 @@ +package seedu.storage; + +import com.google.gson.*; +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 index 486d474962..ed2feeeb4e 100644 --- a/src/main/java/seedu/storage/Storage.java +++ b/src/main/java/seedu/storage/Storage.java @@ -1,6 +1,7 @@ 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; @@ -10,6 +11,8 @@ 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; @@ -20,7 +23,13 @@ public class Storage { 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 final Gson gson = new Gson(); + 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 @@ -38,6 +47,10 @@ public void loadData(EquipmentManager equipmentManager) { 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); } } From 3af7ab41b040cc8e6613df9ed377d62894dd6f7f Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Fri, 8 Apr 2022 15:44:48 +0800 Subject: [PATCH 178/229] Refactor UserGuide.md to include code blocks and update some command details. --- docs/UserGuide.md | 144 ++++++++++-------- src/main/java/seedu/command/CheckCommand.java | 6 +- src/main/java/seedu/command/ListCommand.java | 4 +- 3 files changed, 86 insertions(+), 68 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index ec5bfffe44..cf391381b5 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -28,17 +28,17 @@ EquipmentManager is a Command Line Interface application to help with keeping tr ### Introduction -* Words in `UPPER_CASE` are the parameters to be supplied by the user. Spaces are acceptable.
- e.g. in `check n/ITEM_NAME`, `ITEM_NAME` is a parameter which can be used as `check n/SM-57`. +* Words in `UPPER_CASE` are the parameters to be supplied by the user. Spaces are acceptable. However, the parameter must be enclosed in backtick.
+ e.g. in ``check n/`ITEM_NAME` ``, `ITEM_NAME` is a parameter which can be used as ``check n/`SM-57` ``. * Items in square brackets are optional.
- e.g. `s/SERIAL_NUMBER [n/ITEM_NAME] [t/TYPE] ...` can be used as `s/SM57-1 n/SM57 t/MICROPHONE...` or as `s/SM57-1 t/MICROPHONE...`. + e.g. ``s/`SERIAL_NUMBER` [n/`ITEM_NAME`] [t/`TYPE`] ...`` can be used as ``s/`SM57-1` n/`SM57` t/`MICROPHONE`...`` or as ``s/`SM57-1` t/`MICROPHONE`...``. * After the command word (e.g. `add`, `update`), parameters can be in any order.
- e.g. if the command specifies `... s/SERIAL_NUMBER n/ITEM_NAME...`, `n/ITEM_NAME s/SERIAL_NUMBER` is also acceptable. + e.g. if the command specifies ``... s/`SERIAL_NUMBER` n/`ITEM_NAME`...``, ``n/`ITEM_NAME` s/`SERIAL_NUMBER` `` is also acceptable. * Only one attribute/value can be saved per parameter. Where multiple inputs are supplied, the last parameter will be taken instead of the first one.
- e.g. `... n/ITEM_NAME_1 n/ITEM_NAME_2` will be interpreted as `... n/ITEM_NAME_2`, omitting `n/ITEM_NAME_1` entirely. + e.g. ``... n/`ITEM_NAME_1` n/`ITEM_NAME_2` `` will be interpreted as ``... n/`ITEM_NAME_2` ``, omitting ``n/`ITEM_NAME_1` `` entirely. * Extraneous parameters for commands that do not take in parameters (such as `help`, `bye` and `save`) will be ignored.
e.g. if the command specifies `help 123`, it will be interpreted as `help`. @@ -57,53 +57,61 @@ Example of usage and output: ``add n/`SpeakerB` s/`S1404115ASF` t/`Speaker` c/`1000` pf/`Loud_Technologies` pd/`2022-02-23` `` -output: `Equipment successfully added: SpeakerB, serial number S1404115ASF` +Output: + +``` +Equipment successfully added: SpeakerB, serial number S1404115ASF +``` ### Checking an equipment: `check` -Check the details of the equipment that has the name specified. +Check the details of the equipments that matches the specified parameter. + +Format: ``check parameter/`PARAMETER_VALUE` `` -Format: ``check n/`ITEM_NAME` `` +e.g. ``check n/`ITEM_NAME` `` or ``check s/`SERIAL_NUMBER` `` or ``check t/`TYPE` `` -* Only the `ITEM_NAME` can be used to check for a piece of equipment. +* Only one parameter can be used to check for a piece of equipment. Example of usage and output: ``check n/`SpeakerB` `` -output: +Output: -`Here are the equipment matching to 'SpeakerB':` - -`1. serialNumber=S1404115ASF,itemName=SpeakerB,type=SPEAKER,cost=1000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-02-23` +``` +Here are the equipment matching to 'SpeakerB': +1. serialNumber=S1404115ASF,itemName=SpeakerB,type=SPEAKER,cost=1000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-02-23 +``` ### Listing equipment: `list` Print a list of all equipment in the inventory. If a parameter is supplied, only the equipment matching to the parameter will be printed. -Format: `list [PARAMETER_NAME]` +Format: ``list [t/`TYPE`]`` -* `PARAMETER_NAME` can only take on values of `SPEAKER`, `MICROPHONE`, `STAND`, `CABLE`. +* `TYPE` can only take on values of `SPEAKER`, `MICROPHONE`, `STAND`, `CABLE`. Example of usage and output: `list` -output: - -`TOTAL QUANTITY OF EQUIPMENT: 2` - -`1. serialNumber=S89347971ASF,itemName=MicrophoneC,type=MICROPHONE,cost=2000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-01-21` +Output: -`2. serialNumber=S1404115ASF,itemName=SpeakerB,type=SPEAKER,cost=1000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-02-23` +``` +TOTAL QUANTITY OF EQUIPMENT: 2 +1. serialNumber=S89347971ASF,itemName=MicrophoneC,type=MICROPHONE,cost=2000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-01-21 +2. serialNumber=S1404115ASF,itemName=SpeakerB,type=SPEAKER,cost=1000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-02-23 +``` Example of usage and output: -`list microphone` - -output: +``list t/`MICROPHONE` `` -`TOTAL QUANTITY OF EQUIPMENT: 1` +Output: -`1. serialNumber=S89347971ASF,itemName=MicrophoneC,type=MICROPHONE,cost=2000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-01-21` +``` +TOTAL QUANTITY OF EQUIPMENT: 1 +1. serialNumber=S89347971ASF,itemName=MicrophoneC,type=MICROPHONE,cost=2000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-01-21 +``` ### Updating an equipment: `update` @@ -118,12 +126,14 @@ Example of usage and output: ``update s/`S14115ASF` c/`1200` pf/`AVLFX` `` -output: +Output: -`Equipment successfully updated for serial number S14115ASF,`
-`Updated details are:`
-`New cost: 1200.0`
-`New purchased from: AVLFX`
+``` +Equipment successfully updated for serial number S14115ASF, +Updated details are: +New cost: 1200.0 +New purchased from: AVLFX +``` ### Deleting an equipment: `delete` @@ -135,9 +145,11 @@ Example of usage and output: ``delete s/`S14115ASF` `` -output: +Output: -`Equipment successfully deleted: SpeakerB, serial number S14115ASF` +``` +Equipment successfully deleted: SpeakerB, serial number S14115ASF +``` ### Saving application state: `save` @@ -151,7 +163,9 @@ Example of usage and output: Output: -`Successfully saved.` +``` +Successfully saved. +``` ### Getting help: `help` @@ -165,42 +179,44 @@ Example of usage and output: Output: -`add: Adds a Equipment to the equipmentInventory.`
-``Parameters: n/`ITEM NAME` s/`SERIAL NUMBER` t/`TYPE` c/`COST` pf/`PURCHASED FROM` pd/`PURCHASED DATE` ``
-``Example: add n/`SpeakerB` s/`S1404115ASF` t/`Speaker` c/`1000` pf/`Loud_Technologies` pd/`2022-02-23` ``
+``` +add: Adds a Equipment to the equipmentInventory. +Parameters: n/`ITEM NAME` s/`SERIAL NUMBER` t/`TYPE` c/`COST` pf/`PURCHASED FROM` pd/`PURCHASED DATE` +Example: add n/`SpeakerB` s/`S1404115ASF` t/`Speaker` c/`1000` pf/`Loud_Technologies` pd/`2022-02-23` -`delete: Deletes the equipment with the specified serial number.`
-``Parameters: s/`SERIAL_NUMBER` ``
-``Example: delete s/`SM57-1` ``
+delete: Deletes the equipment with the specified serial number. +Parameters: s/`SERIAL_NUMBER` +Example: delete s/`SM57-1` -`update: Updates the equipment with the specified serial number.`
-`Parameters in [square brackets] are optional.`
-``Parameters: s/`SERIAL NUMBER` [n/`ITEM NAME`] [t/`TYPE`] [c/`COST`] [pf/`PURCHASED FROM`] [pd/`PURCHASED DATE`]``
-``Example: update s/`SM57-1` n/`SpeakerC` c/`2510` pd/`2022-08-21` ``
+update: Updates the equipment with the specified serial number. +Parameters in [square brackets] are optional. +Parameters: s/`SERIAL NUMBER` [n/`ITEM NAME`] [t/`TYPE`] [c/`COST`] [pf/`PURCHASED FROM`] [pd/`PURCHASED DATE`] +Example: update s/`SM57-1` n/`SpeakerC` c/`2510` pd/`2022-08-21` -`list: Prints a list of all equipment in the inventory.`
-`Parameters: NIL`
-`Example: list`
+list: Prints a list of all equipment in the inventory. +Parameters: NIL +Example: list -`list: Prints a list of all equipment in the inventory of the specified type.`
-``Parameters: `Type` ``
-`Example: list MICROPHONE`
+list: Prints a list of all equipment in the inventory of the specified type. +Parameters: `TYPE` +Example: list t/`MICROPHONE` -`check: Gives details of the equipment with the specified name.`
-``Parameters: n/`ITEM_NAME` ``
-``Example: check n/`MixerC` ``
+check: Check the details of the equipments that matches the specified parameter. +Parameters: parameter/`PARAMETER_VALUE` +Example: check n/`MixerC` or check s/`SM57-1` or check t/`MICROPHONE` -`save: Saves current state of application.`
-`Parameters: NIL`
-`Example: save`
+save: Saves current state of application. +Parameters: NIL +Example: save -`bye: Exits the application.`
-`Parameters: NIL`
-`Example: bye`
+bye: Exits the application. +Parameters: NIL +Example: bye -`help: Shows details of available commands to users.`
-`Parameters: NIL`
-`Example: help`
+help: Shows details of available commands to users. +Parameters: NIL +Example: help +``` ### Exiting the application: `bye` @@ -214,7 +230,9 @@ Example of usage and output: Output: -`Bye, See you again!` +``` +Bye, See you again! +``` ## FAQ diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index 88016f6978..11e94fc8af 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -14,11 +14,11 @@ public class CheckCommand extends Command { private final ArrayList commandStrings; public static final String COMMAND_WORD = "check"; - public static final String COMMAND_DESCRIPTION = ": Gives details of the equipment with the specified name. " + public static final String COMMAND_DESCRIPTION = ": Check the details of the equipments that matches the specified parameter. " + System.lineSeparator() - + "Parameters: n/`ITEM_NAME`" + System.lineSeparator() + + "Parameters: parameter/`PARAMETER_VALUE`" + System.lineSeparator() + "Example: " - + "check n/`MixerC`"; + + "check n/`MixerC` or check s/`SM57-1` or check t/`MICROPHONE`"; /** * constructor for CheckCommand. Initialises successMessage and usageReminder from Command diff --git a/src/main/java/seedu/command/ListCommand.java b/src/main/java/seedu/command/ListCommand.java index ee1b031e5c..05b318039e 100644 --- a/src/main/java/seedu/command/ListCommand.java +++ b/src/main/java/seedu/command/ListCommand.java @@ -20,9 +20,9 @@ public class ListCommand extends Command { public static final String COMMAND_DESCRIPTION_WITH_TYPE = ": Prints a list of all equipment in the inventory of the specified type. " + System.lineSeparator() - + "Parameters: `Type`" + System.lineSeparator() + + "Parameters: `TYPE`" + System.lineSeparator() + "Example: " - + "list MICROPHONE"; + + "list t/`MICROPHONE`"; /** * constructor for ListCommand with NO specified type. Initialises successMessage and usageReminder from Command From a21807eff1d29cb5600077990f177caf829e4e70 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Fri, 8 Apr 2022 22:58:26 +0800 Subject: [PATCH 179/229] Fix Gradle and removed list TYPE from HelpCommand --- docs/UserGuide.md | 20 +------------------ src/main/java/seedu/command/CheckCommand.java | 3 ++- src/main/java/seedu/command/HelpCommand.java | 2 -- 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index cf391381b5..c5170bb3c3 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -86,9 +86,7 @@ Here are the equipment matching to 'SpeakerB': ### Listing equipment: `list` Print a list of all equipment in the inventory. If a parameter is supplied, only the equipment matching to the parameter will be printed. -Format: ``list [t/`TYPE`]`` - -* `TYPE` can only take on values of `SPEAKER`, `MICROPHONE`, `STAND`, `CABLE`. +Format: `list` Example of usage and output: @@ -102,17 +100,6 @@ TOTAL QUANTITY OF EQUIPMENT: 2 2. serialNumber=S1404115ASF,itemName=SpeakerB,type=SPEAKER,cost=1000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-02-23 ``` -Example of usage and output: - -``list t/`MICROPHONE` `` - -Output: - -``` -TOTAL QUANTITY OF EQUIPMENT: 1 -1. serialNumber=S89347971ASF,itemName=MicrophoneC,type=MICROPHONE,cost=2000.0,purchasedFrom=Loud_Technologies,purchasedDate=2022-01-21 -``` - ### Updating an equipment: `update` Equipment can be updated with new information. Every parameter except serial number can be updated. @@ -197,10 +184,6 @@ list: Prints a list of all equipment in the inventory. Parameters: NIL Example: list -list: Prints a list of all equipment in the inventory of the specified type. -Parameters: `TYPE` -Example: list t/`MICROPHONE` - check: Check the details of the equipments that matches the specified parameter. Parameters: parameter/`PARAMETER_VALUE` Example: check n/`MixerC` or check s/`SM57-1` or check t/`MICROPHONE` @@ -247,7 +230,6 @@ Bye, See you again! * Add equipment ``add n/`ITEM_NAME` s/`SERIAL_NUMBER` t/`TYPE` c/`COST` pf/`PURCHASED_FROM` pd/`PURCHASED_DATE` `` * Check equipment ``check n/`ITEM_NAME` `` * Listing equipment: `list` -* Listing equipment by type: ``list t/`TYPE` `` * Updating an equipment: ``update s/`SERIAL_NUMBER` [n/`ITEM_NAME`] [t/`TYPE`] [c/`COST`] [pf/`PURCHASED_FROM`] [pd/`PURCHASED_DATE`]`` * Deleting an equipment: ``delete s/`SERIAL_NUMBER` `` * Saving application state: `save` diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index 11e94fc8af..8bf79d5e2b 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -14,7 +14,8 @@ public class CheckCommand extends Command { private final ArrayList commandStrings; public static final String COMMAND_WORD = "check"; - public static final String COMMAND_DESCRIPTION = ": Check the details of the equipments that matches the specified parameter. " + public static final String COMMAND_DESCRIPTION = ": Check the details of the equipments that matches the specified" + + " parameter. " + System.lineSeparator() + "Parameters: parameter/`PARAMETER_VALUE`" + System.lineSeparator() + "Example: " diff --git a/src/main/java/seedu/command/HelpCommand.java b/src/main/java/seedu/command/HelpCommand.java index fce376721d..8b2c17886b 100644 --- a/src/main/java/seedu/command/HelpCommand.java +++ b/src/main/java/seedu/command/HelpCommand.java @@ -24,8 +24,6 @@ public CommandResult execute() { + System.lineSeparator() + System.lineSeparator() + ListCommand.COMMAND_WORD + ListCommand.COMMAND_DESCRIPTION + System.lineSeparator() - + System.lineSeparator() + ListCommand.COMMAND_WORD + ListCommand.COMMAND_DESCRIPTION_WITH_TYPE - + System.lineSeparator() + System.lineSeparator() + CheckCommand.COMMAND_WORD + CheckCommand.COMMAND_DESCRIPTION + System.lineSeparator() + System.lineSeparator() + SaveCommand.COMMAND_WORD + SaveCommand.COMMAND_DESCRIPTION From 042dc644657fce0ddf04b15c6435365d2fdabee4 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Fri, 8 Apr 2022 23:01:22 +0800 Subject: [PATCH 180/229] Remove * import --- src/main/java/seedu/storage/LocalDateAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/storage/LocalDateAdapter.java b/src/main/java/seedu/storage/LocalDateAdapter.java index cb4bf28143..6f4a1ed389 100644 --- a/src/main/java/seedu/storage/LocalDateAdapter.java +++ b/src/main/java/seedu/storage/LocalDateAdapter.java @@ -1,6 +1,6 @@ package seedu.storage; -import com.google.gson.*; +import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; From 5b6db61de58569db529b6f936aad2475c8269897 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Sat, 9 Apr 2022 00:01:19 +0800 Subject: [PATCH 181/229] Make key of Equipments to be lowercase --- .../java/seedu/command/DeleteCommand.java | 2 +- .../seedu/equipment/EquipmentManager.java | 24 +++++++++---------- .../seedu/equipment/EquipmentManagerTest.java | 2 +- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/main/java/seedu/command/DeleteCommand.java b/src/main/java/seedu/command/DeleteCommand.java index 8ce33db2c8..a2416e10b2 100644 --- a/src/main/java/seedu/command/DeleteCommand.java +++ b/src/main/java/seedu/command/DeleteCommand.java @@ -37,7 +37,7 @@ public CommandResult execute() { try { serialNumber = prepareDelete(); - equipmentName = equipmentManager.getEquipmentList().get(serialNumber).getItemName(); + equipmentName = equipmentManager.getEquipmentList().get(serialNumber.toLowerCase()).getItemName(); } catch (NullPointerException e) { return new CommandResult(INVALID_SERIAL_NUMBER); } catch (AssertionError e) { diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index d00ca03900..e5091a15aa 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -5,6 +5,7 @@ import java.time.LocalDate; import java.util.ArrayList; import java.util.HashMap; +import java.util.Locale; public class EquipmentManager { private final HashMap equipmentList; @@ -26,10 +27,10 @@ public EquipmentManager() { */ public void addEquipment(String itemName, String serialNumber, EquipmentType type, double cost, String purchasedFrom, LocalDate purchasedDate) throws DuplicateSerialNumberException { - if (!equipmentList.containsKey(serialNumber)) { + if (!equipmentList.containsKey(serialNumber.toLowerCase())) { Equipment equipment = new Equipment(itemName, serialNumber, type, cost, purchasedFrom, purchasedDate); - equipmentList.put(serialNumber, equipment); - } else if (equipmentList.containsKey(serialNumber)) { + equipmentList.put(serialNumber.toLowerCase(), equipment); + } else if (equipmentList.containsKey(serialNumber.toLowerCase())) { throw new DuplicateSerialNumberException(); } } @@ -42,8 +43,8 @@ public void addEquipment(String itemName, String serialNumber, EquipmentType typ */ public void addEquipment(Equipment equipment) throws DuplicateSerialNumberException { String serialNumber = equipment.getSerialNumber(); - if (!equipmentList.containsKey(serialNumber)) { - equipmentList.putIfAbsent(equipment.getSerialNumber(), equipment); + if (!equipmentList.containsKey(serialNumber.toLowerCase())) { + equipmentList.putIfAbsent(equipment.getSerialNumber().toLowerCase(), equipment); } else { throw new DuplicateSerialNumberException(); } @@ -67,11 +68,8 @@ public ArrayList checkEquipment(Pair checkParam) { } break; case "serialNumber": - for (Equipment equipment : equipmentList.values()) { - if (equipment.getSerialNumber().contains((String) checkParam.getValue())) { - listOfEquipments.add(equipment); - } - } + String serialNumber = (String) checkParam.getValue(); + listOfEquipments.add(equipmentList.get(serialNumber.toLowerCase())); break; case "type": for (Equipment equipment : equipmentList.values()) { @@ -146,10 +144,10 @@ public HashMap getEquipmentList() { * @return Boolean value based on whether the update succeeded or not. */ public boolean updateEquipment(String serialNumber, ArrayList> updatePairs) { - if (!equipmentList.containsKey(serialNumber)) { + if (!equipmentList.containsKey(serialNumber.toLowerCase())) { return false; } - Equipment updatedEquipment = equipmentList.get(serialNumber); + Equipment updatedEquipment = equipmentList.get(serialNumber.toLowerCase()); for (Pair updates : updatePairs) { String key = updates.getKey(); switch (key) { @@ -185,6 +183,6 @@ public boolean updateEquipment(String serialNumber, ArrayList> u * @param serialNumber Serial number of Equipment in String. */ public void deleteEquipment(String serialNumber) { - equipmentList.remove(serialNumber); + equipmentList.remove(serialNumber.toLowerCase()); } } diff --git a/src/test/java/seedu/equipment/EquipmentManagerTest.java b/src/test/java/seedu/equipment/EquipmentManagerTest.java index e00c9563f7..47ef843a9d 100644 --- a/src/test/java/seedu/equipment/EquipmentManagerTest.java +++ b/src/test/java/seedu/equipment/EquipmentManagerTest.java @@ -34,7 +34,7 @@ public void updateEquipment_success() throws DuplicateSerialNumberException { 2000, "Louder Technologies", LocalDate.parse("2022-03-17")); - assertEquals(expectedEquipment, equipments.get("S1404115ASF")); + assertEquals(expectedEquipment, equipments.get("S1404115ASF".toLowerCase())); } @Test From 909760ad427fa1db57c685f364bcffaca245636c Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sat, 9 Apr 2022 00:33:19 +0800 Subject: [PATCH 182/229] Update exception handling for CheckCommand Fixes #134 --- src/main/java/seedu/command/CheckCommand.java | 20 ++++++++++++++++--- src/main/java/seedu/parser/Parser.java | 4 ---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index 8bf79d5e2b..b139f17dc3 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -5,6 +5,7 @@ import seedu.equipment.EquipmentType; import java.time.LocalDate; +import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.Locale; @@ -38,8 +39,17 @@ public CheckCommand(ArrayList commandStrings) { * @return CommandResult with message from execution of this command */ public CommandResult execute() { - Pair checkPair = generateCheckPair(); - ArrayList equipment = equipmentManager.checkEquipment(checkPair); + ArrayList equipment; + try { + Pair checkPair = generateCheckPair(); + equipment = equipmentManager.checkEquipment(checkPair); + } catch (DateTimeParseException e) { + return new CommandResult(INVALID_DATE_MESSAGE); + } catch (NumberFormatException e) { + return new CommandResult(INCORRECT_COST_FORMAT); + } catch (IllegalArgumentException e) { + return new CommandResult(INCORRECT_ENUM_TYPE); + } return new CommandResult(String.format(successMessage, commandStrings.get(0)), equipment); } @@ -49,8 +59,12 @@ public CommandResult execute() { * Pair is a class that was implemented to match each attribute to its value. * By using pair, we are able to specify the attribute to be checked. * @return Pair of value to be checked and its matching attribute. + * + * @throws NumberFormatException if cost is invalid + * @throws IllegalArgumentException if EquipmentType is invalid */ - public Pair generateCheckPair() throws AssertionError, NumberFormatException, IllegalArgumentException { + public Pair generateCheckPair() throws AssertionError, NumberFormatException, IllegalArgumentException + , DateTimeParseException { Pair pair = null; String s = commandStrings.get(0); diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 9fa9c50513..d391890c5d 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -127,10 +127,6 @@ public Command parseCommand(String userInput) { return new CheckCommand(args); } catch (IncompleteCommandException e) { return new IncorrectCommand(CheckCommand.COMMAND_WORD + CheckCommand.COMMAND_DESCRIPTION); - } catch (NumberFormatException e) { - return new IncorrectCommand(Command.INCORRECT_ENUM_TYPE); - } catch (IllegalArgumentException e) { - return new IncorrectCommand(Command.INCORRECT_COST_FORMAT); } case DeleteCommand.COMMAND_WORD: try { From ee99055180d8124c94beac4589b499cad147ce91 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sat, 9 Apr 2022 00:42:49 +0800 Subject: [PATCH 183/229] Add instructions for manual testing to developer guide --- docs/DeveloperGuide.md | 76 ++++++++++++++++++++++++++++++++++++++++-- docs/team/yuhao.md | 1 + 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index f13e9f0ae6..ec74ec320a 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -4,7 +4,7 @@ - [Design and Implementation](#design-and-implementation) - [Architecture](#architecture) - [Parser](#parser) - - [Update feature](#update-feature) + - [Command classes](#command-classes) - [EquipmentManager](#equipmentmanager) - [Product scope](#product-scope) - [Target user profile](#target-user-profile) @@ -159,4 +159,76 @@ Further, maintaining a record of the equipment is a time-consuming task given th -------------------------------------------------------------------------------------------------------------------- ## Instructions for manual testing -{Give instructions on how to do a manual product testing e.g., how to load sample data to be used for testing} +### Launch and exit +1. Initial launch + 1. Ensure that you have Java 11 or above installed. + 2. Download the latest version of `EquipmentManager` jar file from [here](https://github.com/AY2122S2-CS2113-F12-2/tp/releases) and copy into an empty folder. + 3. Launch command line and change into the directory jar file is saved. + 4. Run java -jar tp.jar.
+ Expected: application starts with greeting message. +2. Exit application + 1. Enter `bye` into command line.
+ Expected: application exits. + +### Help +1. Help + 1. Test case: `help`
+ Expected: List of commands usage examples is shown. + +### Adding equipment +1. Adding equipment to inventory + 1. Test case: ``add n/`SpeakerB` s/`S1404115ASF` t/`Speaker` c/`1000` pf/`Loud_Technologies` pd/`2022-02-23` `` + Expected: Equipment successfully added. + 2. Test case: ``add n/`SpeakerB` s/`S1404115ASF` c/`1000` pf/`Loud_Technologies` pd/`2022-02-23` `` + Expected: Unable to add equipment with missing attributes. + 3. Test case: ``add n/`SpeakerB` s/`S1404115ASF` t/`something` c/`1000` pf/`Loud_Technologies` pd/`2022-02-23` `` + Expected: Unable to add equipment, Equipment Type has to be `MICROPHONE`, `SPEAKER`, `STAND` or `CABLE`. + 4. Test case: ``add n/`SpeakerB` s/`S1404115ASF` t/`something` c/`1000` pf/`Loud_Technologies` pd/`2123928` `` + Expected: Unable to add equipment, date must be in YYYY-MM-DD format. +2. Adding equipment with duplicate serial number to inventory + 1. Prerequisites: There is already equipment in the inventory, for example the one added above. + 2. Test case: ``add n/`SpeakerB` s/`S1404115ASF` t/`Speaker` c/`1000` pf/`Loud_Technologies` pd/`2022-02-23` `` + Expected: Unable to add equipment with duplicate serial number. +### Updating equipment +1. Updating equipment in inventory + 1. Prerequisite: There is already equipment present in the inventory. + 2. Test case: ``update s/`S1404115ASF` n/`SpeakerC` c/`2510` pd/`2022-08-21` `` + Expected: Equipment details updated with the specified values + 3. Test case: ``update s/`S1404115ASF` c/`2510` rand/`SpeakerC` pd/`2022-08-21` `` + Expected: Update unsuccessful due to unrecognised tag. + +### Checking equipment +1. Checking for equipment matching to a specified attribute value + 1. Prerequisite: There is already equipment present in the inventory. + 2. Test case: ``check n/`Mic` `` + Expected: List of equipment with name containing `Mic`. + 3. Test case: ``check c/`700` `` + Expected: List of equipment with cost of `700`. + 4. Test case: ``check pf/`Tech` `` + Expected: List of equipment purchased from supplier with name containing `Tech`. + 5. Test case: ``check pd/`2022-01-27` `` + Expected: List of equipment purchased on `2022-01-27`. + 6. Test case: ``check t/`SPEAKER` `` + Expected: List of equipment of type `SPEAKER`. +2. Checking for equipment, but using wrong input format + 1. Prerequisite: There is already equipment present in the inventory. + 2. Test case: ``check c/`hello` `` + Expected: Error in displaying equipment, specified cost needs to be able to be parsed to double. + 3. Test case: ``check t/`BLA` `` + Expected: Error in displaying equipment, specified type has to be `MICROPHONE`, `SPEAKER`, `STAND` or `CABLE`. + 4. Test case: ``check pd/`2022` `` + Expected: Error in displaying equipment, specified date needs to follow `YYYY-MM-DD` format. + +### Listing equipment +1. Listing all equipment available in inventory + 1. Test case: `list` + Expected: List of all equipment. + +### Saving +1. Manual saving of application state + 1. Test case: `save` + Expected: Successfully saved. +2. Auto saving of application state + 1. Prerequisite: Application state automatically saved after every 5 commands issued. + 2. Test case: Execution of any 5 commands + Expected: Application auto saved. \ No newline at end of file diff --git a/docs/team/yuhao.md b/docs/team/yuhao.md index 682df59731..3fef9fb0f0 100644 --- a/docs/team/yuhao.md +++ b/docs/team/yuhao.md @@ -21,6 +21,7 @@ Code contribution can be found [here](https://nus-cs2113-ay2122s2.github.io/tp-d ### Contributions to DG * Wrote explanation for the implementation of Command classes. * Added object and sequence diagrams used in explaining flow of updating equipment. +* Wrote instructions for manual testing. ### Contributions to team-based tasks * Took meeting minutes and tracked to-do tasks for the team. From 86bc0da80767134fe3daf004566938d87d635678 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sat, 9 Apr 2022 00:46:35 +0800 Subject: [PATCH 184/229] Fix checkstyle --- src/main/java/seedu/command/CheckCommand.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index b139f17dc3..ec28ac37c9 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -63,8 +63,8 @@ public CommandResult execute() { * @throws NumberFormatException if cost is invalid * @throws IllegalArgumentException if EquipmentType is invalid */ - public Pair generateCheckPair() throws AssertionError, NumberFormatException, IllegalArgumentException - , DateTimeParseException { + public Pair generateCheckPair() throws AssertionError, NumberFormatException, IllegalArgumentException, + DateTimeParseException { Pair pair = null; String s = commandStrings.get(0); From 1bbb2e7ceee4009194742fd8e2f870775c7d4e28 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sat, 9 Apr 2022 01:02:31 +0800 Subject: [PATCH 185/229] Remove implementation of listing equipment of specified type --- src/main/java/seedu/command/ListCommand.java | 36 +++----------------- 1 file changed, 4 insertions(+), 32 deletions(-) diff --git a/src/main/java/seedu/command/ListCommand.java b/src/main/java/seedu/command/ListCommand.java index 05b318039e..96c97185eb 100644 --- a/src/main/java/seedu/command/ListCommand.java +++ b/src/main/java/seedu/command/ListCommand.java @@ -17,12 +17,6 @@ public class ListCommand extends Command { + "Parameters: NIL" + System.lineSeparator() + "Example: " + "list"; - public static final String COMMAND_DESCRIPTION_WITH_TYPE = - ": Prints a list of all equipment in the inventory of the specified type. " - + System.lineSeparator() - + "Parameters: `TYPE`" + System.lineSeparator() - + "Example: " - + "list t/`MICROPHONE`"; /** * constructor for ListCommand with NO specified type. Initialises successMessage and usageReminder from Command @@ -33,41 +27,19 @@ public ListCommand() { usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION; } - /** - * constructor for ListCommand with specified type. Initialises successMessage and usageReminder from Command. - * - * @param commandStrings parsed user input which contains details of equipment to be viewed - */ - public ListCommand(ArrayList commandStrings) { - this.commandStrings = commandStrings; - successMessage = "TOTAL QUANTITY OF %1$s: %2$d" + System.lineSeparator(); - usageReminder = COMMAND_WORD + COMMAND_DESCRIPTION_WITH_TYPE; - } /** - * List all equipment or list equipment of specified type. + * List all equipment. * * @return CommandResult with message from execution of this command */ public CommandResult execute() { int listSize; ArrayList equipmentArrayList; - if (commandStrings == null) { - equipmentArrayList = equipmentManager.listEquipment(); - listSize = equipmentArrayList.size(); - return new CommandResult(String.format(successMessage, listSize), equipmentArrayList); - } - - EquipmentType typeToList; - try { - typeToList = EquipmentType.valueOf(commandStrings.get(0)); - } catch (IllegalArgumentException e) { - return new CommandResult(INCORRECT_ENUM_TYPE); - } - - equipmentArrayList = equipmentManager.listEquipment(typeToList); + equipmentArrayList = equipmentManager.listEquipment(); listSize = equipmentArrayList.size(); - return new CommandResult(String.format(successMessage, typeToList, listSize), equipmentArrayList); + + return new CommandResult(String.format(successMessage, listSize), equipmentArrayList); } /** From 91cdfbeb74cc358d3846551434770770508c3078 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sat, 9 Apr 2022 01:07:13 +0800 Subject: [PATCH 186/229] Remove remaining traces of listing equipment with type --- src/main/java/seedu/parser/Parser.java | 7 +---- .../java/seedu/command/ListCommandTest.java | 26 ------------------- src/test/java/seedu/parser/ParserTest.java | 7 ----- 3 files changed, 1 insertion(+), 39 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index d391890c5d..388efeb9da 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -147,12 +147,7 @@ public Command parseCommand(String userInput) { return new IncorrectCommand(Command.INCORRECT_ENUM_TYPE); } case ListCommand.COMMAND_WORD: - if (arguments == null) { - return new ListCommand(); - } else { - args = new ArrayList<>(Collections.singleton(arguments.toUpperCase(Locale.ROOT))); - return new ListCommand(args); - } + return new ListCommand(); case HelpCommand.COMMAND_WORD: return new HelpCommand(); case SaveCommand.COMMAND_WORD: diff --git a/src/test/java/seedu/command/ListCommandTest.java b/src/test/java/seedu/command/ListCommandTest.java index 751c228e58..ea43d01a66 100644 --- a/src/test/java/seedu/command/ListCommandTest.java +++ b/src/test/java/seedu/command/ListCommandTest.java @@ -15,32 +15,6 @@ class ListCommandTest { ListCommand listCommand; - @Test - void execute_specifiedType_success() { - listCommand = new ListCommand(new ArrayList<>( - Arrays.asList("SPEAKER") - )); - 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 SPEAKER: 1" + System.lineSeparator(), - equipmentManager.listEquipment(EquipmentType.valueOf("SPEAKER"))); - - assertEquals(expectedResult, actualResult); - } - @Test void execute_noSpecifiedType_success() { listCommand = new ListCommand(); diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index d68996b7a9..a336ba79d3 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -337,13 +337,6 @@ void extractArguments_wrongArgTypesUsed_exceptionThrown() { assertEquals(IncompleteCommandException.NO_PARAMETERS_FOUND, exception.getMessage()); } - @Test - void parseCommand_listEnumTypeConvertedToUpper_success() { - Command testCommand = parser.parseCommand("list spEAker"); - Command expectedCommand = new ListCommand(new ArrayList<>(Collections.singleton("SPEAKER"))); - assertEquals(expectedCommand, testCommand); - } - @Test void parseCommand_deleteCommand_success() { Command testCommand = parser.parseCommand("delete s/`S1234567E`"); From 75a5ede8f73cd951d6d90b593e70985b84aaacda Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sat, 9 Apr 2022 01:07:20 +0800 Subject: [PATCH 187/229] Update java docs --- src/main/java/seedu/command/CheckCommand.java | 3 ++- src/main/java/seedu/command/DeleteCommand.java | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/command/CheckCommand.java b/src/main/java/seedu/command/CheckCommand.java index ec28ac37c9..e4222407e8 100644 --- a/src/main/java/seedu/command/CheckCommand.java +++ b/src/main/java/seedu/command/CheckCommand.java @@ -59,9 +59,10 @@ public CommandResult execute() { * Pair is a class that was implemented to match each attribute to its value. * By using pair, we are able to specify the attribute to be checked. * @return Pair of value to be checked and its matching attribute. - * * @throws NumberFormatException if cost is invalid * @throws IllegalArgumentException if EquipmentType is invalid + * @throws DateTimeParseException if date is not in YYYY-MM-DD format + * */ public Pair generateCheckPair() throws AssertionError, NumberFormatException, IllegalArgumentException, DateTimeParseException { diff --git a/src/main/java/seedu/command/DeleteCommand.java b/src/main/java/seedu/command/DeleteCommand.java index 8ce33db2c8..b366c17f84 100644 --- a/src/main/java/seedu/command/DeleteCommand.java +++ b/src/main/java/seedu/command/DeleteCommand.java @@ -61,7 +61,11 @@ public boolean equals(Object other) { return this.commandStrings.equals(otherDeleteCommand.commandStrings); } - + /** + * Asserts that the argument value received is indeed a serial number and removes the '/' from the argument. + * @return String containing serial number of equipment to be deleted. + * @throws AssertionError if argument tag is not 's/' + */ protected String prepareDelete() throws AssertionError { String argString = commandStrings.get(0); int delimiterPos = argString.indexOf('/'); From c29e24184f6fded200b45099036e653cdf65730e Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sat, 9 Apr 2022 01:14:06 +0800 Subject: [PATCH 188/229] Add to glossary in DeveloperGuide --- docs/DeveloperGuide.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index ec74ec320a..f310280080 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -154,7 +154,10 @@ Further, maintaining a record of the equipment is a time-consuming task given th -------------------------------------------------------------------------------------------------------------------- ## Glossary -* *glossary item* - Definition +* *Equipment* - Each entity that is being stored/manipulated in the application +* *Inventory* - Refers to the whole of the Equipment stored in the application +* *Command* - Keywords that users use to tell the application to perform certain actions +* *CommandResult* - Results that are produced from the execution of Commands. -------------------------------------------------------------------------------------------------------------------- ## Instructions for manual testing From 01e05ddf22428b6512b15d0a47ee85e148f6c446 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sat, 9 Apr 2022 01:23:31 +0800 Subject: [PATCH 189/229] Add and update JUnit tests --- .../java/seedu/command/CheckCommandTest.java | 36 +++++++++++++++++++ .../java/seedu/command/DeleteCommandTest.java | 3 +- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/test/java/seedu/command/CheckCommandTest.java b/src/test/java/seedu/command/CheckCommandTest.java index 6a8ed9c26f..c37b630546 100644 --- a/src/test/java/seedu/command/CheckCommandTest.java +++ b/src/test/java/seedu/command/CheckCommandTest.java @@ -48,4 +48,40 @@ void execute_validEquipmentName_success() { 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 index 80285dd2a6..480cef625f 100644 --- a/src/test/java/seedu/command/DeleteCommandTest.java +++ b/src/test/java/seedu/command/DeleteCommandTest.java @@ -53,8 +53,7 @@ void execute_invalidSerialNumber_fail() { CommandResult actualResult = deleteCommand.execute(); CommandResult expectedResult = - new CommandResult("No such serial number, please enter an existing " - + "serial number"); + new CommandResult(Command.INVALID_SERIAL_NUMBER); assertEquals(expectedResult, actualResult); } From 80215ecb538b970c7ffc57d2f03eb3795acc22b5 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sat, 9 Apr 2022 02:34:22 +0800 Subject: [PATCH 190/229] Edit sequence diagram and update developer guide --- .gitignore | 5 ++++- docs/DeveloperGuide.md | 7 +++---- docs/diagrams/.EquipmentManager.vpp.lck | 0 docs/diagrams/EquipmentManager.vpp | Bin 720896 -> 896000 bytes docs/images/sequenceDiagram1.png | Bin 0 -> 25306 bytes docs/images/sequenceDiagramExecute.png | Bin 0 -> 24768 bytes 6 files changed, 7 insertions(+), 5 deletions(-) delete mode 100644 docs/diagrams/.EquipmentManager.vpp.lck create mode 100644 docs/images/sequenceDiagram1.png create mode 100644 docs/images/sequenceDiagramExecute.png diff --git a/.gitignore b/.gitignore index 6390bb6ea0..a3884e21ba 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,7 @@ bin/ text-ui-test/EXPECTED-UNIX.TXT META-INF/MANIFEST.MF src/main/java/META-INF/MANIFEST.MF -/equipments.json \ No newline at end of file +/equipments.json +docs/diagrams/EquipmentManager.vpp.bak_001d +docs/diagrams/EquipmentManager.vpp.bak_002d +docs/diagrams/EquipmentManager.vpp.bak_003d diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index f310280080..2516ba2ca8 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -96,20 +96,19 @@ Step 1. The user adds an equipment to the system with the help of the `add` comm ![equipment0](images/equipment0.png) +![sequenceDiagram1](images/sequenceDiagram1.png) + Step 2. The user executes `update s/S1404115ASF n/SpeakerC c/2000 pd/2022-01-29` to update equipment with serial number S1404115ASF. `Parser#parseCommand` is called from `Duke` to parse the user's input. Step 3. The parser recognises that an `UpdateCommand` is required, and the UpdateCommand is prepared to return to `Duke`. In the constructor of `UpdateCommand`, `prepareModification` is called to set the values of the attributes to be updated. The other attributes are set to null by default. +![sequenceDiagramExecute](images/sequenceDiagramExecute.png) Step 4. `UpdateCommand#execute` is run to process the update. If the serialNumber attribute is null, a `CommandResult` with a `MISSING_SERIAL_NUMBER` output string will be returned. Otherwise, `EquipmentManager#updateEquipment` is called. Step 5. If the update was successful, a `CommandResult` with success message will be returned, else a `CommandResult` with `UPDATE_FAILURE_MESSAGE` will be returned. Upon successful update, the object should be updated with the new attributes as shown in the diagram below. ![equipment1](images/equipment1.png) -The *Sequence Diagram* below shows how the objects/classes interact with each other in the case of an update command being issued by the user. - -![sequenceDiagram](images/sequenceDiagram.png) - Step 6. It is not shown in the sequence diagram but ultimately when the CommandResult is returned to `Duke`, the output of the `CommandResult` gets printed out and displayed to the user. ### EquipmentManager diff --git a/docs/diagrams/.EquipmentManager.vpp.lck b/docs/diagrams/.EquipmentManager.vpp.lck deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docs/diagrams/EquipmentManager.vpp b/docs/diagrams/EquipmentManager.vpp index 9c3c239b251492ac80a93c39fecda7e8bb2ca52f..fc95fb6d04f43dc6512ca6399ef6dc71946d25ef 100644 GIT binary patch delta 113228 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ⅇub>i!$P_6@qXC9Zz97SH#5 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 diff --git a/docs/images/sequenceDiagram1.png b/docs/images/sequenceDiagram1.png new file mode 100644 index 0000000000000000000000000000000000000000..27ec781007c5e3e3f8984fb063a85d65621d6689 GIT binary patch literal 25306 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 literal 0 HcmV?d00001 diff --git a/docs/images/sequenceDiagramExecute.png b/docs/images/sequenceDiagramExecute.png new file mode 100644 index 0000000000000000000000000000000000000000..4cad401ed78ee0686966f30077273001547afce4 GIT binary patch literal 24768 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
XPxn@0?U#kGZvW+}$6 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 Awg3PC literal 0 HcmV?d00001 From f6f7f3569e3c21accab7c4d514842783843e2ddc Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sat, 9 Apr 2022 02:35:01 +0800 Subject: [PATCH 191/229] Update glossary --- docs/team/yuhao.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/team/yuhao.md b/docs/team/yuhao.md index 3fef9fb0f0..bb1b40e863 100644 --- a/docs/team/yuhao.md +++ b/docs/team/yuhao.md @@ -21,6 +21,7 @@ Code contribution can be found [here](https://nus-cs2113-ay2122s2.github.io/tp-d ### Contributions to DG * Wrote explanation for the implementation of Command classes. * Added object and sequence diagrams used in explaining flow of updating equipment. +* Defined some terms in glossary. * Wrote instructions for manual testing. ### Contributions to team-based tasks From 57b2a769cb6534d955e392bf078766e4b52abae0 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sat, 9 Apr 2022 02:38:09 +0800 Subject: [PATCH 192/229] Fix formatting issue with developer guide --- docs/DeveloperGuide.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 2516ba2ca8..25adb8088f 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -103,6 +103,7 @@ Step 2. The user executes `update s/S1404115ASF n/SpeakerC c/2000 pd/2022-01-29` Step 3. The parser recognises that an `UpdateCommand` is required, and the UpdateCommand is prepared to return to `Duke`. In the constructor of `UpdateCommand`, `prepareModification` is called to set the values of the attributes to be updated. The other attributes are set to null by default. ![sequenceDiagramExecute](images/sequenceDiagramExecute.png) + Step 4. `UpdateCommand#execute` is run to process the update. If the serialNumber attribute is null, a `CommandResult` with a `MISSING_SERIAL_NUMBER` output string will be returned. Otherwise, `EquipmentManager#updateEquipment` is called. Step 5. If the update was successful, a `CommandResult` with success message will be returned, else a `CommandResult` with `UPDATE_FAILURE_MESSAGE` will be returned. Upon successful update, the object should be updated with the new attributes as shown in the diagram below. From 6b2bef057d0e636af77331078167deeb000a3e48 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sat, 9 Apr 2022 05:14:44 +0800 Subject: [PATCH 193/229] Loosen restrictions for modification command regex --- src/main/java/seedu/parser/Parser.java | 1 - src/test/java/seedu/parser/ParserTest.java | 11 ++++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index ce2025aebc..b29decc07d 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -53,7 +53,6 @@ public class Parser { public static final Pattern MODIFICATION_ARGUMENT_FORMAT = Pattern.compile( "(" + ARGUMENT_PAIR_REGEX + ")" + "\\s+" // argument space before next delimiter - + "(?=[sntcSNTC]|[pP][fF]|[pP][dD])" // positive lookahead to mandate next delimiter ); /** * Extracts last tag for debugging. diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index d68996b7a9..3eaea6b3c3 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -331,7 +331,16 @@ void extractArguments_idealArgumentPairs_success() throws IncompleteCommandExcep } @Test - void extractArguments_wrongArgTypesUsed_exceptionThrown() { + 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()); From b7a889f9df518dad418af3d6ec35d40f8670313d Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sat, 9 Apr 2022 17:47:33 +0800 Subject: [PATCH 194/229] Deprecate support for list command with argument tags in Parser --- src/main/java/seedu/parser/Parser.java | 7 +------ src/test/java/seedu/parser/ParserTest.java | 1 + 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index ce2025aebc..a9a4b6ca42 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -152,12 +152,7 @@ public Command parseCommand(String userInput) { return new IncorrectCommand(ModificationCommand.INVALID_TYPE_MESSAGE); } case ListCommand.COMMAND_WORD: - if (arguments == null) { - return new ListCommand(); - } else { - args = new ArrayList<>(Collections.singleton(arguments.toUpperCase(Locale.ROOT))); - return new ListCommand(args); - } + return new ListCommand(); case HelpCommand.COMMAND_WORD: return new HelpCommand(); case SaveCommand.COMMAND_WORD: diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index d68996b7a9..9cb1d133e3 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -337,6 +337,7 @@ void extractArguments_wrongArgTypesUsed_exceptionThrown() { assertEquals(IncompleteCommandException.NO_PARAMETERS_FOUND, exception.getMessage()); } + @Deprecated @Test void parseCommand_listEnumTypeConvertedToUpper_success() { Command testCommand = parser.parseCommand("list spEAker"); From 7578d415d69b313ab593acc5ec481559de517911 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sat, 9 Apr 2022 18:43:43 +0800 Subject: [PATCH 195/229] Refactor Parser#splitCommandTerm with updated JavaDoc --- src/main/java/seedu/parser/Parser.java | 13 ++++++++----- src/test/java/seedu/parser/ParserTest.java | 22 ++++++++++++++++++++-- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index a9a4b6ca42..758701e47a 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -30,7 +30,7 @@ public class Parser { * Format to parse command by breaking it up into two segments: command and arguments: these can then be separately * passed into arguments. */ - public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s+(?.+)"); + public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\w+)\\s+(?.+)"); /** * Defines regex used to match argument pairs in the command line. @@ -168,18 +168,21 @@ public Command parseCommand(String userInput) { /** * 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 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 String, first element being the command term and the second element being arguments + * @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 command word first + // Checks for list/help/save/bye command word first switch (userInput.toLowerCase(Locale.ROOT)) { case ListCommand.COMMAND_WORD: resultArrayList.add(ListCommand.COMMAND_WORD); diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 9cb1d133e3..8637848e0e 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -36,8 +36,26 @@ void splitCommandTerm_validCommand_success() throws IncompleteCommandException { "add n/`ITEM_NAME` s/`SERIAL_NUMBER` t/`TYPE` c/`COST` pf/`PURCHASED_FROM` " + "pd/`PURCHASED_DATE`"); assertEquals(expectedResult, actualResult); - assertEquals(expectedResult.get(0), actualResult.get(0)); - assertEquals(expectedResult.get(1), actualResult.get(1)); + } + + @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 From 689d70667d9be4178bd59ddbc353a65bc7c4782d Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sat, 9 Apr 2022 19:55:58 +0800 Subject: [PATCH 196/229] Elaborate on DeveloperGuide.md's Design and Implementation --- docs/DeveloperGuide.md | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index f13e9f0ae6..224737f86c 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -4,7 +4,7 @@ - [Design and Implementation](#design-and-implementation) - [Architecture](#architecture) - [Parser](#parser) - - [Update feature](#update-feature) + - [Command classes](#command-classes) - [EquipmentManager](#equipmentmanager) - [Product scope](#product-scope) - [Target user profile](#target-user-profile) @@ -44,24 +44,29 @@ As such, we referenced AddressBook to segment the program into `Parser`, `Comman ### Parser -`Parser` is the first filter for text inputs read to the user. +`Parser` is the first filter for text inputs read to the user. It serves to: +1. Split text input from the user into strings of argument pairs. +2. Check and modify upper/lower case for argument tags. +3. Remove backticks, beginning and trailing whitespace. +4. Create the correct instance of `Command` based on the argument tag. + As alluded to prior, one major consideration was to build it in a manner that can parse text input as effectively as possible. In considering text input, we divided the parsing into the following segments: -

commandWord [argumentType/`argumentValue`] [...]

+commandWord [argumentType/`argumentValue`] [...]

-To dispatch argumentType/\`argumentValue\` strings to the correct `Command` class, the following logic is employed throughout `Parser` by `parseCommand`. +To dispatch argumentType/\`argumentValue\` strings to the correct `Command` class, the following logic is employed by `Parser#parseCommand`. **1. Parse the correct Command Word** -

commandWord

+commandWord

-`splitCommandTerm` splits the input string upon the first space. +`Parser#splitCommandTerm` splits the input string upon the first space. The first substring is used to decide which `Command` to dispatch while the second is used for its arguments. In the case where a second substring is not required, as in the case of `help` and `list`, a null String is used and the following step is skipped entirely. **2. Split Arguments** -

[argumentType/`argumentValue`] [...]

+[argumentType/`argumentValue`] [...]

Complex commands such as `add` and `update` necessitate multiple arguments. To implement this while ensuring that multi-word strings are acceptable input, `extractArguments` is implemented. @@ -77,15 +82,15 @@ For added safeguards in equipment deletion, the delete command implements a more

-Throughout the `Parser` implementation, exceptions were used to return `IncorrectCommand` classes that can be used to pass error messages to the user. These will be discussed in the following segments. +Throughout the `Parser` implementation, exceptions were caught to return `IncorrectCommand` classes that can be used to pass error messages to the user. These will be discussed in the following segments. ### Command classes #### Current Design and Implementation -`Command` classes are largely similar to each other. The most complex command, `UpdateCommand` will be explained here. +`Command` classes are largely similar to each other. Taking in input Strings from `Parser`, they invoke methods from `EquipmentManager` to perform the necessary actions. Where applicable, the `Command` classes also convert values to the necessary data types (Double, EquipmentType and LocalDate) prior to passing these values in. -The update feature is facilitated by `UpdateCommand`. It extends `ModificationCommand` and implements the following operations: +The most complex command, `UpdateCommand` will be explained here as the method calls are similar to the remaining commands. The update feature is facilitated by `UpdateCommand`. It extends `ModificationCommand` and implements the following operations: * `UpdateCommand#generateUpdatePairs()` — Generates pairs of attributes and their update values. * `UpdateCommand#generateUpdateString()` — Generates String with details of the update executed. From 8debc8e18417f3d8d52df1849a3eea8f615348af Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sat, 9 Apr 2022 19:56:25 +0800 Subject: [PATCH 197/229] Elaborate on DeveloperGuide.md's Design and Implementation --- docs/DeveloperGuide.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 224737f86c..2b994d14b5 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -52,13 +52,13 @@ As such, we referenced AddressBook to segment the program into `Parser`, `Comman As alluded to prior, one major consideration was to build it in a manner that can parse text input as effectively as possible. In considering text input, we divided the parsing into the following segments: -commandWord [argumentType/`argumentValue`] [...]

+

commandWord [argumentType/`argumentValue`] [...]

To dispatch argumentType/\`argumentValue\` strings to the correct `Command` class, the following logic is employed by `Parser#parseCommand`. **1. Parse the correct Command Word** -commandWord

+

commandWord

`Parser#splitCommandTerm` splits the input string upon the first space. The first substring is used to decide which `Command` to dispatch while the second is used for its arguments. @@ -66,7 +66,7 @@ In the case where a second substring is not required, as in the case of `help` a **2. Split Arguments** -[argumentType/`argumentValue`] [...]

+

[argumentType/`argumentValue`] [...]

Complex commands such as `add` and `update` necessitate multiple arguments. To implement this while ensuring that multi-word strings are acceptable input, `extractArguments` is implemented. From 7837794f39f3383cd358819dc45da265a8a8025e Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sat, 9 Apr 2022 20:06:18 +0800 Subject: [PATCH 198/229] Refactor constants in Parser.java --- src/main/java/seedu/parser/Parser.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index b29decc07d..546b15ecb2 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -31,7 +31,6 @@ public class Parser { * passed into arguments. */ public static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)\\s+(?.+)"); - /** * Defines regex used to match argument pairs in the command line. * @@ -51,8 +50,7 @@ public class Parser { * Regex101 for demo. */ public static final Pattern MODIFICATION_ARGUMENT_FORMAT = Pattern.compile( - "(" + ARGUMENT_PAIR_REGEX + ")" - + "\\s+" // argument space before next delimiter + "(" + ARGUMENT_PAIR_REGEX + ")" + "\\s+" // argument space before next delimiter ); /** * Extracts last tag for debugging. @@ -61,10 +59,8 @@ public class Parser { */ public static final Pattern MODIFICATION_ARGUMENT_TRAILING_FORMAT = Pattern.compile( "(?" + ARGUMENT_PAIR_REGEX + ")$"); public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("^(?" + "[Ss]" + "\\/" // argument delimiter @@ -72,13 +68,13 @@ public class Parser { + "[\\w\\s\\-\\.]+" // actual argument value + "`+" // backticks to enclose string + ")$"); - public static final String INCORRECT_COMMAND_FORMAT = "Command word not recognised. " + System.lineSeparator() + public static final String UNRECOGNISED_COMMAND_MESSAGE = "Command word not recognised. " + System.lineSeparator() + "Please use one of the following: " + AddCommand.COMMAND_WORD + ", " + UpdateCommand.COMMAND_WORD + ", " + ListCommand.COMMAND_WORD + ", " + CheckCommand.COMMAND_WORD + ", " + DeleteCommand.COMMAND_WORD + ", " + HelpCommand.COMMAND_WORD + ", " + SaveCommand.COMMAND_WORD + ", " + ByeCommand.COMMAND_WORD + "."; - public static final String MISSING_COMMAND_WORD_DELIMITER = INCORRECT_COMMAND_FORMAT + System.lineSeparator() - + "If including additional arguments, please separate them with a space."; + public static final String MISSING_COMMAND_WORD_DELIMITER_MESSAGE = UNRECOGNISED_COMMAND_MESSAGE + + System.lineSeparator() + "If including additional arguments, please separate them with a space."; /** * Interpret the command requested by the user and returns a corresponding Command object. @@ -92,7 +88,7 @@ public Command parseCommand(String userInput) { try { commandAndArgument = splitCommandTerm(userInput); } catch (IncompleteCommandException e) { - return new IncorrectCommand(MISSING_COMMAND_WORD_DELIMITER); + return new IncorrectCommand(MISSING_COMMAND_WORD_DELIMITER_MESSAGE); } // only arguments is trimmed because commandWord is split on the first space @@ -164,7 +160,7 @@ public Command parseCommand(String userInput) { case ByeCommand.COMMAND_WORD: return new ByeCommand(); default: - return new IncorrectCommand(INCORRECT_COMMAND_FORMAT); + return new IncorrectCommand(UNRECOGNISED_COMMAND_MESSAGE); } } From ef1c6c0e7740de9a68ba424438657f9d48b5df55 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sat, 9 Apr 2022 20:23:05 +0800 Subject: [PATCH 199/229] Remove deprecated code --- src/main/java/seedu/parser/Parser.java | 58 ---------------- src/test/java/seedu/parser/ParserTest.java | 80 ---------------------- 2 files changed, 138 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 546b15ecb2..f00322f202 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -285,62 +285,4 @@ private static String reformatArgumentPair(String argument) { return newString.replace("`", ""); } - @Deprecated - public static final Pattern ADD_COMMAND_FORMAT = Pattern.compile( - "n\\/(?.+)" + "\\s+" - + "s\\/(?.+)" + "\\s+" - + "t\\/(?.+)" + "\\s+" - + "c\\/(?.+)" + "\\s+" - + "pf\\/(?.+)" + "\\s+" - + "pd\\/(?.+)" - ); - - /** - * Prepare arguments for AddCommand by splitting up the arguments into different parts. - * - *

Index: - * - *

0. equipmentName : String of equipment name - * - *

1. serialNumber : String of unique serial number - * - *

2. type : String representation of enumerated class - * - *

3. cost : String representation of double value, "$" optional but "," delimiter forbidden - * - *

4. purchasedFrom : String of vendor name, suggest adhering to one consistent naming scheme - * - *

5. purchasedDate : String representation for now, possibility for future support - * - * @param args String to be split into substrings - * @return ArrayList of arguments - * @throws IncompleteCommandException if no match found - * @deprecated Use extractArguments as it is more robust in conjunction with subclasses of ModificationCommand - */ - @Deprecated - protected ArrayList prepareAdd(String args) throws IncompleteCommandException { - final Matcher matcher = ADD_COMMAND_FORMAT.matcher(args.trim()); - // validate arg string format - int matchCount = matcher.groupCount(); - if (!matcher.matches()) { - throw new IncompleteCommandException("Add command values are incomplete or missing!"); - } - ArrayList results = new ArrayList<>(); - for (int i = 1; i <= matchCount; i++) { - String result = matcher.group(i); - if (hasSlashDelimiter(result)) { - throw new IncompleteCommandException("Use of '/' for purposes other than delimiter is forbidden!"); - } - results.add(result); - } - return results; - } - - @Deprecated - private static boolean hasSlashDelimiter(String argument) { - return argument.contains("/"); - } - - - } diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 3eaea6b3c3..50266a2ce7 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -56,86 +56,6 @@ void splitCommandTerm_noSpaceDelimiter_exceptionThrown() { } } - @Deprecated - @Disabled("extractArgument is a better replacement for prepareAdd") - @Test - void prepareAdd_addStringWithSpaces_success() throws IncompleteCommandException { - ArrayList expectedResult = new ArrayList<>( - Arrays.asList("Speaker B", "S1404115ASF", "Speaker", "1000", "Loud Technologies", "2022-02-23") - ); - ArrayList actualResult = parser.prepareAdd( - "n/Speaker B s/S1404115ASF t/Speaker c/1000 pf/Loud Technologies pd/2022-02-23"); - assertEquals(expectedResult, actualResult); - } - - @Deprecated - @Disabled("extractArgument is a better replacement for prepareAdd") - @Test - void prepareAdd_insufficientArguments_exceptionThrown() { - ArrayList unexpectedResult = new ArrayList<>( - Arrays.asList("Speaker B", "S1404115ASF", "1000", "Loud Technologies", "2022-02-23") - ); - try { - ArrayList actualResult = parser.prepareAdd( - "n/Speaker B s/S1404115ASF c/1000 pf/Loud Technologies pd/2022-02-23"); - assertEquals(unexpectedResult, actualResult); - fail(); - } catch (IncompleteCommandException e) { - assertEquals("Add command values are incomplete or missing!", e.getMessage()); - } - } - - @Deprecated - @Disabled("extractArgument is a better replacement for prepareAdd") - @Test - void prepareAdd_argumentEnteredTwice_exceptionThrown() { - ArrayList unexpectedResult = new ArrayList<>( - Arrays.asList("Speaker B", "S1404115ASF", "Speaker", "1000 c/1000", "Loud Technologies", "2022-02-23") - ); - try { - ArrayList actualResult = parser.prepareAdd( - "n/Speaker B s/S1404115ASF t/Speaker c/1000 c/1000 pf/Loud Technologies pd/2022-02-23"); - assertEquals(unexpectedResult, actualResult); - fail(); - } catch (IncompleteCommandException e) { - assertEquals("Use of '/' for purposes other than delimiter is forbidden!", e.getMessage()); - } - } - - @Deprecated - @Disabled("extractArgument is a better replacement for prepareAdd") - @Test - void prepareAdd_argumentIncludesSlashA_exceptionThrown() { - ArrayList unexpectedResult = new ArrayList<>( - Arrays.asList("Speaker B", "S1404115/ASF", "Speaker", "1000", "Loud Technologies", "2022-02-23") - ); - try { - ArrayList actualResult = parser.prepareAdd( - "n/Speaker B s/S1404115/ASF t/Speaker c/1000 pf/Loud Technologies pd/2022-02-23"); - assertEquals(unexpectedResult, actualResult); - fail(); - } catch (IncompleteCommandException e) { - assertEquals("Use of '/' for purposes other than delimiter is forbidden!", e.getMessage()); - } - } - - @Deprecated - @Disabled("extractArgument is a better replacement for prepareAdd") - @Test - void prepareAdd_argumentIncludesSlashB_exceptionThrown() { - ArrayList unexpectedResult = new ArrayList<>( - Arrays.asList("Speaker B", "S1404115", "t/SF t/Speaker", "1000", "Loud Technologies", "2022-02-23") - ); - try { - ArrayList actualResult = parser.prepareAdd( - "n/Speaker B s/S1404115t/SF t/Speaker c/1000 pf/Loud Technologies pd/2022-02-23"); - assertEquals(unexpectedResult, actualResult); - fail(); - } catch (IncompleteCommandException e) { - assertEquals("Use of '/' for purposes other than delimiter is forbidden!", e.getMessage()); - } - } - @Test void prepareCheck_viewStringWithSpaces_success() throws IncompleteCommandException { ArrayList expectedResult = new ArrayList<>( From 5f7883d66e9b7c1e15f6c1b643cb3f78033eb5f1 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sat, 9 Apr 2022 20:32:31 +0800 Subject: [PATCH 200/229] Remove deprecated test case for parseCommand --- src/test/java/seedu/parser/ParserTest.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 8637848e0e..5bdf47878c 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -355,14 +355,6 @@ void extractArguments_wrongArgTypesUsed_exceptionThrown() { assertEquals(IncompleteCommandException.NO_PARAMETERS_FOUND, exception.getMessage()); } - @Deprecated - @Test - void parseCommand_listEnumTypeConvertedToUpper_success() { - Command testCommand = parser.parseCommand("list spEAker"); - Command expectedCommand = new ListCommand(new ArrayList<>(Collections.singleton("SPEAKER"))); - assertEquals(expectedCommand, testCommand); - } - @Test void parseCommand_deleteCommand_success() { Command testCommand = parser.parseCommand("delete s/`S1234567E`"); From 87d11a36e055a1000c38aff1ff26555b7cba6d9a Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sat, 9 Apr 2022 20:35:25 +0800 Subject: [PATCH 201/229] Minor edit to Value Proposition --- docs/DeveloperGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index f13e9f0ae6..d1a5ded034 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -134,7 +134,7 @@ The target user is the logistics chief of an event support club. He is responsib ### Value proposition -Equipment for the club differ in terms of shape and size. Owing to the climate-sensitive and fragile nature of some of these equipment, they are often stored in opaque containers, which may not be easily accessible given space constraints. By keeping records of this information on our application, the logistics chief can easily access and retrieve this information without having to make a physical trip down to the storeroom. +Equipment for the club differ in terms of shape and size. Owing to the climate-sensitive and fragile nature of some of these equipment, they are often stored in opaque containers, which may not be easily accessible or quickly identifiable given space constraints. By keeping records of this information on our application, the logistics chief can easily access and retrieve this information without having to make a physical trip down to the storeroom. Further, maintaining a record of the equipment is a time-consuming task given that they often need to be referred to by both the model number and a short alias used by club members. As the post of logistics chief is changed every year when passed down to a new member, this member will need to be acquainted with both the common name and the model number of the relevant equipment. Our application thus provides a convenient way to search by both specifications. From 92ecb83677bc740c6174042954796e52aabd5c9d Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sat, 9 Apr 2022 20:59:12 +0800 Subject: [PATCH 202/229] Add some user stories --- docs/DeveloperGuide.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index d1a5ded034..86f06a0009 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -141,10 +141,19 @@ Further, maintaining a record of the equipment is a time-consuming task given th -------------------------------------------------------------------------------------------------------------------- ## User Stories -|Version| As a ... | I want to ... | So that I can ...| -|--------|----------|---------------|------------------| -|v1.0|new user|see usage instructions|refer to them when I forget how to use the application| -|v2.0|user|find a to-do item by name|locate a to-do without having to go through the entire list| +| Version | As a ... | I want to ... | So that I can ... | +|---------|---------------------------------------|----------------------------------------------------------------|----------------------------------------------------------------------| +| v_.0 | new user | see usage instructions | refer to them when I forget how to use the application | +| v_.0 | new user | list all equipment | see all current equipment in the application | +| v_.0 | conscientious logs chief | add equipment | newly purchased equipment can be kept up to date | +| v_.0 | meticulous logs chief | update equipment | correct any errors in previously recorded equipment | +| v_.0 | conscientious logs chief | delete equipment | remove decommissioned equipment from the application | +| v_.0 | forgetful logs chief | search for equipment | be able to find equipment by its attributes | +| v3.0 | forward-planning logs chief | filter equipment purchased before a certain date | conduct more regular inspections on them | +| v3.0 | busy logs chief | mark equipment to be faulty/working | filter and send the faulty ones for repair | +| v3.0 | logs chief supporting multiple events | ensure that equipment can be earmarked for an associated event | my equipment will not be double-booked and have scheduling conflicts | + + -------------------------------------------------------------------------------------------------------------------- ## NonFunctional Requirements From 7913e08c4f37ad5522d65b889601e919b5fc14c6 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Sat, 9 Apr 2022 22:56:14 +0800 Subject: [PATCH 203/229] Add Storage in DG and change file name --- docs/AboutUs.md | 10 +++---- docs/DeveloperGuide.md | 26 +++++++++++++++++++ .../team/{bryanchristopher.md => Bryan-BC.md} | 0 3 files changed, 31 insertions(+), 5 deletions(-) rename docs/team/{bryanchristopher.md => Bryan-BC.md} (100%) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 77f80b0c01..1a905946e0 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,7 +1,7 @@ # About us -| Display | Name | Github Profile | Portfolio | -|-----------------------------------------------------|:-----------------:|:---------------------------------------:|:-------------------------------------:| -| ![](https://via.placeholder.com/100.png?text=Photo) | Bryan Christopher | [Github](https://github.com/Bryan-BC) | [Portfolio](team/bryanchristopher.md) | -| ![](https://via.placeholder.com/100.png?text=Photo) | Bai Shun Yao | [Github](https://github.com/shunyao643) | [Portfolio](team/shunyao.md) | -| ![](https://via.placeholder.com/100.png?text=Photo) | Yu Hao | [Github](https://github.com/yuhaochua) | [Portfolio](team/yuhao.md) | +| Display | Name | Github Profile | Portfolio | +|-----------------------------------------------------|:-----------------:|:---------------------------------------:|:-------------------------------:| +| ![](https://via.placeholder.com/100.png?text=Photo) | Bryan Christopher | [Github](https://github.com/Bryan-BC) | [Portfolio](team/Bryan-BC.md) | +| ![](https://via.placeholder.com/100.png?text=Photo) | Bai Shun Yao | [Github](https://github.com/shunyao643) | [Portfolio](team/shunyao643.md) | +| ![](https://via.placeholder.com/100.png?text=Photo) | Yu Hao | [Github](https://github.com/yuhaochua) | [Portfolio](team/yuhao.md) | diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index f13e9f0ae6..29b99372e2 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -126,6 +126,32 @@ These methods are used during the execution of each of the `Command` class. The `EquipmentManager` is implemented as the main storage unit of all the equipments during the execution of the program. +### Storage + +The `Storage` class is used to store the data of the program. It utilises the Gson library to serialise and deserialise the data. +There is also a LocalDateAdapter class which is used to convert the LocalDate objects to YYYY-MM-DD format. + +#### 1. `saveData` method + +The `saveData` method is used to save the Equipments added to the `equipment.json` file. +The method will automatically create the file if it does not exist. +While saving the data, the `Equipment` objects in `equipmentList` is converted to a JSON string and saved to the file. +During the execution of the program, the `equipment.json` file will be updated with the latest data after every 5 commands. +Alternatively, the user can manually save the data by calling the `save` command. + +#### 2. `loadData` method + +The `loadData` method is used to load the data from the `equipment.json` file. +The method is able to handle the cases where: + +* The file does not exist. +* The file is empty. +* The data in the file is not in the correct format. +* There are more than one `Equipment` object with the same serial number. + +While loading the data, the `equipment.json` file is read and the data is converted from a JSON string to an ArrayList of `Equipment` objects. +The ArrayList of `Equipment` objects is then added to the `equipmentList` HashMap. + -------------------------------------------------------------------------------------------------------------------- ## Product scope ### Target user profile diff --git a/docs/team/bryanchristopher.md b/docs/team/Bryan-BC.md similarity index 100% rename from docs/team/bryanchristopher.md rename to docs/team/Bryan-BC.md From dd421a9781aed207844205bd550eb2b8e754851d Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sat, 9 Apr 2022 23:30:34 +0800 Subject: [PATCH 204/229] Refactor personal portfolio page name to align with github name --- docs/AboutUs.md | 2 +- docs/team/johndoe.md | 6 ------ docs/team/{yuhao.md => yuhaochua.md} | 0 3 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 docs/team/johndoe.md rename docs/team/{yuhao.md => yuhaochua.md} (100%) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 77f80b0c01..fee008ed26 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -4,4 +4,4 @@ |-----------------------------------------------------|:-----------------:|:---------------------------------------:|:-------------------------------------:| | ![](https://via.placeholder.com/100.png?text=Photo) | Bryan Christopher | [Github](https://github.com/Bryan-BC) | [Portfolio](team/bryanchristopher.md) | | ![](https://via.placeholder.com/100.png?text=Photo) | Bai Shun Yao | [Github](https://github.com/shunyao643) | [Portfolio](team/shunyao.md) | -| ![](https://via.placeholder.com/100.png?text=Photo) | Yu Hao | [Github](https://github.com/yuhaochua) | [Portfolio](team/yuhao.md) | +| ![](https://via.placeholder.com/100.png?text=Photo) | Yu Hao | [Github](https://github.com/yuhaochua) | [Portfolio](team/yuhaochua.md) | diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md deleted file mode 100644 index ab75b391b8..0000000000 --- a/docs/team/johndoe.md +++ /dev/null @@ -1,6 +0,0 @@ -# John Doe - Project Portfolio Page - -## Overview - - -### Summary of Contributions diff --git a/docs/team/yuhao.md b/docs/team/yuhaochua.md similarity index 100% rename from docs/team/yuhao.md rename to docs/team/yuhaochua.md From 2c0cdb25fd64dd45e06cbf1cb5bd381904fc5892 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sun, 10 Apr 2022 01:05:05 +0800 Subject: [PATCH 205/229] Standardise formatting for Developer Guide --- docs/DeveloperGuide.md | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 4bbd9b427a..5e67f8ab47 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -19,14 +19,12 @@ Our project could not have been possible without the prior work of the following: - [SE-EDU project team](https://se-education.org/docs/team.html) for their work on [AddressBook Level 3](https://github.com/se-edu/addressbook-level3), for which we referenced ideas as well as code snippets. -- Google's [GSON Java library](https://github.com/google/gson) for which we used to load and save our data files. -- Members of the [AY2122S2-CS2113-F10-2 team](https://github.com/nus-cs2113-AY2122S2) for pointing out the possibility of and requesting permission to make use of the above GSON library. +- Google's [Gson Java library](https://github.com/google/gson) for which we used to load and save our data files. +- Members of the [AY2122S2-CS2113-F10-2 team](https://github.com/nus-cs2113-AY2122S2) for pointing out the possibility of and requesting permission to make use of the above Gson library. -------------------------------------------------------------------------------------------------------------------- ## **Design and Implementation** -This section describes some noteworthy details on how certain features are designed and implemented. - ### Architecture Our design draws significant inspiration from the implementation of AddressBook Level 3 (henceforth AddressBook). @@ -52,11 +50,12 @@ As such, we referenced AddressBook to segment the program into `Parser`, `Comman As alluded to prior, one major consideration was to build it in a manner that can parse text input as effectively as possible. In considering text input, we divided the parsing into the following segments: +

commandWord [argumentType/`argumentValue`] [...]

To dispatch argumentType/\`argumentValue\` strings to the correct `Command` class, the following logic is employed by `Parser#parseCommand`. -**1. Parse the correct Command Word** +#### 1. Parse the command word

commandWord

@@ -64,13 +63,13 @@ To dispatch argumentType/\`argumentValue\` strings to the correct ` The first substring is used to decide which `Command` to dispatch while the second is used for its arguments. In the case where a second substring is not required, as in the case of `help` and `list`, a null String is used and the following step is skipped entirely. -**2. Split Arguments** +####2. Split arguments

[argumentType/`argumentValue`] [...]

Complex commands such as `add` and `update` necessitate multiple arguments. To implement this while ensuring that multi-word strings are acceptable input, `extractArguments` is implemented. -Without specifically explaining the main regular expression ([details here](https://regex101.com/r/gwjHWD/3)), the approach sought to match `argumentType` and \`argumentValue\` pairs with a positive lookahead. +Without specifically explaining the main regular expression ([details here](https://regex101.com/r/gwjHWD/3)), the approach sought to match `argumentType` and argumentValue pairs with a positive lookahead. The final argument pair will then be extracted using a separate regex. Together, this ensured that all argument pairs can be effectively parsed and dispatched to each `Command` class. @@ -86,8 +85,6 @@ Throughout the `Parser` implementation, exceptions were caught to return `Incorr ### Command classes -#### Current Design and Implementation - `Command` classes are largely similar to each other. Taking in input Strings from `Parser`, they invoke methods from `EquipmentManager` to perform the necessary actions. Where applicable, the `Command` classes also convert values to the necessary data types (Double, EquipmentType and LocalDate) prior to passing these values in. The most complex command, `UpdateCommand` will be explained here as the method calls are similar to the remaining commands. The update feature is facilitated by `UpdateCommand`. It extends `ModificationCommand` and implements the following operations: @@ -97,25 +94,31 @@ The most complex command, `UpdateCommand` will be explained here as the method c Given below is an example usage scenario and how the update feature behaves at each step. -Step 1. The user adds an equipment to the system with the help of the `add` command. The added equipment has the following attributes shown below. +#### Step 1 +The user adds an equipment to the system with the help of the `add` command. The added equipment has the following attributes shown below. ![equipment0](images/equipment0.png) ![sequenceDiagram1](images/sequenceDiagram1.png) -Step 2. The user executes `update s/S1404115ASF n/SpeakerC c/2000 pd/2022-01-29` to update equipment with serial number S1404115ASF. `Parser#parseCommand` is called from `Duke` to parse the user's input. +#### Step 2 +The user executes `update s/S1404115ASF n/SpeakerC c/2000 pd/2022-01-29` to update equipment with serial number S1404115ASF. `Parser#parseCommand` is called from `Duke` to parse the user's input. -Step 3. The parser recognises that an `UpdateCommand` is required, and the UpdateCommand is prepared to return to `Duke`. In the constructor of `UpdateCommand`, `prepareModification` is called to set the values of the attributes to be updated. The other attributes are set to null by default. +#### Step 3 +The parser recognises that an `UpdateCommand` is required, and the UpdateCommand is prepared to return to `Duke`. In the constructor of `UpdateCommand`, `UpdateCommand#prepareModification` is called to set the values of the attributes to be updated. The other attributes are set to null by default. ![sequenceDiagramExecute](images/sequenceDiagramExecute.png) -Step 4. `UpdateCommand#execute` is run to process the update. If the serialNumber attribute is null, a `CommandResult` with a `MISSING_SERIAL_NUMBER` output string will be returned. Otherwise, `EquipmentManager#updateEquipment` is called. +#### Step 4 +`UpdateCommand#execute` is run to process the update. If the serialNumber attribute is null, a `CommandResult` with a `MISSING_SERIAL_NUMBER` output string will be returned. Otherwise, `EquipmentManager#updateEquipment` is called. -Step 5. If the update was successful, a `CommandResult` with success message will be returned, else a `CommandResult` with `UPDATE_FAILURE_MESSAGE` will be returned. Upon successful update, the object should be updated with the new attributes as shown in the diagram below. +#### Step 5 +If the update was successful, a `CommandResult` with success message will be returned, else a `CommandResult` with `UPDATE_FAILURE_MESSAGE` will be returned. Upon successful update, the object should be updated with the new attributes as shown in the diagram below. ![equipment1](images/equipment1.png) -Step 6. It is not shown in the sequence diagram but ultimately when the CommandResult is returned to `Duke`, the output of the `CommandResult` gets printed out and displayed to the user. +#### Step 6 +It is not shown in the sequence diagram but ultimately when the CommandResult is returned to `Duke`, the output of the `CommandResult` gets printed out and displayed to the user. ### EquipmentManager @@ -129,7 +132,7 @@ These methods are used during the execution of each of the `Command` class. * `updateEquipment` — Updates the specified `Equipment` with the corresponding updates given in the ArrayList of pairs. * `deleteEquipment` — Deletes the specified `Equipment`. -The `EquipmentManager` is implemented as the main storage unit of all the equipments during the execution of the program. +The `EquipmentManager` is implemented as the main storage unit of all `Equipment` during the execution of the program. ### Storage From baab98cbbe5b888d81f48b0c24332cc11b01889d Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sun, 10 Apr 2022 01:15:20 +0800 Subject: [PATCH 206/229] Reformat Instructions for manual testing --- docs/DeveloperGuide.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 5e67f8ab47..ec0fcb7bc6 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -224,57 +224,76 @@ Further, maintaining a record of the equipment is a time-consuming task given th ### Adding equipment 1. Adding equipment to inventory 1. Test case: ``add n/`SpeakerB` s/`S1404115ASF` t/`Speaker` c/`1000` pf/`Loud_Technologies` pd/`2022-02-23` `` + Expected: Equipment successfully added. 2. Test case: ``add n/`SpeakerB` s/`S1404115ASF` c/`1000` pf/`Loud_Technologies` pd/`2022-02-23` `` + Expected: Unable to add equipment with missing attributes. 3. Test case: ``add n/`SpeakerB` s/`S1404115ASF` t/`something` c/`1000` pf/`Loud_Technologies` pd/`2022-02-23` `` + Expected: Unable to add equipment, Equipment Type has to be `MICROPHONE`, `SPEAKER`, `STAND` or `CABLE`. 4. Test case: ``add n/`SpeakerB` s/`S1404115ASF` t/`something` c/`1000` pf/`Loud_Technologies` pd/`2123928` `` + Expected: Unable to add equipment, date must be in YYYY-MM-DD format. 2. Adding equipment with duplicate serial number to inventory 1. Prerequisites: There is already equipment in the inventory, for example the one added above. 2. Test case: ``add n/`SpeakerB` s/`S1404115ASF` t/`Speaker` c/`1000` pf/`Loud_Technologies` pd/`2022-02-23` `` + Expected: Unable to add equipment with duplicate serial number. + ### Updating equipment 1. Updating equipment in inventory 1. Prerequisite: There is already equipment present in the inventory. 2. Test case: ``update s/`S1404115ASF` n/`SpeakerC` c/`2510` pd/`2022-08-21` `` + Expected: Equipment details updated with the specified values 3. Test case: ``update s/`S1404115ASF` c/`2510` rand/`SpeakerC` pd/`2022-08-21` `` + Expected: Update unsuccessful due to unrecognised tag. ### Checking equipment 1. Checking for equipment matching to a specified attribute value 1. Prerequisite: There is already equipment present in the inventory. 2. Test case: ``check n/`Mic` `` + Expected: List of equipment with name containing `Mic`. 3. Test case: ``check c/`700` `` + Expected: List of equipment with cost of `700`. 4. Test case: ``check pf/`Tech` `` + Expected: List of equipment purchased from supplier with name containing `Tech`. 5. Test case: ``check pd/`2022-01-27` `` + Expected: List of equipment purchased on `2022-01-27`. 6. Test case: ``check t/`SPEAKER` `` + Expected: List of equipment of type `SPEAKER`. 2. Checking for equipment, but using wrong input format 1. Prerequisite: There is already equipment present in the inventory. 2. Test case: ``check c/`hello` `` + Expected: Error in displaying equipment, specified cost needs to be able to be parsed to double. 3. Test case: ``check t/`BLA` `` + Expected: Error in displaying equipment, specified type has to be `MICROPHONE`, `SPEAKER`, `STAND` or `CABLE`. 4. Test case: ``check pd/`2022` `` + Expected: Error in displaying equipment, specified date needs to follow `YYYY-MM-DD` format. ### Listing equipment 1. Listing all equipment available in inventory 1. Test case: `list` + Expected: List of all equipment. ### Saving 1. Manual saving of application state 1. Test case: `save` + Expected: Successfully saved. 2. Auto saving of application state 1. Prerequisite: Application state automatically saved after every 5 commands issued. 2. Test case: Execution of any 5 commands + Expected: Application auto saved. \ No newline at end of file From 9ade160af714e22ca7a6ed89a07b36567695bd81 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sun, 10 Apr 2022 01:19:42 +0800 Subject: [PATCH 207/229] Add Parser terminology to glossary --- docs/DeveloperGuide.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index ec0fcb7bc6..643fefd048 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -199,8 +199,10 @@ Further, maintaining a record of the equipment is a time-consuming task given th * *Equipment* - Each entity that is being stored/manipulated in the application * *Inventory* - Refers to the whole of the Equipment stored in the application -* *Command* - Keywords that users use to tell the application to perform certain actions -* *CommandResult* - Results that are produced from the execution of Commands. +* *Command Word* - First word keyed preceding any subsequent arguments to indicate a command to the application +* *Argument Pair/Type/Value* - Refers to a pair of words keyed following a command word, indicating a type of attribute to be updated and its value +* *`Command`* - Keywords that users use to tell the application to perform certain actions +* *`CommandResult`* - Results that are produced from the execution of Commands. -------------------------------------------------------------------------------------------------------------------- ## Instructions for manual testing From 7b3cef31d7585159541ddf4dbd10e0b58d05f7df Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sun, 10 Apr 2022 01:24:30 +0800 Subject: [PATCH 208/229] Update Parser regex documentation --- docs/DeveloperGuide.md | 5 +++-- src/main/java/seedu/parser/Parser.java | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 643fefd048..f72349c532 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -68,8 +68,9 @@ In the case where a second substring is not required, as in the case of `help` a

[argumentType/`argumentValue`] [...]

Complex commands such as `add` and `update` necessitate multiple arguments. -To implement this while ensuring that multi-word strings are acceptable input, `extractArguments` is implemented. -Without specifically explaining the main regular expression ([details here](https://regex101.com/r/gwjHWD/3)), the approach sought to match `argumentType` and argumentValue pairs with a positive lookahead. +To implement this while ensuring that multi-word strings are acceptable input, `extractArguments` is implemented. + +The main regular expression ([details here](https://regex101.com/r/dMwMWw/3)) sought to match `argumentType` and argumentValue pairs with a positive lookahead. The final argument pair will then be extracted using a separate regex. Together, this ensured that all argument pairs can be effectively parsed and dispatched to each `Command` class. diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 199316159c..40ebe8b8da 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -46,7 +46,7 @@ public class Parser { + "`+"; // backticks to enclose string /** * Extracts first n-1 tags for debugging and assumes that the last tag contains the whole string, refer to: - * Regex101 for demo. + * Date: Sun, 10 Apr 2022 01:27:22 +0800 Subject: [PATCH 209/229] Update User Stories table --- docs/DeveloperGuide.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index f72349c532..9282759b89 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -178,12 +178,12 @@ Further, maintaining a record of the equipment is a time-consuming task given th | Version | As a ... | I want to ... | So that I can ... | |---------|---------------------------------------|----------------------------------------------------------------|----------------------------------------------------------------------| -| v_.0 | new user | see usage instructions | refer to them when I forget how to use the application | -| v_.0 | new user | list all equipment | see all current equipment in the application | -| v_.0 | conscientious logs chief | add equipment | newly purchased equipment can be kept up to date | -| v_.0 | meticulous logs chief | update equipment | correct any errors in previously recorded equipment | -| v_.0 | conscientious logs chief | delete equipment | remove decommissioned equipment from the application | -| v_.0 | forgetful logs chief | search for equipment | be able to find equipment by its attributes | +| v1.0 | new user | list all equipment | see all current equipment in the application | +| v1.0 | conscientious logs chief | add equipment | newly purchased equipment can be kept up to date | +| v2.0 | new user | see usage instructions | refer to them when I forget how to use the application | +| v2.0 | meticulous logs chief | update equipment | correct any errors in previously recorded equipment | +| v2.0 | conscientious logs chief | delete equipment | remove decommissioned equipment from the application | +| v2.1 | forgetful logs chief | search for equipment | be able to find equipment by its attributes | | v3.0 | forward-planning logs chief | filter equipment purchased before a certain date | conduct more regular inspections on them | | v3.0 | busy logs chief | mark equipment to be faulty/working | filter and send the faulty ones for repair | | v3.0 | logs chief supporting multiple events | ensure that equipment can be earmarked for an associated event | my equipment will not be double-booked and have scheduling conflicts | From d9677f8b7153d2af43b524fdb541fa07c16ed08e Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sun, 10 Apr 2022 01:57:10 +0800 Subject: [PATCH 210/229] Touchup rest of DeveloperGuide.md --- docs/DeveloperGuide.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 9282759b89..14b52e88e6 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -171,7 +171,7 @@ The target user is the logistics chief of an event support club. He is responsib Equipment for the club differ in terms of shape and size. Owing to the climate-sensitive and fragile nature of some of these equipment, they are often stored in opaque containers, which may not be easily accessible or quickly identifiable given space constraints. By keeping records of this information on our application, the logistics chief can easily access and retrieve this information without having to make a physical trip down to the storeroom. -Further, maintaining a record of the equipment is a time-consuming task given that they often need to be referred to by both the model number and a short alias used by club members. As the post of logistics chief is changed every year when passed down to a new member, this member will need to be acquainted with both the common name and the model number of the relevant equipment. Our application thus provides a convenient way to search by both specifications. +Further, maintaining a record of the equipment is a time-consuming task given that they often need to be referred to by both the serial number and a common name (short alias) used by club members. As the post of logistics chief is changed every year when passed down to a new member, this member will need to be acquainted with both the common name and the serial number of the relevant equipment. Our application thus provides a convenient way to search by both specifications. In fact, additional information such as the vendor, purchased date, equipment type, and the cost of the equipment is also stored and searchable. -------------------------------------------------------------------------------------------------------------------- ## User Stories @@ -182,6 +182,7 @@ Further, maintaining a record of the equipment is a time-consuming task given th | v1.0 | conscientious logs chief | add equipment | newly purchased equipment can be kept up to date | | v2.0 | new user | see usage instructions | refer to them when I forget how to use the application | | v2.0 | meticulous logs chief | update equipment | correct any errors in previously recorded equipment | +| v2.0 | conscientious logs chief | save the state of the equipment list | come back to a saved version of my work later on | | v2.0 | conscientious logs chief | delete equipment | remove decommissioned equipment from the application | | v2.1 | forgetful logs chief | search for equipment | be able to find equipment by its attributes | | v3.0 | forward-planning logs chief | filter equipment purchased before a certain date | conduct more regular inspections on them | @@ -193,7 +194,9 @@ Further, maintaining a record of the equipment is a time-consuming task given th -------------------------------------------------------------------------------------------------------------------- ## NonFunctional Requirements -{Give non-functional requirements} +1. Spaces should be permitted as a delimiter for equipment attributes of type String, e.g. equipment name, vendor name. +2. Equipment name need not be unique as there may be multiple equipment with the same name. +3. Serial number should be unique and case-insensitive. -------------------------------------------------------------------------------------------------------------------- ## Glossary From c0769db09ab1f2ac776e2fd3cf5a4d6f56c0e393 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sun, 10 Apr 2022 02:09:57 +0800 Subject: [PATCH 211/229] Catch DateTimeParseException for Update command --- src/main/java/seedu/parser/Parser.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 199316159c..0b51ca11b2 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -140,6 +140,8 @@ public Command parseCommand(String userInput) { 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(); From 31997937c40aa05ad3e91d1233099bd6c32e80bb Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sun, 10 Apr 2022 02:16:17 +0800 Subject: [PATCH 212/229] Fix uncaught exceptions in Parser --- src/main/java/seedu/parser/Parser.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 0b51ca11b2..2164fbea15 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -122,6 +122,12 @@ public Command parseCommand(String userInput) { return new CheckCommand(args); } catch (IncompleteCommandException e) { return new IncorrectCommand(CheckCommand.COMMAND_WORD + CheckCommand.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 DeleteCommand.COMMAND_WORD: try { From 6a0e8a203b489e896de8010764ef1cb0c26ffc30 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sun, 10 Apr 2022 02:20:53 +0800 Subject: [PATCH 213/229] Complete JavaDoc for Parser.java --- src/main/java/seedu/parser/Parser.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 40ebe8b8da..214410a2e3 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -207,8 +207,8 @@ public ArrayList splitCommandTerm(String userInput) throws IncompleteCom } /** - * Prepare argument for CheckCommand by matching the preceding "n/" prefix, setting it to lowercase and verifying - * that there are no additional tags. + * 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) @@ -224,8 +224,8 @@ protected ArrayList prepareCheck(String args) throws IncompleteCommandEx } /** - * Prepare argument for DeleteCommand by matching the preceding "s/" prefix, setting it to lowercase and verifying - * that there are no additional tags. + * 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) @@ -241,7 +241,8 @@ protected ArrayList prepareDelete(String args) throws IncompleteCommandE } /** - * Splits main arguments into split tags with each substring. + * 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 From 1e1b00e4979fab6474feaf49a4a71bafdaa9b474 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sun, 10 Apr 2022 02:32:04 +0800 Subject: [PATCH 214/229] Update shunyao643.md --- docs/team/shunyao643.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/team/shunyao643.md b/docs/team/shunyao643.md index 8188ab2db9..ff9d8f50e1 100644 --- a/docs/team/shunyao643.md +++ b/docs/team/shunyao643.md @@ -9,7 +9,8 @@ EquipmentManager is a Command Line Interface application to help with keeping tr Code contribution can be found [here](https://nus-cs2113-ay2122s2.github.io/tp-dashboard/?search=shunyao643&breakdown=true&sort=groupTitle&sortWithin=title&since=2022-02-18&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other). ### Enhancements implemented -* In charge of the parsing of commands prior to command execution. Parser implements a regex-based approach to parsing commands. +* In charge of the parsing of commands prior to command execution. + * Parser implements a regex-based approach to parsing commands. This is challenging and necessary due to non-functional requirements of the project. ### Contributions to UG * Add top-level introduction summary. @@ -21,6 +22,7 @@ Code contribution can be found [here](https://nus-cs2113-ay2122s2.github.io/tp-d * Update user-stories and non-functional requirements in line with progress of the project. ### Contributions to team-based tasks +* Product Owner for the project. * Set up GitHub team organisation and repository. * Maintain issue tracker throughout project with the use of assignees, labels, closing statements and milestones. * Manage release of v1.0 of the project. From 905863eeb0a1502bf3bb44c40cbb9b6f01c6daf6 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sun, 10 Apr 2022 10:15:05 +0800 Subject: [PATCH 215/229] Update enhancements implemented --- docs/team/shunyao643.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/team/shunyao643.md b/docs/team/shunyao643.md index ff9d8f50e1..f7d85869ad 100644 --- a/docs/team/shunyao643.md +++ b/docs/team/shunyao643.md @@ -11,6 +11,7 @@ Code contribution can be found [here](https://nus-cs2113-ay2122s2.github.io/tp-d ### Enhancements implemented * In charge of the parsing of commands prior to command execution. * Parser implements a regex-based approach to parsing commands. This is challenging and necessary due to non-functional requirements of the project. +* Implement DateTime functionality throughout the application's classes. ### Contributions to UG * Add top-level introduction summary. From 208785a6ad5790e806d09f909a69394dd47c0a94 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sun, 10 Apr 2022 10:28:22 +0800 Subject: [PATCH 216/229] Update Parser to remove unnecessary exceptions in CheckCommand --- src/main/java/seedu/parser/Parser.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 1b66a44f77..8e26fa84bd 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -122,12 +122,6 @@ public Command parseCommand(String userInput) { return new CheckCommand(args); } catch (IncompleteCommandException e) { return new IncorrectCommand(CheckCommand.COMMAND_WORD + CheckCommand.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 DeleteCommand.COMMAND_WORD: try { From b3e1e5b6be375421b68191f892d8c46c93fa486a Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sun, 10 Apr 2022 10:29:21 +0800 Subject: [PATCH 217/229] Remove disabled test cases in ParserTest.java --- src/test/java/seedu/parser/ParserTest.java | 66 ---------------------- 1 file changed, 66 deletions(-) diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index d212362728..73d6f11495 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -179,72 +179,6 @@ void prepareDelete_missingBackBackTick_exceptionThrown() { } } - @Disabled - @Test - void extractArguments_validCommands_success() throws IncompleteCommandException { - ArrayList testStrings = new ArrayList<>(Arrays.asList( - "s/S1404115ASF n/Speaker B t/Speaker c/1000 pf/Loud Technologies pd/2022-02-23", - "s/S1404115ASF c/1000.3", - "s/S1404115ASF n/Speaker B ", - "s/S1404115ASF pf/Loud Technologies n/Speaker B", - "t/Speaker s/S1404115ASF", - "c/1000 pf/Loud Technologies s/S1404115ASF" - )); - ArrayList> expectedResults = new ArrayList<>(); - expectedResults.add(new ArrayList<>(Arrays.asList( - "s/S1404115ASF", "n/Speaker B", "t/SPEAKER", "c/1000", "pf/Loud Technologies", "pd/2022-02-23"))); - expectedResults.add(new ArrayList<>(Arrays.asList( - "s/S1404115ASF", "c/1000.3"))); - expectedResults.add(new ArrayList<>(Arrays.asList( - "s/S1404115ASF", "n/Speaker B"))); - expectedResults.add(new ArrayList<>(Arrays.asList( - "s/S1404115ASF", "pf/Loud Technologies", "n/Speaker B"))); - expectedResults.add(new ArrayList<>(Arrays.asList( - "t/SPEAKER", "s/S1404115ASF"))); - expectedResults.add(new ArrayList<>(Arrays.asList( - "c/1000", "pf/Loud Technologies", "s/S1404115ASF"))); - for (int i = 0; i < expectedResults.size(); i++) { - ArrayList testResultsSorted = parser.extractArguments(testStrings.get(i)); - ArrayList expectedResultsSorted = expectedResults.get(i); - testResultsSorted.sort(Comparator.comparing(String::toString)); - expectedResultsSorted.sort(Comparator.comparing(String::toString)); - assertEquals(expectedResultsSorted, testResultsSorted); - } - } - - @Disabled - @Test - void extractArguments_mixedCaseText_success() throws IncompleteCommandException { - ArrayList testStrings = new ArrayList<>(Arrays.asList( - "S/S1404115ASF n/Speaker B t/Speaker c/1000 Pf/Loud Technologies PD/2022-02-23", - "s/S1404115ASF C/1000", - "s/S1404115ASF N/Speaker B ", - "s/S1404115ASF pf/Loud Technologies n/Speaker B", - "t/Speaker S/S1404115ASF", - "c/1000 pF/Loud Technologies s/S1404115ASF" - )); - ArrayList> expectedResults = new ArrayList<>(); - expectedResults.add(new ArrayList<>(Arrays.asList( - "s/S1404115ASF", "n/Speaker B", "t/SPEAKER", "c/1000", "pf/Loud Technologies", "pd/2022-02-23"))); - expectedResults.add(new ArrayList<>(Arrays.asList( - "s/S1404115ASF", "c/1000"))); - expectedResults.add(new ArrayList<>(Arrays.asList( - "s/S1404115ASF", "n/Speaker B"))); - expectedResults.add(new ArrayList<>(Arrays.asList( - "s/S1404115ASF", "pf/Loud Technologies", "n/Speaker B"))); - expectedResults.add(new ArrayList<>(Arrays.asList( - "t/SPEAKER", "s/S1404115ASF"))); - expectedResults.add(new ArrayList<>(Arrays.asList( - "c/1000", "pf/Loud Technologies", "s/S1404115ASF"))); - for (int i = 0; i < expectedResults.size(); i++) { - ArrayList testResultsSorted = parser.extractArguments(testStrings.get(i)); - ArrayList expectedResultsSorted = expectedResults.get(i); - testResultsSorted.sort(Comparator.comparing(String::toString)); - expectedResultsSorted.sort(Comparator.comparing(String::toString)); - assertEquals(expectedResultsSorted, testResultsSorted); - } - } - @Test void extractArguments_noSpaceBeforeTypeSlashDelimiterFound_exceptionThrown() { ArrayList expectedResult = new ArrayList<>(Arrays.asList( From e932e3aba5a1669b274c7fc3e14ee844b5d669ea Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Sun, 10 Apr 2022 10:37:17 +0800 Subject: [PATCH 218/229] Add minor details to DG and change portfolio part in AboutUs --- docs/AboutUs.md | 10 +++++----- docs/DeveloperGuide.md | 10 ++++++++++ docs/team/Bryan-BC.md | 2 +- .../java/seedu/equipment/EquipmentManager.java | 16 ---------------- 4 files changed, 16 insertions(+), 22 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index b77430885b..a5417beac9 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,9 @@ # About us -| Display | Name | Github Profile | Portfolio | -|-----------------------------------------------------|:-----------------:|:---------------------------------------:|:-------------------------------------:| -| ![](https://via.placeholder.com/100.png?text=Photo) | Bryan Christopher | [Github](https://github.com/Bryan-BC) | [Portfolio](team/bryanchristopher.md) | -| ![](https://via.placeholder.com/100.png?text=Photo) | Bai Shun Yao | [Github](https://github.com/shunyao643) | [Portfolio](team/shunyao.md) | -| ![](https://via.placeholder.com/100.png?text=Photo) | Yu Hao | [Github](https://github.com/yuhaochua) | [Portfolio](team/yuhaochua.md) | +| Display | Name | Github Profile | Portfolio | +|-----------------------------------------------------|:-----------------:|:---------------------------------------:|:-------------------------------:| +| ![](https://via.placeholder.com/100.png?text=Photo) | Bryan Christopher | [Github](https://github.com/Bryan-BC) | [Portfolio](team/Bryan-BC.md) | +| ![](https://via.placeholder.com/100.png?text=Photo) | Bai Shun Yao | [Github](https://github.com/shunyao643) | [Portfolio](team/shunyao643.md) | +| ![](https://via.placeholder.com/100.png?text=Photo) | Yu Hao | [Github](https://github.com/yuhaochua) | [Portfolio](team/yuhaochua.md) | diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index b21f4a1e77..e6858cfc61 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -157,6 +157,16 @@ The method is able to handle the cases where: While loading the data, the `equipment.json` file is read and the data is converted from a JSON string to an ArrayList of `Equipment` objects. The ArrayList of `Equipment` objects is then added to the `equipmentList` HashMap. +The `Storage` class is used in the `Duke` class. +It is used to save and load the data of the program. +Below are the procedures of the `Storage` class usage during program execution. + +1. `Duke` is initialised. +2. `Storage` is initialised. +3. `Storage#loadData` is called to load the data from the `equipment.json` file. +4. After every 5 commands, `Storage#saveData` is called to save the data to the `equipment.json` file. +5. Lastly, before the program terminates, `Storage#saveData` is called to save the data to the `equipment.json` file. + -------------------------------------------------------------------------------------------------------------------- ## Product scope ### Target user profile diff --git a/docs/team/Bryan-BC.md b/docs/team/Bryan-BC.md index 9db3627ee9..3837669c5e 100644 --- a/docs/team/Bryan-BC.md +++ b/docs/team/Bryan-BC.md @@ -6,7 +6,7 @@ EquipmentManager is a Command Line Interface application to help with keeping tr ## Summary of Contributions Besides reviewing pull requests and participating in discussions during meetings, below are the main contributions made to the project: -## Contributions to the Codebase +### Contributions to the Codebase * Implementation of the classes in the equipment package. * Implementation of the classes in the storage package. * Implementation of Gson for serialization and deserialization of the data. diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index e5091a15aa..4fb33b74a1 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -114,22 +114,6 @@ public ArrayList listEquipment() { return new ArrayList<>(equipmentList.values()); } - /** - * Creates an ArrayList of all Equipment with the specified EquipmentType. - * - * @param type Type of equipment in EquipmentType enum. - * @return An ArrayList of Equipment Objects with the specified type in equipmentList. - */ - public ArrayList listEquipment(EquipmentType type) { - ArrayList listOfEquipments = new ArrayList<>(); - for (Equipment equipment : equipmentList.values()) { - if (equipment.getType().equals(type)) { - listOfEquipments.add(equipment); - } - } - return listOfEquipments; - } - public HashMap getEquipmentList() { return equipmentList; } From ec269c972b7c279625612937c904b2b381866a58 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Sun, 10 Apr 2022 10:37:17 +0800 Subject: [PATCH 219/229] Add minor details to DG and change portfolio part in AboutUs --- docs/AboutUs.md | 10 +++++----- docs/DeveloperGuide.md | 10 ++++++++++ docs/team/Bryan-BC.md | 2 +- .../java/seedu/equipment/EquipmentManager.java | 16 ---------------- 4 files changed, 16 insertions(+), 22 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index b77430885b..a5417beac9 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,9 @@ # About us -| Display | Name | Github Profile | Portfolio | -|-----------------------------------------------------|:-----------------:|:---------------------------------------:|:-------------------------------------:| -| ![](https://via.placeholder.com/100.png?text=Photo) | Bryan Christopher | [Github](https://github.com/Bryan-BC) | [Portfolio](team/bryanchristopher.md) | -| ![](https://via.placeholder.com/100.png?text=Photo) | Bai Shun Yao | [Github](https://github.com/shunyao643) | [Portfolio](team/shunyao.md) | -| ![](https://via.placeholder.com/100.png?text=Photo) | Yu Hao | [Github](https://github.com/yuhaochua) | [Portfolio](team/yuhaochua.md) | +| Display | Name | Github Profile | Portfolio | +|-----------------------------------------------------|:-----------------:|:---------------------------------------:|:-------------------------------:| +| ![](https://via.placeholder.com/100.png?text=Photo) | Bryan Christopher | [Github](https://github.com/Bryan-BC) | [Portfolio](team/Bryan-BC.md) | +| ![](https://via.placeholder.com/100.png?text=Photo) | Bai Shun Yao | [Github](https://github.com/shunyao643) | [Portfolio](team/shunyao643.md) | +| ![](https://via.placeholder.com/100.png?text=Photo) | Yu Hao | [Github](https://github.com/yuhaochua) | [Portfolio](team/yuhaochua.md) | diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 14b52e88e6..315a85bf22 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -161,6 +161,16 @@ The method is able to handle the cases where: While loading the data, the `equipment.json` file is read and the data is converted from a JSON string to an ArrayList of `Equipment` objects. The ArrayList of `Equipment` objects is then added to the `equipmentList` HashMap. +The `Storage` class is used in the `Duke` class. +It is used to save and load the data of the program. +Below are the procedures of the `Storage` class usage during program execution. + +1. `Duke` is initialised. +2. `Storage` is initialised. +3. `Storage#loadData` is called to load the data from the `equipment.json` file. +4. After every 5 commands, `Storage#saveData` is called to save the data to the `equipment.json` file. +5. Lastly, before the program terminates, `Storage#saveData` is called to save the data to the `equipment.json` file. + -------------------------------------------------------------------------------------------------------------------- ## Product scope ### Target user profile diff --git a/docs/team/Bryan-BC.md b/docs/team/Bryan-BC.md index 9db3627ee9..3837669c5e 100644 --- a/docs/team/Bryan-BC.md +++ b/docs/team/Bryan-BC.md @@ -6,7 +6,7 @@ EquipmentManager is a Command Line Interface application to help with keeping tr ## Summary of Contributions Besides reviewing pull requests and participating in discussions during meetings, below are the main contributions made to the project: -## Contributions to the Codebase +### Contributions to the Codebase * Implementation of the classes in the equipment package. * Implementation of the classes in the storage package. * Implementation of Gson for serialization and deserialization of the data. diff --git a/src/main/java/seedu/equipment/EquipmentManager.java b/src/main/java/seedu/equipment/EquipmentManager.java index e5091a15aa..4fb33b74a1 100644 --- a/src/main/java/seedu/equipment/EquipmentManager.java +++ b/src/main/java/seedu/equipment/EquipmentManager.java @@ -114,22 +114,6 @@ public ArrayList listEquipment() { return new ArrayList<>(equipmentList.values()); } - /** - * Creates an ArrayList of all Equipment with the specified EquipmentType. - * - * @param type Type of equipment in EquipmentType enum. - * @return An ArrayList of Equipment Objects with the specified type in equipmentList. - */ - public ArrayList listEquipment(EquipmentType type) { - ArrayList listOfEquipments = new ArrayList<>(); - for (Equipment equipment : equipmentList.values()) { - if (equipment.getType().equals(type)) { - listOfEquipments.add(equipment); - } - } - return listOfEquipments; - } - public HashMap getEquipmentList() { return equipmentList; } From 995ff01ad1bb5cbf99b9097b35996c7f72c4b980 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sun, 10 Apr 2022 10:38:39 +0800 Subject: [PATCH 220/229] Add test case for updateCommand to catch incorrect Date exception --- src/test/java/seedu/parser/ParserTest.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 73d6f11495..485869ace6 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -7,6 +7,7 @@ import seedu.command.DeleteCommand; import seedu.command.IncorrectCommand; import seedu.command.ListCommand; +import seedu.command.UpdateCommand; import java.util.ArrayList; import java.util.Arrays; @@ -233,10 +234,18 @@ void parseCommand_trailingWhiteSpace_success() { } @Test - void parseCommand_deleteCommand_wrongArgType_exceptionThrown() { + void parseCommand_deleteCommandWrongArgType_exceptionCaught() { Command expectedCommand = new IncorrectCommand(DeleteCommand.COMMAND_WORD + DeleteCommand.COMMAND_DESCRIPTION); - Command testCommand = parser.parseCommand("delete x/S1234567E"); + 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); } From 20f0798ffac15f806e9b5216addfddaec4938436 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sun, 10 Apr 2022 10:40:11 +0800 Subject: [PATCH 221/229] Minor edit to sequenceDiagram screenshot --- docs/images/sequenceDiagram1.png | Bin 25306 -> 24402 bytes docs/images/sequenceDiagramExecute.png | Bin 24768 -> 24622 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/images/sequenceDiagram1.png b/docs/images/sequenceDiagram1.png index 27ec781007c5e3e3f8984fb063a85d65621d6689..02d7471087c8bf5341871696e582386d14bdc1fd 100644 GIT binary patch literal 24402 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

LIrx)ESWXPTJ}+yIP)q@wm68g6zb2}M(XG5 z$|{Hc!7fmW9zn!xq^*1bd4{Usrc#1D#hS=v?0G9PCbVOws>4>?Y1k{ zfpfDr1RkU)?~iTxs&lBOFmlhSMm$7i2vj=r5=^c41!fyQG<#w2>0emBgHxH~2sLzF zls|{{8BlXvO}4Z}`Ldodu;>TJ`odeW zjt9LhfQY_YqUl1MOVbS{yp4PbiO)_2;v?`Em-(;Dt4>Y8;dk60aeZOam=R{k@1EF< zhe%uD5p!*6X_@8lRbrob-HMI>Xhg?y76am1YBEm#i#D(|fB?VNKfjzK^|CBN!;$LA zKF)i1i$Ug7EfpXmq;|TJX(!dP1EO zW0d8}XFTsUxn0ghARkgTzxiR8T%H%&k(V-taX^M-D-L=tH=(6 z+7Yl=jnHv(;laaQQ9f zQ;h>Ao1{jR&xXWpvMxJs4IJQgYQ_1o?_ykh>rBO zdVMz!!3;%hVZBMN;1wQqby5w1rh1znzW(V(lREB(^7VGuwtzXUSyJ+G(77vE+w$rc_P5s-XszN>kmh8@Z{s*8QwQ6`w zHekV{rS`-X;9|6gs#teXFP?6!yc#Nceb+{OLmHz=3YS46ODW_j*fcNR%}{8G5R5|n zy`@{5&<|hS%m(PH*%C-Cj$fN2G+hZs70Mev#Rv1cm+eDsv(_j6K^tBX@hwG{O5 zD3gh@eEs2^xHN^#aOJ#r9#h^Y?*H8HDw`@vT9K4(9+0iD=FT+g5>;v_= z)ztW#B79uaDm7wCC@;KJhvojl}qY&G~7*HOL>Jg-=2JR~*ANa;cKO06(<5 z9F=U>Ue`cDau&D!PQpl@mKTS^-j9px%I%s5G3;iz=f~TnT{>L!Ilo7B;m!WR!RxjI z0MR`A{Jp)$(`vb^y_PY(j0~CRH;kB`5~o!wlb$edMANQwhn+hbH^U3!J4?&D2AE(` z0OpBEAU2(95vHII>V5Dq&akFiwf;a_h;pIc=M6zGM6{-!L_uK?c$$W?-|D`CQF#+U z9LH)D&I1Il*u+3z;x&(dmX&dbBDAvy4kBeVkVZCTKab`Tfq-gqyfwMVR*?BjEc}aG zso6ArVIgD7`fx7ZV1`0iOA#3VP<{~aQRK>GWohS`>3E66#cq%r_I%6duzANIB2H~x zpTqe%)Z1m&*RO__ARZq4ArK#2#0PexwMSz{XE|zhJ$!p@Plm1)GUV@n#2^iCL}f(B ziyGo{Icsyo@7HSdQ88h9s@3%A{+@;5a1PzFs&GpQC`AUNXQN||T`R{N5hM+@IC;!gr>)^;|SsU+5qqQm8U zV!l4I{LM*H4;qNTihj*3h7I^i3@Vw!$ zv#wta4NWf^U4XGK*0ZL|<7o!^$_-`%Lz!Up;_cG!Ej=YBR{2O zA&4`ugfzQ%%{-38ViQZDP)(aI34;T-kM?Lgjc{_84MarYA`4IA+!_&m;2o!8p4l{CW|w>(X+m{Pw+1#S+{8vw{dny=V>zE| z)lw^Oyztn~Jabh5V8@`i5e^aj%#-raIk?OiY3)eD0RQZ~ z7Hx}oD@_NBbfSq>U=QWrFr}PmIFKe|X-Iw1eC_Rx%+5u=>*4t5pD?5W$N!lQnMMQ5 zGREJtjCEpQEIQH##%KNaqPyPQe($uG$(Q7>?eXPt36D<=+LV< z*h_z69m;F{O<{% z_@}Xd1M@$x{pT3Q3&H+(W5dDo`@#({7SifKK=Z@Uqxp}V^np}D3&uz0>*i#J|shIf;%KKOu;^{mPiRJNUm zwRqyoKM_5Ln2_23n%ld~JKgd8nnk9Qs=2tDZkNT-;HEzf6-{evMk;JFr=FTCW+{_V zD`ru0*=^B2WHY7&W+e*Ac)o1*pB&Jt+-7Yc|Ekr99USqu_smw7`#G&wg7Mi+V>RL| zJO`MN`Tu?$_0I9;xY9s|f>@E^;G5}Z8ZL(lyPyL6xe4k!(Fe#~v7BM%?5n;HD4KTX zTbl!kxtm%^-C~WV0VB|qA`!E|=QMsi?KaK)9SMU3n~=>IlS1lSQQ-Mj<#rRGCz`J= z&$HQ*-+V2&LIMRrZX}yY^u!ei>dh^m39U9;bzBYym6*9R&MrpZ$NOUNU-S&RCLEKd zE$2BMn?})<49`1kOjfc-zybgmDd{XKJ-So)zFXDB#_=+?EA`l5vEyqJz#VgdWC^}r z&s9&k`=<3NcfwzROWK3<6;4YlL?4IIzS`*+7mDC6uIoJDnRSfb1LQsDLuiT#kBEx- zr-;2Sw2X4oMG!}D^e6W5+ zvpy))`xT0CnFnu$hEB>y3k`3G7$mgMOF`=Rdbpwl3OL~)5?-ON)Cvo`)sBauNCF#;m>duE^Noh-WzuDzo$^GpnHUmCqkb-141c?D6w7JVlqU0ifvq5i z)o>uME49{Da{2ioa(AWiXn{5;2wR5fyhxR%JEN2h>M985KgbCA zU8^pTiATlpYhz=HR6c5JgWROu5Hvl2z_!xCZh$-%n1zD2cazOkD?L>HTfeU{iotC4NfB^ zCU1drXH3`ck&Sr6-;v4_^&%aW?qn&(Ob8G(i`@(4@7hQl7VZO+7)J?VzBz0i71qm)AnO{08gD^CnyLW(zg61^0H4Vp0Fx$&v<91jf*=%=0cB{E4~ z-A5$2l+{rRsot2bt(|C*I#`j)xJjS7hcl5|$ZUjHgQg#%VUS6u?dtag z(gDJXuZUV_V`s8Ur#f`?4~H?L6rsHqKr96aprGquj4UPw`8Gz7%|hX#K(L176-fYJyxswKu}4uBO7$81>#p)UMTEQ0=PA(r*#n8Lxvs2t!GUOiN< zOjO{HdD7_H`Ixzg(YNizoU{D~C`o>n{I28)-dt2~*PQ>z|A1TtSTzV6mdX^uJzV9> zH+sKE5cHn8sEvgkTFJvc7o>#ui@zE?T8?+4Z*49y9+d^82ya1d-N6}WT=xKl?or61 zjpHWs%U~|@*?&OtUAdW$DzfaFoQbF;dQ?5By`D^7?Qamff@t&5^&a(fe>8s5l08?& z#aM#x6)ib&Fdb+hsR_~48o;sFunnztP1%n+yYu}srz1|vFui`m51mj4Xu?vX>b$`x z1#~<7fZQ4Co_Kmc;Lv5p1L?rfKdr`fG(~5Q0UBomZy^EV)k@-f`T0M2@c&yv`m=Y$ z5w4)B;1HW0Co~1jODLwqd^LX($|sC%I?%W7o=(RYH!S}iPR>RPS>?gme*I_tve{o6 zRb9gw8Vr{ct8m?|HAH!M=3e-?T6J%9qaMqFDf0dc7ew8?Aay-Sv|ma5xG=dF*?%zf z)(ppP${|%v_V6?NRNJ5}C^V96)`!a1@`Ox5)TG--Zu~UQ^h`NhwYUl7xa|=|Ew0>j zbU96hH0hVP#oBmvaEQv!I$iB*`}gaub)ihL8iE84YeY8Tj^pLkaV`5dZuNIZ@Wm53 zc+h;7dbBoCUZ{prre0}F5Via00qEg}zk2A3bmfJF;fF@Zw$O2<<>5K3;UppH(pTkR zl}QqI)`(5Tn9q-z;j*O)QQhV5{K1@_Teas`oB+f8VJ$YLqz>4}h|jXZ6N=&C(Y*XW z+{v@|YFIt3>uG2rhbMRoakkr@qKo$;uF{Z85oh{Fn5L6oFbwjXaWQP$!rboh_O#ic z7BxMsf&URoWukBjp$eowe=UC}8CDY)u$Nzr_@_P^^rxs?BYl|WA|FKn*h=Wvpu_|e z``35Z1ue?wyVu_qCJO?{Fb{ScXn94kYM|c zaxfT?b}516C&LpA6mi&w*Pl{)=lRZ)d)(ShcMU@G4yaKHd>+m$TkUMSUB7kS zYo|~=r+ZuS>9MfiLd9&mDYMocQs&ucf!KrYt$td(n z*4z!_YiS(HRFcwrFY{5?!UL?$j=Q`dy13W`+@T|99APd_V6$uy3X#*vj#h7`5KBH1p}UzF3ZP}GB2-jZ7|bn5W(Yi zAub@hbIpHHDL*_vDn@}j%;*@#v?G7%DBJFTNhHcpCaqYEw zV1zIg$UBkjX5U!S8EP*II)A`L>IKl*7#eZq%1vrs?cuF2(Lo}1!}za0dMLgd@<@B1wtG^QDY3l zx&YHc(1=Ga9vN&-tHF=2I@k@$Ff~_)Iz~kIR-q$Y9apcG+a+;rh-tVH?!d{(b?w_4 z%8uzgsyEgSNQKiw)p->{&{QUa&vY4+Ys!psq;&_s)RzEet85_XuAu+nx=3N7#!`7LP!%PD$+p#(pY@83s%{_M@DOx*&4#B>{ye-WD zL#xxOSIBq0ac8Q7ma7DM_%i1bT2KZXvZTO|JAy{1TyB|6saaFic{ayTFvy|VbCRwT z>hc%Zs^6}|C`8stt2>d7gA$`%T87=7O9&9LeqMf>7i9%kZXn+Srjkoc=3*~494^E}Ss5{c{y(oXt0K)}(k^hlqQU&aw%{J^RCvcMI#f1b10CPOK*OZWXhDF-{n zO6QP)R>)&tt4lr05HU|5ZmIegZh>fPlN&S{8`cxgp+oC5Ewqbi*Yj+9Kx#HkRXb&K zWxe>2{4W0!YoXgf-sb< zGz9U(6fSPV#cZIBwtcN2aXFAtsRj7IToymjY^*3<_bT-89tZEYbdv(d8Eg7H!@&&i z!7l3qtHz>?VLT|`ujf$@*xn`})tYSHd#*LW)K2twji)n13aYO-g3$yZ#$O5_;}25BqqHw;O~%<|fP$og5nNvM{-M|x z%2{PI5K3Kwc=kRWx`AS;X}0mBaH;9!57;}51&l@MX9%$*-2+4N(;#{}hy$97xH}oh zX6F_tmlN**<)qz{@N({OSQ8JZPH_qtes~Pu*01yCe&`6iz@K~Qi+)QJ%s}oi6P(05 zu2DrLBY?vE3p>SZs>Ose0;6j&NIG*sn8^!t09=-Et?T8&5y+lT&8#gm*at^Fw5on% z_p6UUHiCITE{+*SE)jZI=78eErcmp?x*I#j1wASSVYGrqT*n}0XA^d_nT$P+W--v- zY~*;0n%{;PYb}2FuAthJUXNSKD>mQ-IsA2d7zGeR>4aJXiG@LtxX?X||1+cP`s%z{ zH$t8K7Xb=$8vgNUiUgrWE3sYMZYebM85=>nC8MLy^aUmbhaBr&EG?=gRH_E#!(xs6 zC0t6YmEpR4E@RwJNoLR^_LSv}x1~8JliRKo(CP>(O&5!_904sXFOIB=V|9e4J%y)G zs((qSU>?@z<4S*`)+Z!WPirqebv2Eb{N{4Az_fUvo+#i}bK)5jLABU`IsDo>;TG~z zJi+v-3-S-Ic!{iIFzId)kH4Lv19}LHKL(akOy_eV0+((7T#07g>h7KZS2sex`?6O2 zN8ER9o^mN1#^Ck$B;~$oRTRGZ{IH#Y>2Q6xTlZ{}gV<~t7&yY&vBy9uA(f-`v^`G> z?>*f1_cNPDWK^bf<@}@-03|zjbRM#Ybv3$Qp3d2{E;BR8b$p=83E2>-HS>J>5mYvw zVfQ~-&A0(AsClLL`{A0h2LbUwkB@PkXsf9x+u|rtVhksLd}114^yEsJ-_EFP zn2wg+|HUF@bq>arwNCne5fUgZzsQx(-ovPiAc1T$JtM3`^Z3noL?W7w6&Va&x8a&i zl=T{VwYKa$fQSt4pMozzvJ%-NkKx*3&%LwK#R}8oj1s_{VwB9 zDtCR~$_#b?s?j%3pDnRxXIr%54`h{n;w z0p2Yfk*>{ zml*TDe7p(#K4>-u+5wAJ6_dFY&)9_HdUpAmxgg1sDk7u9*%u4OPiNK^F#MA`R63vl z^y?i08Z=CPER(6WJOY7gabGN)AOhn!f_uF)ufUE$IN^drxnbUau_DX7joUWuqxL=_B{j4BBQAtAmuCxeX#fMJ^Ajd z!U%Jg<=XO*si{m3V#vhKF#}{QdNTbi>+)ReR!# z*uag)UA|f{Zdd#9*)E2t*)AO%{b1t!gWi>R=BQWtedBfVW7h3Z_Q6rnh!lbdSjTm1Pmfa*$nk>{(0k8d?7`WJMx9zu9IDf7Eiy&w&plxg;qV{f`LK_TXDuwQ*rxDrj}lCFEM7mdcuq;GXLv zEe*H|k`_drl@G|9Naj)nm{g>Ekc&KvM!h_JZ1uTW$Q`^Q33K>hxG`|N+&3%^{>PY< z>mTg_1Y$NMS1dXdY|2Mn+}k`dY0_k;azzFg8DW8iXp#iWs4ZuYX`o@RfH#Npm&Jx{ zAY{fGT{zrOBu&o$@|F;neD#PBFx2F>f|(uNZdX>E=vIJ$EVw9-;(IDr+WeVq)b}92Q`kO8GNfx|V=#Siue9ll_rSIvJKEEW!sAeepH>wLjfVS3+o)%$|3AKRvO9D7a zd#cKT%BEA3U{2}4*yYQ-D%bLB^7KEniu^10VDay$C@rG4>q8RsF@89Cd01aPxdM?Y z3>2EbWw**U;NezqkiC`S4YvNXA}nxEH)c{u@m26~AbJusLNcwpFW3uGjCq&RlK-Wh zfvkYc%|2!S9UmAUMoP`%Ykor8H7z)F|BKWBApqzKyLA#JB!5*9K#T?|1qVr4`w%=( zE87>^!w#uK@BCMY_#+bkkyidsrNW!$kKX#1!XcscN3_0CIDYgA2Gg{%nvBV>6Sv#` zp^Ft}D4r4m%_WX;)nkdmafkOt)$(RUa0OZu5OTalFT}XQY+w&|BUWG zm-Iy^pxX;Gr4G8$es{(vyovY*=l|V?{&$f$E}Mhf8TxM<-;t)}ZVm&W0V$s50#!;f z^5Dh(1KyKwzh%uxIDRsR4?u-#_<irfJ7s2Hus;q?}NKppm%HXg2Z-X z)Oo0)uxF^f=SYOi@Mqd;J@{id{*sW86Mg}GC0FS^F>n-G9Xc2Krmb<*MoZZ8eDX`N z*~>s;t*SGH80hO!BfOlPyDDVUFx{xVJGvyiwe>8$*t5=$VYHKFR!7M^bsFF_f@cdn0 zlp8@5@yhsz*>ufb(qx7LjZ1_*P;r{)gZSx7m4LDjbg8Uj%>Q*3wBLW<6?@<5Xrov4 zstxMEopM+v&IiPsnhhblDK@YRL|lV3DDce)40OnW?|kF=?(9d>im}|f5B9+H$6R>F zd;+RL0iC-UjKr$AxdzaIZLYmNJ~0=DY@@q%nJI;6l_V&5-J*=Cz#(oa>d)=20>q_K`=zM&2kKZC;uw5aCpt2qGP9VegN-8Y=LEinG{x*_d>;F} zveTuQ=7taVnxRz)P`eQ}lv;DUAT)j!6ZN>i4PwE(WIHEb9e=^ka z)K{ex&g{QRLa6;=f1|_?1h_v)r{98lhe{_b{UdpuN@{+>=@o+oo&#KMkDW>YA$wQH zH{hv#4dfl6fLlZF5ZQOtDtn74oC+Y$=}rR0jFQWCgR&ILBZ5sq@!6o@5{5t-@?J|E ziqJl@1g`fb`%eV5inzfRSO8DRmvP|4O-%d+x0g98-wMwj-Sw&pUp3%439I3kvN=B* zq4v;c4^Y#oS(t=g(*5o$_GfowcD!RK@{;^z1x&3j5m1gWO|87ZezSP^K)t+9s`{o5 zMDhX?Y^HkM_(D8}O#+paPwlGKc$B%f*3GTF+H&ztZ>kijfq2*^626|hMKD-^Fq^ii zv7kl{(E$&rDw9PFtSBsKCb+?xzf!oSvQrB0Gx#Wmbd2;hVImaI+=Lz(7C7=)`Yn)5 z=9+vh&jIS68#BrsRK3f&RCHVF_1Hbz8IY4|r=_bqQMxz?x&~?{?Yg;=!`~1JcgX>Y zz`$Y;_Qi4#j3GZD|0Ehl-o6PG&LAJQdu>5_9{sy@{wakaV1hn`LYnY+hnng@hI%MB`@yCcV5fJ)a?vmMp#gGs1+I(9tH2`n{4-F{?n z$|@^BvQ{ly zapg~wTmdizLioe%x*gaqcw`>In#6LAz2HxcoFFUx&e+};4?S3ohT1r3E%11k-adQ! zU_qpH!2AH%s%{CS%=>jjsf;j@=Rj8~J~I`7d&a<(;`99;aK?qDWu@U^-vpzFu!sG$ zTW8IhQ(puc-0`5VY0W`OO*XT7^R*A-NfXW=dx1s(j9c_Gt>)~&^jZ5EMGWr+V2%Hc z#~+-W_R}JBr(27owff5g28;g>CXT7otZ{Z&e_sI&HWk27`s~8{J;Mk_kH++S1{7M7 zgl)NI5+1#-*r+^B99pVOU=p`(xOH=^PgdH2-?w&-nSAUOFJR+1Q1@8=v8{xV`#}IS z;mm*~=H>K}(8hQ;ulmRNZu*BNEL^%3Py|-}agUjzW=AU%W!{}Nlc!jw7!{)iL)?A* zmE>+au&3N4^qFTn{n){IbBbX8c+4}A1oq%=*Jk1Om01OFrD!(;NucV*Ew(&GzFAl!8- zlmd%{+Vw}A!DH~JWc+~nY`szx^{$iJlTozW5qWd|Ymq3q`LhZ@kdlj@N~qh*05+`t zOe=6$QDpM9g?r1b-uLEd3HIiwb6cDp7*wmYa9S>WN|Q?sJiG?}u;!iFMiaUQ|Fv_d zs0h@R#BFk>N1Ya*A^f-ViaAs_U23K&lc`A8dz0zzsBmo1fUiSz^}Ay^bz&tK|F*lW zp_A}XN`B*^DwT@mAp4aj2ZWnT#j1b42+6Iz8guM~8W>EJa@44z+0E#oAzALYph)f56cx5Zk%Z`8g+Z$oNHb9kc&`+KZ2+K_LRx+pZTc3oE ziad`}CGg4KJAAmB`!S>Ncv7NvqNw+LYrw2nYWo}z19wg@9z6kp&K#% z2}bKIDw9qfWz=4Mi52|)fln|;u09!7i5vB)m={flRY7ELV^p;uZ81Tf6&0PaYP;E=Z z#}Z_^Kp)&o=%;(TJZl$}E*1S%Fo1JUs7Bf;B4d@}%Cy~TPY(l6wQ9tb+zai*wV_lFkyXcKXmh*XW@ens3uyZF)zUgh#M&ZdA*Rlo#G0gS_6-7eAE5AzQ0j6(McTY z=JfTI-EId>Zkud{wLuh`HFFWv673r9(_0_;rbw9le#<@fZ-Y7NZ}kKvOrUm$^;Zm$ zQWpbgatJy|Q;zF&KYJcO9|24#^caryEA-FT4F;cJTW02Vfqy;BoCKj$^>lAhcj>;{ zcI7sofw9&dv&v1js9(*ez##gA*(LqxNsONgPKE6zwd2tSRmT^qC#2mFRIR-jXtwXE zadG;IJ$I<^=M2E5k42sZTCHCqO1c0kcX-iBVoo@6{$aaonQY`u{RZ6RPvn+u9cks> zPN?LX&d4Ujp?5xBib6=)hxvaxx%PM{vp-xrGP!Hyl1s#hh(U^2MXZ`gsg+E~ZH1UM zMT@p6LgTucN~RPuNwuO_<&sKLQf%WExfG*|OUkXHY<}PK4n>#!?C0k%pZA^jocBHF ze9!q_p63AuD^b?JLk@I&yj=j8&~lxoq6(= zqLW9h=vcX!oNH15%dYD8bgH@9K*SV0wO+qeK}hA1=$T#>4p&mkMG!)J@*snBf}lo~ zVEgKusqDz7vR@(?S>j`&qC_PxN(Ipw#mpgXgDCiqw8hf}1)1Uo*`5SlR1+$pVqoJ{ znYfiW92w67n4K)DiF_#2A%e;oQPMzZ#Mg&xayLJbT$nxy^!yJO8EK1MOSW88B_r^6 zQg`WkOPgAYOn@n&qJLzg4(3kW4Qk)+rqZoa2PlRJ2>8o-ld-Y(GU;EUmlTxbt8_RJ z)%H4q?_-t#{mzqHGx;)%wEp5}*!ue3*9PG~B1krH&0@pe^mJd1*F&vRp`;x>rMC?2 z{lx>KxBeu3O_C15fF@18w2^t@UsN?4j{y;-`zx*@=H74wj|(%~+E zw_;#^m8TjAC%aqC#?r>Xf(}5^Pe6dAW2F}*NP3?hlZD4t!ABy!4A-BS<_HV1quogC z^H0DjAvRB$MFF#ZS>02I-R$gRkKR4h2LMCEuE z6sy-vh0%nyKgeP`XnF$Y$^|^9>+Ig9EGju4!4U(`@DsmW+&(%mj9BK4`oRjnp2PF2 zuJGY?T&BO(zg^^M07{WNfokpwPm50WQY%h8-x7ko;6!349Zv^hMnacKCbd)SGr~9f zh?awv`v6WR`P>l^Qjy^TL5}l=E@tGF#qdX$b>3C^2jt81dBX`CA9#gSb4^YjOH!!` zPF-8TpPyFecdhv`B49V!#(N8g(W1|r<5F=x$cBS@DX$KGuG(Cm2cR?7~69`~jSoEsMS4tLgjuhJaz-|OF)B7tb?ge8=SZ40} z9|t1og`J^7LIjtJKe?slQZVH)Cw#Al1dIWdhq>8SIR_CFY;;Llf+Yj2uAzG$HX4DB z*qN@}z>{4dKsUOt;Kk!3xK>he#wEm1pbMkc?nykIGREouh4XqaAg}uN zG1nYrU40ncbawax4EhW{L_-##{qg|hjL8)Jy@f~EO8KuY)mMqFYq@Xhf2j6Zc5QEz zSYq^UNQ-c+VhCYN7ld2lEHM^|ZQ~{-qW~VDk;&Sb62}bkEsYe99rq1<9cYg-sRtgf zP;EBL-D0Sy_gLQ&z&}r7O@ezEj;^8Vj%Ev3`vs#hjDJebSrck=ImAL}Y<1hXD~2EZ z!`uF1n@Yulk2gegkx)um4VS08-srb50ztq~57AV{%7e@rXmty9`75WR7Pm69?>*#g zJ?@%rGj^SwbQJJ6PQX0gpW}I$O8y;Lfw9Z_zQSn}pLTHb4N13Fe?S9`*{s>Z4ZhHu zTrPqpyzWhX;)!K603l{bpOrW^f8_8yO5zE1_n#VbT?&YFv~8s3oZUTbU4mfJ&ep|3 z+Qo@|#p(k9@1Yxn4tibFnt65yRT0vOzPGz?ox#&JEce)VY@@+1b&3-m*x@l6^|(qy zyT(>yAc@zmWv_~Q>OU(~2XbOh3!Mm*$;p;)=C2#9jkBUUBmrX8XG`O!TPNNXj+SMd z-jw154BLIS_xz`6vQyTbGt0)1+$@imi&vAP24ZNx zef@+qz7kSXh;Gxmg2sz9Je|2)xHWPViWCfhINuw;@$vl*8jzxk_Cm_#5q&C1`i7BV9{y^{bQ7UNxgJO*lpF_6KEk

7 zS<-yYUJZp;o~AQ~wgOmKKcwG{2KBJ}Xa0Oq#ZrSLl=?g6 zMLcV{H|CrJU(G3hoQy?_l>lF?D7-&jt4d>Y6Ar+_a}bg@bBU8_y%|PPXSD(&M@~#9 zFSlo*^x0jv6ZCq*t?=I)S-GGVfCbb54Y7u8iO+INxe4LLv!6o{a;tVX1o6@+>lAEv zm2Czv`3QEfiDT>R)AQE^1s0!bp1!EXbSkZblnz=Hz@9S~V$$RmaPDMqc=5Ra8BQ={ zBkng!#&o)@>-+npsm3XQ67+hLs%EyGUM;cwawEMWi>Q6i2#I}AbeQRrJ6z#&@Q&6qlWDCHgANxyjwLuY3*oZl(OmAuuZ-1^I zU(nZ-dm1tD4KE=^Im##cJjy#$2*jR@MRy7x5!BZ*R?iPDA8@9r#fPa3lzp?WjFyYn z->>zy+0;@03UE9;U^5r>a36|O4UkMh_V~%arDe-5;0Y3`IYl&}Qh#%eR}q=Q)2(dU zK~&xy=2tQ8jDW*Lp(fb2?G8H8zqa=OWI_Bhl&A5Xwd~om?D04Ei3zK!4=6#W(O0|D z^t08efO^vP=>EE;Mv0%dI{vEIR4@Pz7wgWqh7~)RlWaSKsuR?{JUIVb$F%RPMSibz zUXa=4&dhbr*ja|{N&nx7FZ)B$bhqtA)v{5vH-4v$6Zq#3(nyp7YPO?|mcyS!t)I`S zfC;$_w;ihZx4wH10YoGgRTzNt*L}4d;aWh;V%U%NylP%9=t5jGVNP`^CPs$uE`@mk z>COW@Qftc(z!`~y3PC{>}s4{^k%>(8I**+9OvRzPMvjnS%(1R-q26plJp7*Dm!Bcf z9n2RUy0uM)H@j0F1JzqMi}oq~){1ygDUw|d=RwjW_&RU_HC{TN`Q?7{=Bt2`f&XWH zm}_kPFa&mt)SIfs=2u#`jfUE*1 zU525&!SQi_8&~T{?p|Ju#;^-f5H=t5i2VkUa*1==zY2K!kW0X)0ZDGgHn?XF4^REy z{y^3Uls?SI_7`IzGAbZ1HNKvpd2SXDUw;&fN55!tqLrzy0F8!&U(XRFErY6#Aeh+cQy43>wc*6&+`57@4VVA5KY>t+dTPEaT%% zrU%wa>svx-%2x?`Hqzncw~ms|QXjpYq0Iv^2%))jbMnvW$(=Ek^*!iDw|S#9S$xWk zII3SCb|V7Rg-{>OR|2ve=P-|MxIb`*>UR`%W8xk^0C@_~PiNv^W+r08F3ez`QQDuI^K0av-N$0?fYVy@Y zDirEcoQ_kNcGEPEo{e}I{3Q&Rb*EnrVOCXX`S_7d+_1O$^oa)*mSm-$S09an56KY? zs7&36IIMSeuB+S_wriDQ2mXlFEWhQhA^KRO%Ft-XJuZQ%Yb+)dBV51p_q%Z{2W~yH zg#T`!El(5zK1JoR1-EmNWQgm!*<{#k HZV~?j;7FEj literal 25306 zcma(3Wk8f&*9Hs&f`F(D4bokbN;eE$A}uhaqNE@ojUq@l2nf<$14y@YsEBk43?V7q z_3c5u?(2S@?|I+%7cg_~eePI$t>ZY>+5|mNlfQN2&J7e4lv|1l(1$1}XmAu1)Mr@N z!6)T{pYl;q%+eL1Qd+LCjStv0!$Y+f`IiO(I_-E`4+KLqK4;RTVOW$Cq7&YILle`j z$NGjw<}n0=Fx?S@&>as-0SPvI^ob2agDo?A_Os}lz*lJ*Yn$~A>`O%-9S^>$Il8#) zT%=fvFbylb4%!UhvoqJ{#B!Q}3{M zzeUoaJR^yk6kw>ce8=rzkQszr1b@O7lUj96HP^x7Wck~Cu891@^M#nTOl;>1*qrY~_J(@J-JtXP%R zC$Mw&k-^|Q9n5+tkM`u!`9=8Gyzhth)FEq1?*{(g+Ta*@g}FX$>!J8i*4wF>(W33Y z_eDVxeTDmNi3IKShDw8Xn7SJ=KXvTQxnwS!r+DZ#Un<7GVd}xlGP-WG?s6GWeHfg+ z>64hL3L^;~y~!qV((}3yccG|1Gn#WIf%T^Z*QRDcOF&DiXvJKi&3Y05ls9CB5Vf9;bT$se;cS9VowRgQ zOv*N9$u_7Z3u+8Ko8*wU)H;qM$2eyr`9{ZDKStEYul;a*ugeR?s=8B{D|467<@|e@jKgx<5usln&*%qs zD^uS#GCqpPNVTq{{A!T8NPRKpqFLph{9;d;1kNOaQvj@JY4~^)POm+*-6hl}JSe7A z+1B`Z;bn9gwkCD54O&KJJ4YBai5W(Sp*+pd`{PINqX6M4^$mn}wLtFq`-y@Bqb2w| zZ%nQM=2iGFkDXq%K{{A}vJidml%84zg@lNF!1I<8R_9E;L-^r7FtMXK?noX)U2o-! zp)~=A*pq9WLBi7k!7~@n-sVldNGN)v&{${lSh?ZgWDOJXp1d%SDuln6T%6+g%i(QE zhxH8S`!G-8uAf;Czb~dKI@Xjak9~>ju!rzX97Y}JG+*j%x2#>_`LhoZI=hQ9C=ETc zIcJf68^azPN8DjG#bif)U&By$@g4Q(t+TR{Si)Os2Tx{729x7PER$@Et35W_L0 zeWnhn%$xVTF1KXF`nOA4IZx1 zzJG^TzpA6Iuulh{$lwS2jdz?}Y}HNbT2{ldoYl!&64;|jUn?iL#BnD-xvU}>7cZwd zJFvgHZBN{K5vUvU0Ye-3mtDkJQVIQ#%oGuurqquZyQkkC8XAMVyY~|kFwkp3e_L225 z^)r{fdyZmg3P*G6L&gG4%z@GT+c&Mw?$$f! zmlFHIc^9WY9Lc27esT`D57u_NpSrl-4?DThyhcO+E3eI5FL=}>ctyB%-&W$H28LIB ze>$_&h6G+W^C=>2%BD3R_X~AmR2x%iQHbtYLdUn)#1UVkQXd2N;&E^My`}+{tuv)b z0(wTT+PU+*hcC-BBDhOQEmLhcJ!OvP(K#un>yRC;_vlW-T@@BRe94Ml zb~8OM`FOKaoL!dl9o|N}GAZ(ab7~B1{D2Knuj7idt(iz1dBG(`o*{s|-fw!gE1aV6 zU|yA)|LyXfPW!majZN8X5s{F-5_Z~5Y?t&rs(9K}-)=OzWVM4F92ISqs?;P`zWu`E z1pV=Y4>rxoCl+jka0#L_nod#)XkxHdgMJD-7VgbWNhr2AmIgg|FAI(OK8I@{Q|1U^Hst;riOVA}lSI0ViF0V`|N~#uq0&>=YqwQ13c?u0{ve z>P-(*X(+9X;ASZ`BW&AT`Iw|0G)^*7nLM<%3L*Jo_tZ64^tJ$Bg4>b3#$-=eQ>q?nuT{_bC$45YoP ze&0B&`b_hyO7n{yrWYj}vW?RzUy(p1{^txBWuup8VZq>Jy5R8#ix5rfJzr|kgLL^? zB7uXPYFTvRO)66|eG(e8jg6QMdl+G`ZglQ#dX>Lx-LSj;v$*Tg-6iSm-e?=ec>9}u z$MWq&8g7j+E{$Cg*VZ>G*x5dVhH{CUA5L|``Au2fm|)DR?-?)(G=(-Bb{&Vt`xbg) z_KomUu|nFq*RG8Gf8e};%yLbDeZPHyC%bZECRt#YkFBO*;q}$Nq8(*^S>}pQITC!KwS-u_XDa9_|*yrm_ zGgt4$_T?K<{0yH_)4-SG!_3*Kxy8F4JdF&Ac`ZxpgMvS0KZW=&!&kCpJ}>81M?3=E zyZz#B{T-UyhdJM{X%N6&6QMrjkFw$4C*R+&J98Ii^Y~-~Wuq?Ae0I2JmS~5?8p_Rz z@%^U%qOFaG;-1ky80+%V*{Oz!3<=CJzoyB`s4zDFvYuiCpD3$an)6Accwojletz}N zVjr{R~PjzUYF zjqjvD=GVSwrDR1I_y)iFK0a>A1aqcg!b;vuaDUPMx$ZAWJaJF2j&8Q9z`#*D^CEAC z!(roAcqLV8h?b1i2;b1Y{zcUC@x+pim-3L@X5mSR*E=5;`j&zZk8*uREtKj!Gm~~V z<$1;<8}sG^%)@sBNfNc#?q$KtQw_#~dVWO<<+9X;34PFg9B-TAsR8e219IaWMpU zRVBFW=CX=j%G<@~h2_J?uBZCjmJ}LJDotCQl$`K5A%VBu*Jf%Ae!pFFYW}pH6zMBG zqlU}QOv|Fnaq3i7WmtNWh2c`K?4(vE_Lgm#f5{0JXC$3Qhlmi*qs93TqM05G$>*@a zQYSW%ITE+}j;86u^XwB*htj31s6D}lrJ~OcMKK&ok#q&gSiz$SF{8KX?_M2CdBY9f zJbZ!eN9nTi`Th9#y8SE*eX4UI?JpbR&>yt(WwNhMCuXUStf_R$Wr9wlc>3It z?EGsnavgG}C=a_`T(gSM<5ucd&;MD6j{7!}w}@W5)|(GG)lQu+9xghl$~COI#D8`Z z7*7~<({{`KbYpWu;{5kAr%^G z8#cZwd9e4-kx=H2^KQc())BJgi{DUHo`v?8hv*6%m|5YZ7q64HF+j9kR=NDV0lF#LOtI=A z-FDwuP}E45#^8DKne>?CGNyqMPAR9S^p96#v;x54hq1AD97TW7<@Q^?&NT5-r?pGj z_=z6(1}`uDD8$Z^hrx_Q&{a_93CHy<0l@ZQY})PCk0$w!j${M9ytf_&UiTrj7klK7 z1-*Y`fc0~$pU~8H4bfVu4>ZM&T2w*jIp$Sdw?_ya0 zm^q`scCdM_9}8VHq(E>)5HoL0(8FH??C+@AS+Ze&{@L9(VWu^~D-CS*S_mR%|Gv>k z4c)OUBjhpHoCNge-1R0^l=Fv+og5-JzI_sjr6KP|!WdVhX79#I8|Gp}rSsZ|+1b&y zBbm>(M32GFgsES4R-aVNLSUiMb?po$n8ubKMZ^M+3vLAGa2T<`Q)tkFUI(=-`H$=J zVpMaM!&Wr(vVl6L(?*)G==qc0%Y(y=?;k#NJRXgUlqQ@%p;24gzeAg;F-DSMuliQC zOq?1G(ObmJYv$jq{cDx8+W&b^U2W4DMQ9vU>uwac_HT1{aj+nv&)F=XmdHgq?1M88 z4ha0`<*J#`yFu8NFHy!Cr0OwwCGl0@Cqh8x1C^&IRJ3fy6;lk>yEtLaSBF1zH)k>- zrd!J;Xcykj?tNFP!EBrpc6I8*ukk*e6`aj~dlmi9yAtEg@Zoy=*kctzqYm?(LHxE8 z7KI-}^rHn9D*wypLp2&QOl)X>xK=gK71^D+Ms@5heRMZBB*GHg&j@dn3`9inymO!z z*uc@y3#Duq-*bkPEvLdZvjz8u^OtA%0Lq+6=sm`*n{AlvsxA<2q*S7-SJtAiRbh9j zSJ9dp3;98eHwKt@bYFK}ntXoD20SSP{n_r)myS@fdkehnh4`gbWI*TG_qjau32Q?i z;zlcCc9S8cl!L`O2|bObxKft1Itufrj*oUn%vFgG0bm+{?{2=7YOhr2NCM25(aPl| zK=-_w(knCf<29Z@3-o{wK*CB%Uk z{*s{6)DkDqK5Y7*?pa_!2LtvmdU=;g%F0Kd9Xz+^t3x*xXcT>C#gUXPOu6p&S#=uE zo{Y8=QLB2;aNU@Bb$0o%K&>Z&Ql?oMZX@&YpMDqs%}1MMFkeHFL7g(1@!%R`YZBtfJ=( zJ#5{*rwI_u73Pkr8XuS04DZ*H-=$Ui*6iB$(UlPzK*AV=R$-3Vt2y0~o}(_1YQ1$H zBESL*+T6-u(0Jvd0>IM)@G$-3?UOG8Gl2xmYRkiZ;Jc{*`cBwpj9Vj10ng!JUEfQa z|2CyCLuWW;p>7OTTSzn%b%F-~At|X#L|AP5TJ4LU?WzLP4A*Z{u%!509NVlxqKvBT zK8)4BgrE6z1QTUE8_Yq3a5Y7)@!O2i9Bj_mS4udq#)i(?{b&$MhcG3gzBr0zkrZJf zgfp-#8#hEnyBby5BrXr-#~d9tUvk*hE)o}B%zk>4;kejqwl(`H1J>wn_Q@B+vDRtj zyV;Khw~R-XRy#gGFlAT=aw)#rLwxvA$5w>TnGC0H@gr@|txuSaWNp_{ToKr{p>t>< zBwWNv{I<~>@}Z=(Pd+D@ZoC09EcQJh(fSdLBKEtZ=rbf=qh+{kOz^HgDz{J^DAeVu zEqS^5!>lKoaeRV(d!o#|E9;3WO=ABm)N6Ze(!96-S(00$2%@OrbeVuhm*#h^!6+9) z^)++VDq&wiqk!d!%EGbo$01LL3*w4WMcv9PKahu0OO)sy_r9F*Vy?2E;XK%w%!S{$ zC2_X(=4hvnYjLM~#+$wAWR<v#qwQkvI1&zXpbp3j{|>DQ}_ULr5bF;TXx}A&!rk=lf`YrACX9*FjAr}3Jr;IR`Yu%o&Y%l|v%simJmS5g8 zy6-KUP7bOgNGZfU$9ltG1+G^-8?+ER(9BjMs!a_hV(;Ckf4RvSZ|u3<;kPDndGLNcE$ZL?p*Mi}!%ruw3~< zkP)Iw0D+U%p)7q)oM(Y;eQfRpX&?5MBN<)# zi=SWP+R)c$9WD#B3mq-wTfDh%wlt+?E5`?4oS*hRR_Xlq(X!ufZ9A{YwC!z%Vhq!c z&)&6!lhN82mSkSnNduCST%A|p`BZImOezT`!*d^>7o~Xo5?T{vqj8yT{cmU09jMEA zMuWzqLp;$3cCg)w z!?iFLp_t6{C_=QR+wK)vZ=LfR)9wOdSLM9T{6a45PLKGM^Qh5yJG6 zc<`{r()2U?&Zb#v2r);r?RG}e$<3{$B>UhduhU1D1kwu0AO*#c><4Se2~HBtBlQV( z$bp0iLwrbaSDB9}u!bxgVt$U~Hy^k&#zsx3sN=j1T$iWzVu{AI5%-LXnaGq=TD$SRwAbhgfzq0Y#C6BjRcE;KgS9L zO6m1l_kNL0QHNn|-Jp15Z+-hG|J8q;>-otVyn}DlkUld#2b*)9z{%txwx`;3o%3Ql z@#EguC@w+iBZO>&)SK%)gtiIEZB5gNj*yS4YN!uCq|qt04}>ea{0YclNg1H2HfW3S z&1c!4V@q8&9yPkza48ujuQEKsrGahFqueW?RfYmY#25AUnJ>;MI_2zk7j^u{I@*kS z+ev;_!!oglIi?L9o!`w;4>tCCSS1Sxw4gyX6FkRcf4no;ckBWG!p39}rg`rija#Pb zZ_K-ETq%Lq0(Dj9L*jF3Bsb>6RS68on3qvVbzbQYM@o?94@3%~wGs~KWhrYef>xDP z_mFc)M9yJ2yr=(97`ooUt{BLvr@H8i!wDg|SREBw)wn_8EWz=dDOv$oG47t}H5V1o z^$Ut?pYH_Z-IXLfh?1wm10bZLT-n5vz4K$nhY7XRWV9?{DcRWBFaCczmV4CBZkJWp zVj3jZW1ROqe3yzu9v-6UB^?G`ld?k$-~Z%qU4Eq&-jeo*X_`_io-=qLu_7rUy2bq$bO2X%d8*D2~A2@e{vBO4@)%O5@`b)yCkOS3p3%PU)p~ z1(ozYj~C;klHc+bfe|B!C(y8OG?gxbbwGfrk0(m_GdMKMtWXR%p#knpeTDF6rx3HsY?8R7K?%hl6{%cC8 z3}6-yO^4MXRtH2o_BJ?nA?gz6_b2QAK#^YOgQ_F}dt%G}lsIQhTq?q~Q8-Didg{AN zpVN(Mv%wryv&)O~5pR{r4zdXzjc>#X4<0nQgUtn#I`1zstbG^^jd8_5LcTK`sbGQW zPp_|GLO%#QuYYOx#lUGtf`aQeNoju7%-`M~Gmq#w>6f@P{EEc~@B|X!@mO?2w$FC^ zL&)uFr0zfcCRwEaQSKn!Zo1BF`CEF1N+Pe>+DNfuG7;5>dD(3Jk578MRwg?r|L0J= zTpS7DC>jIc+yqzua91{djJiFMtxQrIn)j^CtYcwjW3sw0j~%+@vDwJXrdx7Xb{Swz zbKBFS`G^oIG57ALzp88}+uLv@?gF;J-Ze)h*kdv1a;a%sQ5C5Uw^=*Zu@Ew31|8uA*-lm!Yjayj z&T#(v79Ipl%GVb$3_?n~K!dP*=y5W??fV4Y$H7f(^bYuNkHcR?0@F@0<^@b55ICi< zQ)FMa+Jg)z_BOzpeLR&fmOe-A7wQy8qY=?L9c|5xR3VXxhW;xS8-SY@2^&$&4KM-0 zp|3u1ap)?fj9Hch)>(%1(!Z_qEs1r)DvS8E zK&SY9g1A?mjr{g|N-h_b42-|Wgq}#=XZaf~YY9#H54WF`Ue4>UUHwa;RVZQvC~q-n zHgxQ0-g~W&mDxCVKTq2XIa6T+t+D^MZVSuQl|kP^!@ofIM90L#+BJNGUy6U3M1i)d+8jJX=$$ez|C)mLBmtP=S-2^;fkJV|Mhv3&3HMT zag%4c$q4f+w312AJtu3!M`mh^Iir}aN43*GB-*N*hiel34+;;#K(z}~J> zMqJygkxehRg&%yf-gfO9Ciru?9&JX^7=9z%UmElvN+P5@eHtJ#!4rfV z>fi@ah(*sw+~HGd(uin2N{uXy`kw={pcIq6i+!&LG!?JFz$YYx{{Z2zX>Mddvpt#{ z0p{oQ@A+w6Jx-7h9;ZS+o^0Cp*R~kVQayJRy@+Vt-U2)_@cLiQ49Uq@p5idD9ITIL z{>Seji8mp#7mD5A!v!uHP?7&KTHu9|JPPbDIz~q!lCmQmFp?Jkx4&Zkr?WpZ06z4e z*Z#*1BT4#yI~p;hFpz=VE0dJpjvRR8Kb>7gsO?+A?nq(*mHKbfzE1g{rn3qEv*|x8 z88sSyakM?}9@hb&Qoe3>+-B3Mn$1j;(fVYyx-rom@1wZ@iZ0u(aLVzEmv5f=Buc_2 zd9b@&H21z8cA{99 zD0z|vM819eqvigSXFrj={mGa2BbS0Mz=u>jPY`m!rcS7* zd@j!sE4iuf`erKK0rPaVA26ED^)lfG{|p#?Z5$&SzYSawK5xjDW!(*FJ! z0zI5U49W@(S8QOTSpuAuHpS~e|M(I_7Yl}wum5*w87k0L4y6!!c;9+NdHf&w8X=e5lw!_a>#VRxGQg+>J`}u5iUN{-@t)2C@_hc&tb6>VLx(fqb9c znrlNUGf2sXmrlfX;=X=_w|4$RS*MK&ZLK0b4ZE2}kC(M)KpSE*v|nw$svVir3#Af! zv_4g<8Ovo1^N#2YBR4Q3Xd}04+}EiUwfsuK12}nY=u@lV0`21Sm9GA0J~`rZ9`T$; zkM0`P4Y{s=mxYbPVHak?h*Uc_s)*}Uv(+#gE5nTUscj)u2E>f?{GqujUflXjbF*Qmxyv5&fV<}9 zYcG+T7?NH;zkYa3NM<7Fho96hc9^{HwSge&0%G_6JSMH}L~6de%eIxU3#oVH?Va!8 ziZ$sR5PUVHCtJwQe2EWt-4k~}K*8oM1EvhGJR%E3vghu{4MfHu60G(;vgGDoiR2VY@LEwyw_=0*6amCpg>BC}})!*$OowfSo z^zoDiwLi<)&$+l3<4P&v-H>qqS#*&HI5Qk&L1k@9PUa%(1Vyk$;Uw4L2x_{#tJUtd z0de2r!^#+~Qqun(_GkxtXRJ9?nf0*ql%2n zErLGZ{+6%FJWy;PpaB#^Rvl14CUzpXfR85wh0$W+>9=2OjSuFk$J^3gQGNP|qe-AD zvYOEz*)^ZLkUfU(9RP@0dJ>l;s9FIm#xn(^c73PvH0Z}MEuKCwBZ$}>-WkZ0Ulbf! z`jQlK`m0|3fG7d!2voctwo(lk`jBK@P@}Ek87F*3w4wZ60*Sgrl~9C zC-q?Q`a#5U$!%WLD8lyrWFp?hPjfTgtFIB8gC~| zpbdJfIx|I1?zaaKxK~0i#k-%sQn_(};7@E8hMhE>qs?HFVLe1m#N;L?$;nkESpkky z9O*cH3cBc$gKoYM_iw1V#C9p)Ls^1THp(+#91>0fzZV?0MJfz0Rw|B5uASG1=I` zLn-e`G>jYF`S#ix1e6Td!bhnuwlL?x&{!+p-XzP=Wwrp49xsW_zXIL&XnuA|7nRn3 zU>yBZd7rIWsWR{L6B`Y&&szHcO?UhC1I|;q%2Q8(9*K5OR4R0WnO_o}=u$?IP3mOA z8m@m&nHDYY;F%SU$|>J)dVj)@B&Hde8Sy^#mewgI(K+hKfg-NF2v@qgKzM;rY7C>2<4- zyL;Q=BEKLJVh0IDT^2W8Kl6bwCPXj-2-HGs^^qFAd^q8k_k17G3-RHkDX+X|>(?gH z0{8#&tg6j{%z$Cs$fwakX;{GHJ-LET&*!B7umZWra4G~I;tAj}W+03_RGEw7ZBIb^ zC`Fquj;@jaFguI8!ki>F@L(=Vs1)ZRRQ2*?wE5Ab#pB08z>$+qvN@$&6?p7^5s(G? ztcBmhAd^=Ym-Ez@k$rimz%Yw!Rc0_xzobeu6TT^+se6Wr(72`CQUqK5xZc%QVP9zr z!r}sNMm9*o#Q1cDkuxJ{S+j^AUpP)iU0@v@TX9aG_G!y@!Gm<)v!)zd)OPlqZH%XH z@UQz;m`Cd)dFqxw#}(i4;z7e8IUS9t!8!=PPT z*C=k|F++Wt-!fppsiYv%IngC75z^g^(hcO21t5zOIi*!C%Up||=$$grPWVWPk%63% z#waqw@?+(67SAWc^qSR#&Z}-4FzUr}VVK%!XIX0%0h3DUi0LH2bs^xe^>x1l%USHZ zafjcAB{N^lW)a%K;6(o48Y`n zq`utVXGav1h$E?n0&hUDwJsjCJV1Zd57i-yCo9PO9 zM;ep=YO9r09eT$7l^{czS~Ckr$={0wrBffFdM2{jpy~ai`C^}|tLny}_r5Te&K|k% z%_#E*{fPBz5LcJdi$u#5hcodp`vQbEC0DLjp)IW-PXh{`WuRLnHB?U{!l4L+GZN)@ zccaEpxt~-URNL`7-W+)5W4fm9a}pDpw>pVd?}`D0E(pN$aRY{DvV?a|`>g-5tUn5f z+_!M5R(!e#ueXzhk+9}7o>fFm4q8T<_fH9oK*u^f3vVy#G-|HFrnoIx7j(_{YzwuO zqvnDEE7?2*Csj<4C|QZJ87I67%9zi9iv1%3EHB?n1-zEkz{OYae~CVSc@I9}fr?PO z7}DSWhkyMeL;c}USlGm|thX_%6M|C7b>=1)sgzUDK%CMC25DE$AeBb-%x_ zxHunXIuS43UzBD(A+Wm6l|9EOqH-;X)#5#6%q)_5J;*0ev_gtu-3;;(p1HWSC^ZQm&nWPriII1 zZo&$0_iXaa6FL@{E!};krIt`f7=xELp2Ce`1(d4A^86oKmYBY`HRM%dg2^iPoD-Z- z&L1N9s=ZMMe+pGP7w9G&WVfKBL$cj39{E3;Q5W6za|PV)@ifTT6mOz)^Lzru z`#HiQY%7<*u`e*7Ub*L)+84RWStyeNc2i^c?zQ_kf?g^4ws!k1&x}n#9#4qr(YJxa zTd%EB9|`zeoblG-04GlWtML$KZIpnWNg1<;RBZlY3R9;&z*^$)q+Tr?f^_h^pq>5u zjF8#{v9;prAJH0J;AFr@grP({C4*WK`e}Q@Vk#150f$$miicmKC) z!Y%BMbzjBY3NvCc7lhjLW+3PztAq4$AyF0b5Rk`N)w3`7_{JIO1~0m_iUV+|-wjSl zucHR)1dc+_(bQ5ct*i?GS*)MBuGuQQp=?S5KiD8VX+q6uq`dz$(iIs)K)fk(e~_gR zWpf!2$34NLi2HBnAtw*A@>*nG7$Pp~kzBXuw)tV9Xr%V;gQ@~Sz))Kzo&f)yp`I%4 zc$^s_9?eB7G@P`$E=l3C{7s5;p2IUxq9I7a`^=T+*>?v02$Cck7{NYHf_Q&^v1Vgy z1(!&zEKKzjR%sQt|8NYjI@wIQup(ztk`Pn;L`jHCvcbr8j~r}f2;S&Dewu=??WvwL z%L)aey=(KCJjKuTc)WBCPxCDrv090-Q2!_&cyjVS|H^S|)VtUoE0CM36XA+(y{ZAS zTNXq{%7SqIzCooG_zlf;Mi6t-HZc-%<+7zG{1$id@pSqsBhdcOt@Q86f^B zE_Fy5d(g0>a59wmXwI)&Z~}N|J=%||EyO76s1mS9J~R`X7u$%A;!9LsZPD|+K}RyY zSpY;V3?lmF+9@^E_q{+K-d4;=p@J&mq@ZcD#Hikaa0~|b(S1dIdv(GwX}?w7fX43# z6G()&gin$i_P#5d?JW`xt809Z6fxQSLD7Uk8N4UM%4Wvvo(1fNclh%tDHKBaiwGX9<`rd`nel$maKj7q|+^tZ6EIizb7(BI}Fs8-XYGDBqI+6GQITm0+E zA`eKX= zdGCfSOxj~mSZlBki6On7_VzOh)CtH^T=6_mDeTRu5t04jCd$rRnLqZ7KE3D{V}5&! zoGG5jt{iq`i{r;~)cWopC33c!QY1)M6qYLJkYU)F>F(u=BLaB_skVA27-$qKbq+Q& zD?u5oROjs1#C!51Qm%BvWRey5T$`wSinp9!L)ry3pe9jlw<2~>4}5@p&`mZ6$=2Sj znBT=A;k^6jLIM~MsN(?pWLRe8RR3pH{!I?gs?347{z@7PfyduzBaLo$lQ|>rU|-nv zZg?JT)u+rekgC=ik@?J+G=L@)5yg`Rif=N&iOm3r^I@R0==?prPyRH}3W8IaW{@1@ zJjB${ud>l6yVYT=^6j-Pt)4xgOV*HU*aoL$IN)Y zx|jo;+JG7Tj!AGRdF_pM{Mp+&~}?1XAw&eE49 zC>qZec&^)hgt=B?X!;Pkb3P)dwWVfy{zKIzbTcp)y(evFm(B{;Kqt)(RNs}XOUlpW zl0W={2a17z%dlIk%h=f05}$N^ei|hLp$@FdiQaDw;c)%3xmMvtDpes0ba=#Kym8g) zR$DG8Y1(;QXYt_JZF>QQiw6x$?ekCo$(`wm8nKsUUa59l(e#3Nf95sUF+hNSAK<6_ zWdP)PteytAP>9ixYWBEC6>wxl&y0pQHL@OZaW5WeI|u3%bl0X-k5+t;?k`UId_e=_ zc}MDNxDBXg&*$4p4euRMuZc-;UFaUajheX0g=%ARf9C&uT+ZXSV{9`?rQa&}!mNxFJ$z^XtwbtkLolTqm z?bE->FS(br7b7ins!DYM4xIRoQLu> zb_D6(V{4qvT%OPT9ZO}%sJi$uH29HrK)<$zH59rXotfX?l5(MHYropn;I`|yaO*nk z1$vALGGqFCV_ZIE^m6$eD<2b|PE=YKyHw0CXHH5%sv<*=K65nN^G?ddt_XQYQMRT` zj>J}zpy|%s)=>O25E&-|gfobCj>{;#YLX0W+pDoSW3j0Mpv-rUuv^-+Ysk_BAD-iF z5^OH!fwA?TJ^>vE>CU;rQzFv_I)bmN2X+SNcXGamXGVBmyeY+C-cGdfHqPDHkVL)~ zh=kTbJSM%9I1c&tn5eeB#W>sVpZeH0fGTE}Lr{qFPD8h0A*;PmlhXu{kg4`HP?_i$q)oA=0lxRx_jS4Yafp?-@T1ri8> zO9tuY8n)z|HPi;_hURwE=%_Fn0{l?szHeooxFDtGaNsLYnH!_jbx+{KAtxZCI&^P+=lMF3-P%aAYuLJ)WK2 z#1awc&SYxTtku9caDY8LIK3|-&|CR-h#j1YaD!x>P#7CJ+%c=Oe-v zfV20=Nx|unt0b6n^HX6Dc+GyISVm`s5hDI&^$Sx_#pV?-eKS)^-cV^)Cty$!eO*7FAHANa*Y3@ zlcOzKA;YvwW1#=QDF~a5pG#JprFtO_EDr;PFB=WCKGZ2s?X}V~>6IFwm#dV6W#PCkh0@#`UGamnZasfc|x1lkpX|GN$h zqA%B{7%!z;nBF|2PE<><0sk5zG8O64fkv;cPymX-oac^LEK@^HPcH`WOMB8b>2DzW zgJC1{rg$I;=|{G{}X#=d)hbZpT2LjMjx^Y{fXii8B0@ z$toWf@X9)W1fL!YEEA(Y_X^JW^$ZY1vpH0lWA*!7S|-(0I^0wK^N>r%|9og(=<=TK zP@YE;VJS$r-?>XDGT{4j@G2Sp_f0&0%;mzMN?TV~AN^EA))Zgj*VSrPvgPb*hC3&=HE(1#2O6x^N^*V4m zPGovNsvt80tt*0hw6J`8Sl2j++WSZf{*~q1C0Fy=LwGoaL+Sj~I^Td$=Ls@f4G(9q zvz4NzGhxdQ{-#w;&k&5%YM!qxXSM-^)Ev}wbp&zPm$OZLXHf?L6wkpVSltijw-s-2n05)5eFgmz5|)(YC;`qoxI6X(>G(yKF!)ML6H(!&on4CucXFWz?C>-m9Wg%N5RWL zs`On+H*8*l3Z^paQO+`O)6Qle$h7h28LnS!96yc%u4p8>-A>@>2IQ0s@b&nJ#O~*N zW`NQ-k{!gw?Z-TQQT~&~q}o3O-aE}%(y-G@AwAsxy~e@3_$5QkTm;_LSqt1zoxz@3 z5CGR#2(KYa6iEOFCe|+0scc_EYV;O;Uq8LUlm+kT05$!xjqdwbHBNJF0kV}=!xly$ zso#MtrZy-le3%{VDXL#)CJXXjxC8%57GEC!Obr2<<)A2f`CyRo52BTMt9RP*(^O>7 z9UQ6Y<;c9s;k-;Xnt1A;1CnrNBorDOc~me(=J;>%_$#VwTgq-6S%ZwIe= z0C1M^AYD2`ugpxSJ(rD;1O40W24qbeeXqdz)N}l6$O13G>Z=XGoq7Tw9#v+*fR2lg zyi7nZ7Ye!e z{5tFD^|2Drkt3OxWGddXq(3=foDOSr?(xDDINvZn-&CNkEFGTmfHcZR%hi#~@E&~G z%5WXU57z8`o`vFkHu1Y`Ck-2;QYLIG1>RPon`0#(1Q;T2CnceRvC}d>4IH+#!x#amu)~3BK z8ETq`-PtJ}N^4~wfEW(tG~14c{0Uuw$k73yuOv(bdD;su)uc*47AZQS}hBqgByI1Xla1f}F3yNk`4h9w7KUiQqhUpra za^<+LI3EyvyJeGw<+51nW3ztP1Pk1FXV0ZYQ0hBso}L}8eoKFYOj;3|9^s%Cj%YS4 zh2xiz+N)vxfpgIFoK%uoTc3tTTTD7)bE9+g3_>(MeMfRQIUk5YE_2xREfHjtSlSI) z`(H&i6}E$$kBntaSYg1bXhItgKl=D6q4mQC@-!twH#$VL^V#!U#VaAVeR#=XhCE9`voS_s2$4#nJ{m*>_AXuZ!a{eK@&LbCY%CK^|XrqSr`!2TEC=1!Ml*5_gR7L2EA1l7*ynMjyOC} zm~;uid;TA@ka0cH$at%3K+_&nX+8QECoC^x(`sB5{Qjx-1BG6+3`*Z}qyAR;0Sqgx z5PMZ<{3ns0IJ@22qBl>1?OZ#u-S*-3LB;8eS4E>j{Dm z2*0NH&;*sOXAJlLOfale4R)?cOEmugAU7g}P@IR_n3kT71Xu0PjD&=?Gv((hv@A&@tzV9!`F=n2*pZmG*>%Ok@I?r>) zVn7QS38%>D{YM=T@{OS*TQFDZ{ah_vNXGl1Fk$=4cnvrEyPh2F zt2$mf^Zu?-@-Cqc@C{n)-LInmZN@cUuuo2{98Tgz+$G(v>l^}ccSw!#yhl!d9LyOV z53kGSPMD_SVTSwIN(X_iPoU$^_<`bz+@mZ#*FU@|am z(3laQ8hs)nAg+!0lNU7qWtbE}m{aau3$cOA8>39)Ttj%V4 zdWz?7I;lW7vgM5W$jlxIV;rnAbVe0~Hn%$iu?^8@si%bWiJmd;ui$(dzjIHCAbg~& zG5^5EnR_6(Y;)oCf8QeYHCXnRa%{6cO=amGtJpQWS;u`7CJY#0N_e3Vp^!M5Vq)*cuO8T4v~U1{5!_Ii;E49>XhVEKcChx4960`fz%${#2LU zQww`cItjm!gIkyfT47#MIOADJ+uZtv^hGox7XfSLADcF|`)AWL~MC$XpyVpu2IT9EYSs7tJ=X;R6f5a$foPyz9`buA`@~ zG!i+nLiH1m&EC{6Dq&=C<8cIuB9brjr)H zb9f0Y9aSw3O0>|1j|n$c5Ju}s7J84M%TXelkIBIp-#@1<0lbr}aV~?J_n+eRKA6RQ zRgt~d2HGw8XcnRCGo8?Nsqxz?Z*c`IDe9^Gmgw<6pf7}l$DC~A0nD!XMh~?;y3GC= zD7-UqbG|I4*W;O=o@J1Amqr3uPE7WczCib}K(nq~i6%>rXRIUl?8IBmOi?5CMVJta zwTdZMR=gnMG;pd9xAJ^7l*T#t3K@us53Z3b^OKz~%>9o@pdguWGcDZN51Mp=A3IH- z&gBjYH&wgxMl2RLqFCpCS&b#I0HnA~1%Ythy}Ra%EaL5IcTtf3`6QtJp)LGyRq*A~ z=+I=60n(2!!w^EpSZQ|w(Bz`>cf|iA6t_Z;fJdbFP@LJ5fAsFHDj`bd zVqcs&3H4L$%ZNDy6Fk@`2FgE=%LIXiVFi$Wc@XLMMG<2m!0R2s|NpN;^*e`zBj{KI z%yukaD(6qx6R+}swh#`q1qzrT1c>=?Af$Dp)K`cqbYj!7;q%JK2Zmo<{j#yVw_V533GkC%jOu=Kr5ZNMp72VcD92fj&Vzr^$9Rfjkh@}URMwgkHq{x? zx%HK$$B?2XT!MD>p^5r8Y*H%gYAi%@rxCPh<_+_~y8dXBZUHttUXuie}0>+7+8bsJKV^02IFMB+ksOa9{%e61FeUh?!?)}CIk?KQ~R zxZEf9ahNgNmCMRsmLFIm0a^ROjFlHJHXN+WZ-k7gapZB{)cvK?7G?w^=CHhN-Doe; z&^}t6C!m^0TKb`AkXku6J=frtx?3p|$r*f`zkZ)GGRKQ0zM#dzyH+GXnWV^%ci6Uo zbg&c*f%d5qBCdTgLUxWHPx|KR&7B{vUcr;4VSn8qW5e;CFT;Fl$gkHhX3`~ix(Q8Y zciKt?-bYTeR0(Q#s*_@2`HkqADY3AIq3%>s?!t0H#$0}k$={l{8o>C*f))UYRSasM z|8yo$KT!doFZT3`u$aQSAP5429QH+-`nPaw` zwozscdaFc|>W-%}-BL*oJQ*4KlmZ~}ecoawna$iCd0#H`{a7pDQ4?@ueb8y&`)zGW zC;9jU7>~tpz)xn)K&}@a0J1`#iUhzI;(Qfd!kFKuWSw~pr%UyF5DSI~4Qt>lm(bdL z3c=KtzB$PpdB?poAc;XAO%f}T8s1XBfU(pii50_52&+s-?Ye6mSI!(PEDs;Vo4d1i zZwEuChZfIOjChUS#5GerR=Ol^O8a<0k~WC7n( z{FZ>cpvJK4y_~Iqzxx(Zbr7^9FIvZ*VG~#hwjN5b!BoN9lSkHXISA&MyeH*6-^@Sv z$Ds&_Kl!>v*ygs!j`C_`W-;>UQrwql5f?Z=7ykb1kc>b6Z(-H2hYk1qvH?CqDo0!A zH%|qRASM=mGua;)9Ghv;D)|8dy$76pmYs%%Psrn-F7mk&9{`;p#u!l`jLDu3y#%s2 z3Sb}<&;#tO+ZF;KUF%0*nZWmkh3^8UCsv$McS!Qe@}~uWB2J3>gmtkxI=*e1F;VUl z{?ql`fXs;K9)~{xn6&3rZ3uO&sOC(lFB0{DTK#a~)ho|Yv6#E{yhl}Jm{dFHTv9gi z$a>TPR5Mgv;`wYDMCYNIvpu*B-U}-dW(Iz&Li(a`5mhIZ^ABzn7As&1LOEYnui`7kDj z8u568b_d$nI=jt4lFmr6 zo?S=?w-jgF4`_M*elN1eZJp<)R%PDxtS+v{fNFty;WZsBry0vKRFw=lV$6) zjfi(|6E`Dmnh3z+*bZ^TCDl3p51oSH5D^ z@o8~@$i<=h5`ney7`K1*RtdH_F|4B(66wn@d5GM_}jskRPb%_WaP3e&lkA^BU4q_NUOY!Tr4V#tr?o5rr<%TijHBkXIIjy?v|npaY} z3m`7Ey6u%$v7wNkE=&Jck~0;&yAqh#xXt!;uqTu!%7>*pE06h}^_r(a9Py&?vc+&Z zqoaGCVJ^q(0Ce~&@Ut>ACWQ9O#d$B08r!X4l0@usEjw|E7_fX`Pp9Pls7C+-q5xr3 zt91?<2f!I>V84b<+I5xl-^04pMs-J%+VLeOr5N>=H0naQ*5>~&bZyO#8Qi~ zfglBZw36@y6GGR5`LskV-tmJAJiifU7kYW2#nCuH;Ye|I;ifC0Dp8!)Cdb)Hj>}}% zTgrnqR!N_?2*@zROyi}+HUxZZ(OhXOcFj(9pr)FT0x`+)9a8qXR;hu4ytucH2%sdA zuX*GZ-AaX~O#50;eYD@`AY7NuuBz@Jh|UBComcZe)jZt^DCS^xEsg&7>ia=FLNJk4 zfwflD9*0KXo;CcV=9O@=BdTjGcpO-sT?dLe-9AyI^!Oa%p2bKA z8mcXExN4JVwaSI}4f5dRW0p_av8`b<7epsTk}pcWX-j(l(l(MKh>6}fyAU2Pwz3>$ z>oW_z+Lq*Ci}+c(SUydL*F9hQHt;4m3xO3mGr1#h89k)BMMP9J%!aRJX!c<}Y#~}M zhFm%F<-=Thb`N>HG2aXPzuxx#4NCQ?+Qq8$$^`Bb4I8ELH91!F>>p?vKaC6ZLt%j< zF9|3?8V37CYJ119Dm)YZ{9DBI`erpw>c z@5xcWrqqj1Gx3~NBCOxboHdq3X=xbR^1(&i<1f_Ib{ z3~ZTYn6bc*5kzv_3BE*BRM2BQH9>=GRACMNu;p?CFcC8y$i|i7cEu4{W?PA^$vH_w z%$TKu#&k;k_$Ka;sb#!0&Yw)jqz+lS;#HlaoEVN4GlC2QBU+;ZUQG0QgAjOrp++0S zyKIn@bdI=VTP?Qemv_rA8n~JrtVlq9SCiD+_B+v|(swN{wD+mfjgn=~gMfDZ4nqzL z+c2<~sgA)JrE!vBYx)G5nUtxiIGd|6E($-_aP2IZ11Qs?ys`pDRjbl5Sj_+FFEsr4 ev4?LP9SjdNKVBIu1ix7^&)j6IaiNiO=zjnK3I}ii diff --git a/docs/images/sequenceDiagramExecute.png b/docs/images/sequenceDiagramExecute.png index 4cad401ed78ee0686966f30077273001547afce4..4e17a0d6b03ed0329bc93fbbcbf5cf20602f30a7 100644 GIT binary patch literal 24622 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 F{{niD9Z~=Q literal 24768 zcmbTe1yqz@+b#~GbPf$tQUgedfC5sI0|G-zi=-eOBHfK33<4rGf^>H`NC-$uNlTYV zNdEWe?|r}b`~K&gb=Gk$mov{i&wh5?_r34?x~^@wnus zK3I7&HkYO8(`Pl9xsQ20i&3zVjG2l>@5NI6C!40`NZ0R2*Qr$};>*(=zkSjyA6*|B zd!{!{POa5Uo)nt+>NH(n&R=UCZH{a7C-M?0KRe!@+AJt(&QCTIuV|!DzS7|CPLI*- z=O0Xp5DxA#YLb@Cqrj=RQuZOuqpzY_X7LGl&dUxn!LctMXDPWAf6dZD`l*lYb(0NK zuT3kNYTSIJ3UT%!Z}W$6)E|yx1Zno!(bgK5HUYZl7ehrDHWGA<@+!Dh=snh%3_m#!K9slX`-s?* z!e+`6>w{#U%=;P-X^Jiek#4R?91aLrUtgZ+@HYL5J3HGd*?L((5hM09Ok}rq+02bj z{OZ)y@YAO!DSb~~Bb**#GX){!v!IVo7Xmk<1P0aCQeUM}(C+^lRo!YlSnk1!7%>T@ z(`L7yDmUM3$K%!1$WhUfxY!S@-zshx6Wwe4ShL8h$6tKeiki+L*PW`#P1Eb4>x-Dd z>y4cBvDrH3BO64HVT0QyctT^Z=_Kv&L5OY5T=n2JPe3siQ&8+C2`5a)z%iI2b$70z zz^KV1&*$y{N34#(MOLu$JviHMasH&G+i{c$ulZpzoEJ>u%jzzUiBXa&vAo zw)vn_n``O56TXx@2J5qXb!%xF+d{P7q;s(+5kMtN$QtX@I`nFXGKG8gN zgmfag)B+Y({_#C!nNSjGg?l*U+01VqNJkFl<)r1)`<$BCW(m9RKTAECwkZjAo1a3u zY?t*|JGOos^}U?*&6A6!*|>O2^hgs7*~sGqyOqSsoY&!(I@3A#yR2DbTC2D~c(bv1`~k zV4Czfov+OD`MpZ%+Cd<^K0yOIFYJW;wf-?C|LXF5YqEIxTTnQpdzi8F0VPuqaZ6Cd zNG#K1CnE>im!qs92$5ZjeDGznsm6l zO0j9-ZMjg7A-deL_tg;HE)A?-eWzbZyg2*FXJH4ePfNU zo$C~9-Y{xgag#`6hll2esZY0_lGJ1Hr^#S5v4}%qn>9FeNsjX1i;)vjvp@2psOG!J zAV23{--du*LWId!!MAXKB79WBki|Wkt3}AHF ziunIe54}ZJzFz+HnyYF;db(Uu;5CN={+RWJmgr*r1ZPy9yGCHxw@9+=BjGuN)ZZ5p zHaxbCQxredW2th-PYc}IU5m7+G!8xy+<6{@B#VW@dNZ__OQyq-2;V137c3F#;ou{_ zwcu5LDirp6GN@M-RtZhL+P=;w!TUbCG1eoYY02|j$euwo`YN4w{Bw@@m;MqtB$PGK zy4(29Xvs#**%eNLBIu!DSeeb}&2X`jbTIW7^eS`|Af9NZE~j zT6%4pqK0PcN*kr>Z>AX%Sy}|Jno6=D%#;Ys=7dig%RbdW96B z^HuroxvU&c%$j==PSpH1kqACr-_cxm{Z(%|<3PxIzc6@Hf}%)0=juehrRAE|b)>_7 zoP_n_Mk_(o}l893_3UJ?b_MLGScb!ek8s7D0o}I`e1EyT|Zs3V^{aR=gS~71n;E=vzWvBgAMnZT8F&@FcU9|YobUW0xAv_$b_6Z< zS8Y$X@wJYvC)HCbRkLfYv&YSeUnY+7NV1%TH#mv3CuX{r!o^pvsf5NX>Io6`k|zOTF>MZvw9Lot72v8dhXBYOg)uw%_xs zXgt;+u6?Eq>nXK686^3-4c?kD&cy?wsvIaQ;Uw{8OTG9!V?9bCnpZ8KhNP*oD_MTg z`EhUaskBl2oM>M0NA}H&FM7L$ZkqxMwj*9xRsB+d4hxKF?=)=Gc6mDRG-91R4mC0TRi;vVt!0?G?Kt+LrQ0D<431mx+owpDePIL9 zOw1Vh?lME?>OF>ZW~k~qZg{xG-YDcsc4aqK7(9Jhx>)~a=6nUud8T8jTPq}^R%$@n zj5inSXcLQw|>pYL0Gwcqn46oU8#KuUQQlC%Khu3 z?^8;2j?2t-Hq;aq;l$Y)D-c$%sRnwl!b7DV*_TsC8OHVtJI>ZEllzA*q!cZBrSl#H z?^jZD5HfHWW z44w~M5BOO|{Y~;ypEaXwV+Q9Lfiq9%aaDKQ$dNZqM3b+rObQ!hO)rHx?F>++Q>n)o z=WZ*5V=hfeug90Ge?ljq+oQvOa5~wcs(zmSD%vL+vo+*Nwc|Uy873I9gfju2Vjd|g z^r4T|*zXbFOFxs zH_e$}b>3Q8{B+y>GO+HN#By#hDeL(5J=k@Oai%TdBdM0|=oY2Hd2nst5_En2X#Glx-e~WeO@_#?>GNMUF8*qWd?hvITjQ+9CxN}XR))2k?2Xm3 z8}{smv7$oFHrtfs!o~M~iCybi&eqD{G|8{GZ+Ra?pY^;0Ua>?X{bCo#*llQZ{hKQLD7> zTqbHaod3Prd2jZd3FbccEOgGb$)nG7Z%rmI$-R@fZ(c>jxJ7*F)9?E16)>D=?-H{2 z5GEK^qv5MVx!1o>?_Hm+xw@pYo{c%e`8;pUI7q#%d6GllqD?Qq?qhHmZ0gywJa|@B z=lP*INzM1-c`I*{_fVtQo>(^60Z`#BIf#LOUA2d|Ekv|x{2&zfxuIw*N=fW-_Dzucj6lN+>RcEq0NOnIax34_cN|jM+EGqJ3(YQuHWAr zXSE`ER!H<1OaIk&@vYBV5+=s_i2V-T7^%xM@An?ue~c4C6m`hR!)&gsDFSE@PI)Wg_8uEMJETNBJbaN!%+QX&ByD zPV-KXPE6s70V0@%P-2V>ysw3g4H(Ynnw}Wtv{|BFY#bl#x;Nwr0ey_5ddBPOh~LGU zR$@rjVCsDLXzEa6_KKomr{L_dNOgn%wjXB222nutrtTSk!r)1LyR{3`r*S*M^9Xr% z*m5++-6}Ooxw507f`ld{{r8=9lWi_PzxA|HnJgQEa*sb7_Mc!MpDqLEpP;8Ff^EC#WuR3& zU&oVO$^@%Enlvbk6}3eYBbAZYEWruz|J&@g=x*wWmV|4Ibcq+k)b zhIU=alrc?JNP-Sc)g3qj2ByMnAwoiD)kLOOtkR0s1d}?gUYXN2UMUfW6{389$9ZOs zHJhqY&X$Oi>pP`c?#5Z88xlI+M6VFW(3fFCUs6$yF;Y-t~W~^-w6JrbVtg(>)asZeK1uc7=4SV&PnP9 zO@W|>_GB~9N9{(p1mS_)1f=G3klJAATrA4HY}5}Gd0qP0e@ocz-ix3q>v` zZ14C6W#|DH@to^%-B*IZoP~pWvOpcg!1qTGbQ3Q zqxJ8S;&v(*cV;ce+%J7OFiYSGnrga%oCs-rBM#W_6R#xb_+p;UeBz2y0CzsbBce%#O75(ro|Ic*@ z>S8!sRiP2Zg|ZaK=q?_^2;pD%}# zX9p6BC|HohSy5GVV(G?IbpELqrUU=h5G>jVxhN{83T(yuQMyZkg+02@WjVG2U$c1r zpWFT4^&FlI0cy_FzR6*b%GN_dm!$>8ec z#o^HA<;i@_@mVy3?*;tP^~K>Pc&cyJ`{JNyGyVD^$LDgVX5Jc(Gkp@u;G-5v$*axa zweNp*4NCOhs^P24J>M;F22g{KH+jA~>Y_BhNslEd^QBHjbmxAR)mNm*3=UJ48We`J z^j4n!YeF+Oj7z6jb7!We=2*QxWxK@pvVi8HQ`R&nB*$GR4Ra1Hhti5XeywN9W;?G9 zZu(=U`xNqmx-vhVnO1 z@1MQwuaPSvgo6)lr|-M|NVe3ISI;-;2ywkCA^%sqWZ6NW&1eP*qtsX5U!NWQDViNo z7{C#jIHgD&Hl^+6^IZ@8&sBRXz46YZRD3ps@ub7Sq5RzYousPk%cvrn&V9i@bM1q$ zeHx9>%cMapW8cfFX@C_uT~9))Xev5+bz=k~)Z1f`LE+fZw8B@{bYu4M5WeC-?E$-n zolhuqBGq>(oZb2W&8q2xV>k7nH$U|aQ&kL1e6^kFs?j?^$kAamxY3ys*A}5@_AyO##*WCmnARM$V=t$RJgQ9!6iyfi;U-HbFjwUqN zQ(fYAA>3r$cMqf{mZOj|oHy!Eh6Bp=wO(Mx%c4*ltrj0|L6i2IbI+p!_?5h3j~*x$ zLZ5ti0Jk7nA_$991ZY_OG{92E0o29zssQ6}OnCPceuqWnCH&q7k?(2Xw8vJ_c)Y4O z$1CE%#gjtMJ8!^5YAE!-Y9*ybSH?hvkVROWHhL8M+PWhpALxF(iy2S>aX7L<3n`%1q3-7sm6!At4{?E-Upq(~A`YKS6&97gty15PrWP1e~dleyk&x5AiB$b;qLgqmW z9Vs7J(3P)4s4^o7xw9CzSpMTFtC{K|qj=m%s*pB!*5*v;>k#3GiuY)3E8*YWHL^$F z+Y~1!_GpUY6dm&Y7)WNWxOYo7Joe5vhYkXB?XKQ4UK5B)k?%DKauI$=nfxdJ`FZTb zo;N>P762_|QmisK{azoue)f9MaZ~@(KC`1#4!@;7aAoI0( z?-RqLWlNbVYj}(E$Ew5Klk|gUQ3DF^b2-w zm`zDj^`VG)(+Ja|jQ2HsW|UC2ms!Aaa4hYG6lfVQ-RJCu#d(t<^8Skvma0LKt#!-y z&8JIvRU4mD@(+h3j3XhPmW%DddbPm)at9wQ;~$}1^FnyuOM@O3e*_B+B0aj4w^bD- zV^#g&(2kS;Bt-}XdO5{+S6!mO(w0J26p*Xe=w5cV5J^#Bkj?lj>Q2oHGxjLa4O?#`STdctHkEO-P4Khf)ZJZ0%xXRV0XpUXTlU7xM1 zpn2f%Oa-A_W0=TeIJOwdK+g#~<)IO_yIY}1K*B2Wcf6!1Sejl38^StyoWP}%55Plx zPmZI59)XgAilXV1##;@jY6ZNh(uD`y@Z^4|` zhch>mOy7Jh0b!o5&bupu+=IUXg_0kwe|-$FUy)Y^ABgrI|1SOT83kFpeKWyw1p&SQ zAeO7)BVUB)3uA0@7`M_`mLb`|bM;D!g7%1{E53Vd<@Lt1ugSdVj-s|6&)2e!ecCIdi(yF&a3M^sj~7k(Gy3(HXce25*-4^Ng0jznTnR zY*!3vPa1g^4Lodb+PaMfUkHVE%ebbf{i= zi~?KJ*4Ld%!~0aT{e>TMBd6EyW2v+|9@mtnm-RZkF5bGnE)d87=xwP@{9 z1ec2q&a(@2L#tEYrOt2>qKZ1Ojb?DwK);4h6QVaBbkn+i2Yy(bXphDNrxA54e9vbR zFz5+(vY#>>TtVS+H>D5PB(8Pw)TmDBQ-o}3PG=!`+)x-9tNk}*U@w}Jq<%!44Z}r! z_bFlh^mLU?4%QbYne*+67!g2mjDwB0*y79k?2~9nYVMBJTU+4m9vdM{k3-h0g849) zAgq;`^=>=){lg{35)tbD4!6S0oo*&}HH?Qp|qK&lWzN=7x%7{)NO;C0Qe%sp3Ik0PfrdcD1Zj{Ab0_KikXes*!`2Rm^z@?_Q&Ptc%t+r zDXoW6Xy?4f&5ilX_sgZjM2!@WTbZd%hQGE6IDTIt65IFl;aMx~ARMK4@;*O~_S)ws zjKVw7P<@o0DD%y}<P2=bq)=;YyJC!^&=obx0+uOiJxYi zft2`2oLTrOJY0V$A=E#XZkN=)ZaJZ!DWP5!Jiv5 z+YxtG42p26BK9c*i2QrjO2eluWN=hS_D?&eWm_q-A3Fb7!GCVcc$&Z#jtpW@uGO{( zk5YGZ&7`<7$S^jJr>x_UIak_6Jn_W<`}Av=r|i3a_8$UCE!~xqRh;~>{7HgPSW6)5 ztyqIvgIfE#)pu&4J5VgU1*b)~hYlEtsLA9?m0lN`c`2}y9%4?0CXQD>r|f4+Tl;H7 zsY-Hba)PU*5o!OK4=$~=l@UldG6N_^Lhi!WFvzk0gA6Ar$~%L+vN(-bXIqQ3~R>cd9dip#_*rMXhR;B^6sm_1w{3YByjwq%4cF`<+4Y zHma>q3VxQlF`BcrD?)n_5kQjHA57b_-Ql&2^jh`n51v`&!ZP5QbyLD2#UE~$zJ<<6 zZ$*-MPZ*~i9UlC--GE&DHStY-#4sm5B>Tnar&Ug0W*D)M%VL{7QTq-gJJHxj7vzfi zB1Dp!j-!i-&fkPMU}%$&{^-Y@%H|<0a=*~)*&J<$vqMcaA-YVRv;B^%e{s>zS=QnhPE!8x}r`!IZyszCt zOmB9~C6Rqmo}XQ0F$^T4l(cbmgd4X6Zh*J)tH5E{j&m!gRY5R(Lu)jtz+LFwi62gj z)xMc^GC6=YtaHE$j{_FzHos`mCGE5xM=RmuRlG$c%xEW4`I)iVDgnLn{XQP$nv5IbVrV?TwuUV(WsLqaQWtryr@w0D2iBNQ^PP@vl zau4C{uF{klms|9BEXbp$Hpn0zHRV&ule^9Fz>#@Mxh7q{41RbhP>LtG-W29r`Le8! zX9?eMsCd`vS){s}aG@bn%7h1#;Q|z^&j(aEHX6@eiYV1B3Ljh4BhlX#3O}L^$yn76 z_-Sh}w_iMj4TZU8LUl8cvclMUyr-VCjy*3N!7$}P7mmr(CbWA~P+SkQ7oH2UdY#D{Y@9?)8l`izJ*7cFFZR?|&N*-aGxTW;t+2{X zHB_n+j(#H%D)r34S;%@!VLsz?#{**Q844B{a1-T*nYHXhqY>eI;dn$@5BtKvT6 zG7Y*5enSSee4-_qGoup5-|VZ>Z<8|2mD-cN6~kbQRz`^K480 zKj~Jj{QLVako~k;77bi98OmYFu*J=gSKe}x@O(U3ML$|xsTCR))sJ|>^%5(UZpsUO z-xLBq#XU}9qDSK@MBd=KCDszO%i>%pT|K)|q>9UIG}z!Xktkw0PKoDh3A)cpGJ}DMd36Jl zfQqXc$C~8U>P)SNm_a&;8e&r#en-~-%3G7ADx#1$j<}>6nyGXQ=-G)9ez|~m>S{X0 z8}A9WqzODq=DclXddKMq43Ias!DuO+GLdF_ET@^l?~IsGjidX-X4Yh=*UI!BQKQS| z@sP2q-|wp2E)V%vyRv?v&0mW=*E2&m`Li>M4Mqhc5Bf5A#xhRoQ4L2==*2>({e@6ZTQ>JKE`w(Us^+G*(DYbQYK3Am zep7wY$o0o6*%$XPy!biF*9oE(x%a%n}!T0aS*Eo$~# z<0Dwt^E@WWoCTWbGI%8hg2-1}*IF$*4mp#wW3b4TF1H;eUhGM0W50;ei4!x6Qbbng z&_$>Rs~mGC%1Jqf4aE>^Wk>6EKM zpiPP`r~U@}PQUE`uPOhq+O#+Ft9Xv(4W$EqrG-hhrdk{@cL(B%lz|SUWP}uz1twxE z&qJ4xQI_LR2gjb{4F;&3{3#mpa6zlDTuqW) zBTBhHKh=tW=+VcBpXK^Q_t6T3z(`mpHICF7{ge=Vw&dqZq}m8mpraTU;#qH=1qE1D zs#0D$o#vV1xzk&6X^N!;7CdUxxZIr=p-4@WfV4L~9Zu!#!rz`VMr(mR-zI9l(q>Yn zCXR0zS6d-F3=*q4zKr7=7EX}n>R;*yCDqm?q*6gPX8X7WdX0#ym<7ikyR-H_?oML) zllc8vudf7J3SIawO||q9r7{>%LIhT_&m=ULKx?Jx`SOYHACZ#_Yz~vZkP+$&0;8$t zb$l6xlkjs&Dm%TBmr|E0>yeS-&)9!ugXCEUKrx=aY#k{|`}^S1eHg~BHp9BpwF zd?E7lGxIo*72OdgRTnC6hq4>tI5L?QPJ9l67U@;N@V@diY{%tRy;3-iC70tkfGJSj z>$Z;8jEvjJw;9O_zv4>VU;|k=?#Co|)+}Ps{6coJxjGkYJD=H+kt<3XKrGV#WbNwg zf35=C%?0;9{imm6;p+YGxKYU62b|*B1puXfnXzEUps0(VQ7&(Bzq`g*lM*y;OaLTU zM&I4yJ&w1NXY4^~`+DX{yAZ~AX7H;swHjvK91CL3Z-@nawK0jE*$%S7b0}IB5*;6T z_0{BC5}4wwr+*6!#Z;)tCBxmGxmrilOUi4~B|KdwnJzA-t~-CrjVu)eJ{da%t6Um- z-w20;?5``ZS0T+Z9+0Ge#?AcZ&dP%O&()(pR~f+7F>n

XPxn@0?U#kGZvW+}$6 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 Awg3PC From 55ec940afffa3e30a07ac0273e0218d91b91b4c6 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sun, 10 Apr 2022 10:45:18 +0800 Subject: [PATCH 222/229] Minor edit to sequence diagram --- docs/images/sequenceDiagram1.png | Bin 24402 -> 26062 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/images/sequenceDiagram1.png b/docs/images/sequenceDiagram1.png index 02d7471087c8bf5341871696e582386d14bdc1fd..1554233c32eb29f816c92c691fb1bbf6687e7f32 100644 GIT binary patch literal 26062 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 HZV~?j;7FEj From afdf5e2a5c79926e6407007691756ca94b8c1b8c Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sun, 10 Apr 2022 10:48:24 +0800 Subject: [PATCH 223/229] More edit to sequence diagram execute screenshot --- docs/images/sequenceDiagramExecute.png | Bin 24622 -> 24754 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/images/sequenceDiagramExecute.png b/docs/images/sequenceDiagramExecute.png index 4e17a0d6b03ed0329bc93fbbcbf5cf20602f30a7..097903833450f0deb63060a4af72816d419e9233 100644 GIT binary patch literal 24754 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 F{{niD9Z~=Q From 2a67c2d1df524be7bcb8512ebefd6d1890bd20f3 Mon Sep 17 00:00:00 2001 From: yuhaochua Date: Sun, 10 Apr 2022 10:49:40 +0800 Subject: [PATCH 224/229] Update visual paradigm files --- docs/diagrams/.EquipmentManager.vpp.lck | 0 docs/diagrams/EquipmentManager.vpp | Bin 896000 -> 896000 bytes docs/diagrams/EquipmentManager.vpp.bak_004d | Bin 0 -> 205824 bytes docs/diagrams/EquipmentManager.vpp.bak_005d | Bin 0 -> 216064 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/diagrams/.EquipmentManager.vpp.lck create mode 100644 docs/diagrams/EquipmentManager.vpp.bak_004d create mode 100644 docs/diagrams/EquipmentManager.vpp.bak_005d diff --git a/docs/diagrams/.EquipmentManager.vpp.lck b/docs/diagrams/.EquipmentManager.vpp.lck new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/diagrams/EquipmentManager.vpp b/docs/diagrams/EquipmentManager.vpp index fc95fb6d04f43dc6512ca6399ef6dc71946d25ef..2b8286067789dbab5c5068babcccd490f75ef976 100644 GIT binary patch delta 51154 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

  • qIAN4fCVb8e3O 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 J5)Blz{68j8jQRio delta 59165 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 n=}P$g*_)UjtqU#_7qor7xccj+P|s?Rdm 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 diff --git a/docs/diagrams/EquipmentManager.vpp.bak_004d b/docs/diagrams/EquipmentManager.vpp.bak_004d new file mode 100644 index 0000000000000000000000000000000000000000..063cb6374cd9142c601d1aa534798eeba74ce211 GIT binary patch literal 205824 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

    qe-yw36f=Dmuq_s;YCCOSe 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 literal 0 HcmV?d00001 From 4ba8bf1f46a8c0cec8624504d2f40931f1382dbe Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sun, 10 Apr 2022 10:57:03 +0800 Subject: [PATCH 225/229] Transfer new user stories as planned futures into UserGuide.md --- docs/DeveloperGuide.md | 3 ++- docs/UserGuide.md | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 14b52e88e6..26610360b0 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -185,8 +185,9 @@ Further, maintaining a record of the equipment is a time-consuming task given th | v2.0 | conscientious logs chief | save the state of the equipment list | come back to a saved version of my work later on | | v2.0 | conscientious logs chief | delete equipment | remove decommissioned equipment from the application | | v2.1 | forgetful logs chief | search for equipment | be able to find equipment by its attributes | -| v3.0 | forward-planning logs chief | filter equipment purchased before a certain date | conduct more regular inspections on them | +| v3.0 | forward-planning logs chief | filter equipment by date and cost range | conduct more regular checks on expensive or old equipment | | v3.0 | busy logs chief | mark equipment to be faulty/working | filter and send the faulty ones for repair | +| v3.0 | forgetful logs chief | add comments to equipment | take note of any other information relating to my equipment | | v3.0 | logs chief supporting multiple events | ensure that equipment can be earmarked for an associated event | my equipment will not be double-booked and have scheduling conflicts | diff --git a/docs/UserGuide.md b/docs/UserGuide.md index c5170bb3c3..80adb12c66 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -217,6 +217,19 @@ Output: Bye, See you again! ``` +## Planned Features (Coming Soon!) + +In v3.0, we will add support to: +1. Filter equipment by range for: + * Date + * Cost +2. Introduce additional fields to + * Mark equipment as faulty/working + * Add comment for equipment +3. Implement a booking system + * Purpose: equipment can be earmarked for an associated event to avoid scheduling conflicts from double-booking + + ## FAQ **Q**: How do I transfer my data to another computer? From c162645551e485a8ab2d6f713ab247cfab02cd00 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sun, 10 Apr 2022 11:18:04 +0800 Subject: [PATCH 226/229] Update UserGuide and PPP to reflect v2.1 features --- docs/UserGuide.md | 2 +- docs/team/Bryan-BC.md | 2 +- docs/team/shunyao643.md | 2 +- docs/team/yuhaochua.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 80adb12c66..ba2b0e1992 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -2,7 +2,7 @@ ## Overview -EquipmentManager is a Command Line Interface application to help with keeping track of equipment details (e.g. current user, quantity, cost, warranty duration, purchase date) for an AV club. It provides a clean and fast way to manage the inventory as compared to “traditional” methods such as an Excel spreadsheet. +EquipmentManager is a Command Line Interface application to help with keeping track of equipment details (serial number, name, quantity, cost, vendor, purchase date) for an AV club. It provides a clean and fast way to manage the inventory as compared to “traditional” methods such as an Excel spreadsheet. ## Quick Start diff --git a/docs/team/Bryan-BC.md b/docs/team/Bryan-BC.md index 9db3627ee9..709a99a3a3 100644 --- a/docs/team/Bryan-BC.md +++ b/docs/team/Bryan-BC.md @@ -1,7 +1,7 @@ # Bryan Christopher - Project Portfolio Page ## Overview -EquipmentManager is a Command Line Interface application to help with keeping track of equipment details (e.g. current user, quantity, cost, warranty duration, purchase date) for an AV club. It provides a clean and fast way to manage the inventory as compared to “traditional” methods such as an Excel spreadsheet. +EquipmentManager is a Command Line Interface application to help with keeping track of equipment details (serial number, name, quantity, cost, vendor, purchase date) for an AV club. It provides a clean and fast way to manage the inventory as compared to “traditional” methods such as an Excel spreadsheet. ## Summary of Contributions Besides reviewing pull requests and participating in discussions during meetings, below are the main contributions made to the project: diff --git a/docs/team/shunyao643.md b/docs/team/shunyao643.md index f7d85869ad..41dd102218 100644 --- a/docs/team/shunyao643.md +++ b/docs/team/shunyao643.md @@ -1,7 +1,7 @@ # Bai Shun Yao - Project Portfolio Page ## Overview -EquipmentManager is a Command Line Interface application to help with keeping track of equipment details (e.g. current user, quantity, cost, warranty duration, purchase date) for an AV club. It provides a clean and fast way to manage the inventory as compared to “traditional” methods such as an Excel spreadsheet. +EquipmentManager is a Command Line Interface application to help with keeping track of equipment details (serial number, name, quantity, cost, vendor, purchase date) for an AV club. It provides a clean and fast way to manage the inventory as compared to “traditional” methods such as an Excel spreadsheet. ## Summary of Contributions diff --git a/docs/team/yuhaochua.md b/docs/team/yuhaochua.md index bb1b40e863..f4bdc4715d 100644 --- a/docs/team/yuhaochua.md +++ b/docs/team/yuhaochua.md @@ -1,7 +1,7 @@ # Yu Hao - Project Portfolio Page ## Overview -EquipmentManager is a Command Line Interface application to help with keeping track of equipment details (e.g. current user, quantity, cost, warranty duration, purchase date) for an AV club. It provides a clean and fast way to manage the inventory as compared to “traditional” methods such as an Excel spreadsheet. +EquipmentManager is a Command Line Interface application to help with keeping track of equipment details (serial number, name, quantity, cost, vendor, purchase date) for an AV club. It provides a clean and fast way to manage the inventory as compared to “traditional” methods such as an Excel spreadsheet. ## Summary of Contributions From d0c05405c5c9221026c0c58886d94d2f90a9b5de Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Sun, 10 Apr 2022 11:56:14 +0800 Subject: [PATCH 227/229] Add more informative error for $ parsing --- src/main/java/seedu/parser/Parser.java | 2 +- src/test/java/seedu/parser/ParserTest.java | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 8e26fa84bd..e8b4bb17f9 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -42,7 +42,7 @@ public class Parser { "(?:[sntcSNTC]|[pP][fF]|[pP][dD])" // non-capturing group for argument tag + "\\/" // argument delimiter + "`+" // backticks to enclose string - + "[\\w\\s\\-\\.]+" // actual argument value + + "[\\w\\s\\-\\.\\$]+" // actual argument value + "`+"; // backticks to enclose string /** * Extracts first n-1 tags for debugging and assumes that the last tag contains the whole string, refer to: diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index 485869ace6..af6423b0e3 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -3,6 +3,7 @@ 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; @@ -249,4 +250,12 @@ void parseCommand_updateCommandIncorrectDateFormat_exceptionCaught() { 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 From 6fcd2ade83aa7e13ea14b53b7821c9b931987f30 Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Sun, 10 Apr 2022 12:02:17 +0800 Subject: [PATCH 228/229] Change file name to bryan-bc.md --- docs/AboutUs.md | 2 +- docs/team/{Bryan-BC.md => bryan-bc.md} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename docs/team/{Bryan-BC.md => bryan-bc.md} (100%) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index a5417beac9..398f6401a6 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -3,7 +3,7 @@ | Display | Name | Github Profile | Portfolio | |-----------------------------------------------------|:-----------------:|:---------------------------------------:|:-------------------------------:| -| ![](https://via.placeholder.com/100.png?text=Photo) | Bryan Christopher | [Github](https://github.com/Bryan-BC) | [Portfolio](team/Bryan-BC.md) | +| ![](https://via.placeholder.com/100.png?text=Photo) | Bryan Christopher | [Github](https://github.com/Bryan-BC) | [Portfolio](team/bryan-bc.md) | | ![](https://via.placeholder.com/100.png?text=Photo) | Bai Shun Yao | [Github](https://github.com/shunyao643) | [Portfolio](team/shunyao643.md) | | ![](https://via.placeholder.com/100.png?text=Photo) | Yu Hao | [Github](https://github.com/yuhaochua) | [Portfolio](team/yuhaochua.md) | diff --git a/docs/team/Bryan-BC.md b/docs/team/bryan-bc.md similarity index 100% rename from docs/team/Bryan-BC.md rename to docs/team/bryan-bc.md From dad297a6fc2ca7a39e337318400c0c55cc8bce6c Mon Sep 17 00:00:00 2001 From: Bryan-BC Date: Sun, 10 Apr 2022 13:30:33 +0800 Subject: [PATCH 229/229] Add README in tp/docs --- docs/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index bbcc99c1e7..2de8393f3d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,7 @@ -# Duke +# EquipmentManager + +EquipmentManager is a Command Line Interface application to help with keeping track of equipment details (serial number, name, quantity, cost, vendor, purchase date) for an AV club. It provides a clean and fast way to manage the inventory as compared to “traditional” methods such as an Excel spreadsheet. -{Give product intro here} Useful links: * [User Guide](UserGuide.md)

  • LIrx)ESWXPTJ}+yIP)q@wm68g6zb2}M(XG5 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

    5. purchasedDate : String representation for now, possibility for future support + * + * @param args String to be split into substrings + * @return ArrayList of arguments + * @throws IncompleteCommandException if no match found + * @deprecated Use extractArguments as it is more robust in conjunction with subclasses of ModificationCommand + */ + @Deprecated + protected ArrayList prepareAdd(String args) throws IncompleteCommandException { + final Matcher matcher = ADD_COMMAND_FORMAT.matcher(args.trim()); + // validate arg string format + int matchCount = matcher.groupCount(); + if (!matcher.matches()) { + throw new IncompleteCommandException("Add command values are incomplete or missing!"); + } + ArrayList results = new ArrayList<>(); + for (int i = 1; i <= matchCount; i++) { + String result = matcher.group(i); + if (hasSlashDelimiter(result)) { + throw new IncompleteCommandException("Use of '/' for purposes other than delimiter is forbidden!"); + } + results.add(result); + } + return results; + } + + @Deprecated + private static boolean hasSlashDelimiter(String argument) { + return argument.contains("/"); + } + + + } From 5fe725558c01f1b512690aa22923cec4b17ae69b Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Mon, 4 Apr 2022 22:54:19 +0800 Subject: [PATCH 115/229] Complete refactoring of internal references from View command to Check command --- src/main/java/seedu/parser/Parser.java | 2 +- src/test/java/seedu/parser/ParserTest.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index 33852f7817..a7bde7eb29 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -181,7 +181,7 @@ public ArrayList splitCommandTerm(String userInput) throws IncompleteCom protected ArrayList prepareCheck(String args) throws IncompleteCommandException { final Matcher matcher = CHECK_COMMAND_FORMAT.matcher(args.trim()); if (!matcher.matches()) { - throw new IncompleteCommandException("View command values are incomplete or missing!"); + throw new IncompleteCommandException("Check command values are incomplete or missing!"); } return new ArrayList<>(Collections.singleton(matcher.group("itemName"))); } diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java index d961e964e3..5bdc5d89f8 100644 --- a/src/test/java/seedu/parser/ParserTest.java +++ b/src/test/java/seedu/parser/ParserTest.java @@ -134,7 +134,7 @@ void prepareAdd_argumentIncludesSlashB_exceptionThrown() { } @Test - void prepareView_viewStringWithSpaces_success() throws IncompleteCommandException { + void prepareCheck_viewStringWithSpaces_success() throws IncompleteCommandException { ArrayList expectedResult = new ArrayList<>( Arrays.asList("Speaker B") ); @@ -144,7 +144,7 @@ void prepareView_viewStringWithSpaces_success() throws IncompleteCommandExceptio } @Test - void prepareView_wrongArgumentTag_exceptionThrown() { + void prepareCheck_wrongArgumentTag_exceptionThrown() { ArrayList expectedResult = new ArrayList<>( Arrays.asList("Speaker B") ); @@ -154,7 +154,7 @@ void prepareView_wrongArgumentTag_exceptionThrown() { assertEquals(expectedResult, actualResult); fail(); } catch (IncompleteCommandException e) { - assertEquals("View command values are incomplete or missing!", e.getMessage()); + assertEquals("Check command values are incomplete or missing!", e.getMessage()); } } From e2a590824c42db2ad1adc358afbcb54e29d11311 Mon Sep 17 00:00:00 2001 From: shunyao643 <63784032+shunyao643@users.noreply.github.com> Date: Mon, 4 Apr 2022 22:55:13 +0800 Subject: [PATCH 116/229] Improve documentation for modification regex --- src/main/java/seedu/parser/Parser.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java index a7bde7eb29..76d98fe2bb 100644 --- a/src/main/java/seedu/parser/Parser.java +++ b/src/main/java/seedu/parser/Parser.java @@ -33,7 +33,9 @@ public class Parser { public static final Pattern CHECK_COMMAND_FORMAT = Pattern.compile("[Nn]/(?.+)\\s*"); public static final Pattern DELETE_COMMAND_FORMAT = Pattern.compile("[Ss]/(?.+)\\s*"); public static final Pattern TYPE_ENUM_FORMAT = Pattern.compile("[Tt]/(?\\w+)\\s*"); - // ARGUMENT_FORMAT extracts first n-1 tags, for debugging: https://regex101.com/r/7rho4H/1 + /** + * Extracts first n-1 tags for debugging and assumes that the last tag contains the whole string, refer to: + * Regex101 for demo.*/ public static final Pattern MODIFICATION_ARGUMENT_FORMAT = Pattern.compile( "((?:[sntcSNTC]|[pP][fF]|[pP][dD])" // argument tag + "\\/" // argument delimiter @@ -41,7 +43,10 @@ public class Parser { + "\\s+" // argument space before next delimiter + "(?=[sntcSNTC]|[pP][fF]|[pP][dD])" // next delimiter ); - // ARGUMENT_TRAILING_FORMAT extracts last tag + /** + * Extracts last tag for debugging. + * + *