diff --git a/doc/UserGuide.md b/doc/UserGuide.md
index d03dfce73..10b2639fc 100644
--- a/doc/UserGuide.md
+++ b/doc/UserGuide.md
@@ -66,6 +66,21 @@ Examples:
`delete 1`
Deletes the 1st person in the results of the `find` command.
+### Changing a person's phone number : `changenum`
+Changes the specified person's phone number from the address book. Irreversible.
+Format: `changenum INDEX NEW_NUMBER`
+
+> Changes the person's phone number at the specified `INDEX`.
+ The index refers to the index number shown in the most recent listing.
+
+Examples:
+* `list`
+ `changenum 2 99997777`
+ Changes the phone number of the 2nd person in the address book to 99997777.
+* `find Betsy`
+ `changenum 1 88886666`
+ Changes the phone number of the 1st person in the results of the `find` command to 88886666.
+
## View non-private details of a person : `view`
Displays the non-private details of the specified person.
Format: `view INDEX`
diff --git a/src/seedu/addressbook/commands/ChangeNumCommand.java b/src/seedu/addressbook/commands/ChangeNumCommand.java
new file mode 100644
index 000000000..5e11e4d5c
--- /dev/null
+++ b/src/seedu/addressbook/commands/ChangeNumCommand.java
@@ -0,0 +1,44 @@
+package seedu.addressbook.commands;
+
+import seedu.addressbook.common.Messages;
+import seedu.addressbook.data.person.Person;
+import seedu.addressbook.data.person.UniquePersonList;
+
+
+/**
+ * Changes the phone number of a person identified using it's last displayed index from the address book.
+ */
+public class ChangeNumCommand extends Command {
+
+ public static final String COMMAND_WORD = "changenum";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Changes the phone number of the person identified by the index number used in the last person listing.\n"
+ + "Parameters: INDEX NEW_NUMBER\n"
+ + "Example: " + COMMAND_WORD + " 1" + " 99997777";
+
+ public static final String MESSAGE_CHANGE_NUMBER_PERSON_SUCCESS = "Changed Person's Number: %1$s";
+
+ private String newNum;
+
+
+ public ChangeNumCommand(int targetVisibleIndex, String num) {
+
+ super(targetVisibleIndex);
+ newNum = num;
+ }
+
+
+ @Override
+ public CommandResult execute() {
+ try {
+ final Person target = (Person)getTargetPerson();
+ target.setPhone(newNum);
+ return new CommandResult(String.format(MESSAGE_CHANGE_NUMBER_PERSON_SUCCESS, target));
+
+ } catch (IndexOutOfBoundsException ie) {
+ return new CommandResult(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+ }
+
+}
diff --git a/src/seedu/addressbook/commands/HelpCommand.java b/src/seedu/addressbook/commands/HelpCommand.java
index ef2ed7d0e..368c77e05 100644
--- a/src/seedu/addressbook/commands/HelpCommand.java
+++ b/src/seedu/addressbook/commands/HelpCommand.java
@@ -13,6 +13,7 @@ public class HelpCommand extends Command {
public static final String MESSAGE_ALL_USAGES = AddCommand.MESSAGE_USAGE
+ "\n" + DeleteCommand.MESSAGE_USAGE
+ + "\n" + ChangeNumCommand.MESSAGE_USAGE
+ "\n" + ClearCommand.MESSAGE_USAGE
+ "\n" + FindCommand.MESSAGE_USAGE
+ "\n" + ListCommand.MESSAGE_USAGE
diff --git a/src/seedu/addressbook/common/Messages.java b/src/seedu/addressbook/common/Messages.java
index 02cfe6155..eefdecd65 100644
--- a/src/seedu/addressbook/common/Messages.java
+++ b/src/seedu/addressbook/common/Messages.java
@@ -7,6 +7,7 @@ public class Messages {
public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s";
public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid";
+ public static final String MESSAGE_INVALID_PHONE_NUMBER = "Person phone numbers should only contain numbers";
public static final String MESSAGE_PERSON_NOT_IN_ADDRESSBOOK = "Person could not be found in address book";
public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!";
public static final String MESSAGE_PROGRAM_LAUNCH_ARGS_USAGE = "Launch command format: " +
diff --git a/src/seedu/addressbook/data/person/Person.java b/src/seedu/addressbook/data/person/Person.java
index cf6211841..c14fc41eb 100644
--- a/src/seedu/addressbook/data/person/Person.java
+++ b/src/seedu/addressbook/data/person/Person.java
@@ -66,6 +66,13 @@ public void setTags(UniqueTagList replacement) {
tags.setTags(replacement);
}
+ /**
+ * Updates the person's phone number to the one in the argument.
+ */
+ public void setPhone(String num) {
+ this.phone.setNum(num);
+ }
+
@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
diff --git a/src/seedu/addressbook/data/person/Phone.java b/src/seedu/addressbook/data/person/Phone.java
index b5a556de4..22c4ad60e 100644
--- a/src/seedu/addressbook/data/person/Phone.java
+++ b/src/seedu/addressbook/data/person/Phone.java
@@ -12,7 +12,7 @@ public class Phone {
public static final String MESSAGE_PHONE_CONSTRAINTS = "Person phone numbers should only contain numbers";
public static final String PHONE_VALIDATION_REGEX = "\\d+";
- public final String value;
+ public String value;
private boolean isPrivate;
/**
@@ -41,6 +41,10 @@ public String toString() {
return value;
}
+ public void setNum(String num) {
+ this.value = num;
+ }
+
@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
diff --git a/src/seedu/addressbook/parser/Parser.java b/src/seedu/addressbook/parser/Parser.java
index 58f4f7e6c..2e263dbb8 100644
--- a/src/seedu/addressbook/parser/Parser.java
+++ b/src/seedu/addressbook/parser/Parser.java
@@ -8,6 +8,8 @@
import java.util.regex.Pattern;
import static seedu.addressbook.common.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.addressbook.common.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX;
+import static seedu.addressbook.common.Messages.MESSAGE_INVALID_PHONE_NUMBER;
/**
* Parses user input.
@@ -26,6 +28,8 @@ public class Parser {
+ " (?p?)a/(?[^/]+)"
+ "(?(?: t/[^/]+)*)"); // variable number of tags
+ public static final Pattern CHANGE_NUMBER_FORMAT =
+ Pattern.compile("(?.+)" + " (?[^/]+)");
/**
* Signals that the user input could not be parsed.
@@ -47,7 +51,7 @@ public static class ParseException extends Exception {
* @param userInput full user input string
* @return the command based on the user input
*/
- public Command parseCommand(String userInput) {
+ public Command parseCommand(String userInput) throws IllegalValueException {
final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
if (!matcher.matches()) {
return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
@@ -62,6 +66,9 @@ public Command parseCommand(String userInput) {
case DeleteCommand.COMMAND_WORD:
return prepareDelete(arguments);
+
+ case ChangeNumCommand.COMMAND_WORD:
+ return prepareChangeNum(arguments);
case ClearCommand.COMMAND_WORD:
return new ClearCommand();
@@ -156,6 +163,43 @@ private Command prepareDelete(String args) {
}
}
+ /**
+ * Checks whether this string only contains digits.
+ *
+ * @param str a string
+ */
+ private void checkIsPureDigitString (String str) throws IllegalValueException {
+ if (!str.matches("[0-9]+")) {
+ throw new IllegalValueException("Person phone numbers should only contain numbers");
+ }
+ }
+
+ /**
+ * Parses arguments in the context of the change num person command.
+ *
+ * @param args full command args string
+ * @return the prepared command
+ */
+ private Command prepareChangeNum(String args) throws IllegalValueException {
+ final Matcher matcher = CHANGE_NUMBER_FORMAT.matcher(args.trim());
+
+ // Validate arg string format
+ if (!matcher.matches()) {
+ return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
+ }
+ String delims = "[ ]+";
+ String[] tokens = args.trim().split(delims);
+
+ try {
+ checkIsPureDigitString(tokens[1]);
+ return new ChangeNumCommand(Integer.parseInt(tokens[0]), tokens[1]);
+ } catch (IllegalValueException ive) {
+ return new IncorrectCommand(MESSAGE_INVALID_PHONE_NUMBER);
+ } catch (NumberFormatException nfe) {
+ return new IncorrectCommand(MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+ }
+
/**
* Parses arguments in the context of the view command.
*
@@ -227,4 +271,4 @@ private Command prepareFind(String args) {
}
-}
\ No newline at end of file
+}
diff --git a/test/java/seedu/addressbook/logic/LogicTest.java b/test/java/seedu/addressbook/logic/LogicTest.java
index 7efa921ca..e9efea295 100644
--- a/test/java/seedu/addressbook/logic/LogicTest.java
+++ b/test/java/seedu/addressbook/logic/LogicTest.java
@@ -391,6 +391,65 @@ public void execute_delete_missingInAddressBook() throws Exception {
threePersons);
}
+ @Test
+ public void execute_changenum_invalidArgsFormat() throws Exception {
+ String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, ChangeNumCommand.MESSAGE_USAGE);
+ assertCommandBehavior("changenum ", expectedMessage);
+ assertCommandBehavior("changenum arg not number", expectedMessage);
+ }
+
+ @Test
+ public void execute_changenum_invalidIndex() throws Exception {
+ assertInvalidIndexBehaviorForCommand("changenum");
+ }
+
+ @Test
+ public void execute_changenum_changesSuccessfully() throws Exception {
+ TestDataHelper helper = new TestDataHelper();
+ Person p1 = helper.generatePerson(1, false);
+ Person p2 = helper.adam();
+ Person p3 = helper.generatePerson(3, true);
+ Person p4 = helper.adam();
+
+ List threePersons = helper.generatePersonList(p1, p2, p3);
+
+ p4.setPhone("99998888");
+ List updatedThreePersons = helper.generatePersonList(p1, p4, p3);
+
+ AddressBook expectedAB = helper.generateAddressBook(updatedThreePersons);
+
+ helper.addToAddressBook(addressBook, threePersons);
+ logic.setLastShownList(threePersons);
+
+ assertCommandBehavior("changenum 2 99998888",
+ String.format(ChangeNumCommand.MESSAGE_CHANGE_NUMBER_PERSON_SUCCESS, p4),
+ expectedAB,
+ false,
+ updatedThreePersons);
+ }
+
+ @Test
+ public void execute_changenum_invalid_index() throws Exception {
+
+ TestDataHelper helper = new TestDataHelper();
+ Person p1 = helper.generatePerson(1, false);
+ Person p2 = helper.generatePerson(2, true);
+ Person p3 = helper.generatePerson(3, true);
+
+ List threePersons = helper.generatePersonList(p1, p2, p3);
+
+ AddressBook expectedAB = helper.generateAddressBook(threePersons);
+
+ helper.addToAddressBook(addressBook, threePersons);
+ logic.setLastShownList(threePersons);
+
+ assertCommandBehavior("changenum 4 99998888",
+ Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX,
+ expectedAB,
+ false,
+ threePersons);
+ }
+
@Test
public void execute_find_invalidArgsFormat() throws Exception {
String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE);
diff --git a/test/java/seedu/addressbook/parser/ParserTest.java b/test/java/seedu/addressbook/parser/ParserTest.java
index f01be613c..e53843b5d 100644
--- a/test/java/seedu/addressbook/parser/ParserTest.java
+++ b/test/java/seedu/addressbook/parser/ParserTest.java
@@ -25,14 +25,14 @@ public void setup() {
}
@Test
- public void emptyInput_returnsIncorrect() {
+ public void emptyInput_returnsIncorrect() throws IllegalValueException {
final String[] emptyInputs = { "", " ", "\n \n" };
final String resultMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE);
parseAndAssertIncorrectWithMessage(resultMessage, emptyInputs);
}
@Test
- public void unknownCommandWord_returnsHelp() {
+ public void unknownCommandWord_returnsHelp() throws IllegalValueException {
final String input = "unknowncommandword arguments arguments";
parseAndAssertCommandType(input, HelpCommand.class);
}
@@ -42,25 +42,25 @@ public void unknownCommandWord_returnsHelp() {
*/
@Test
- public void helpCommand_parsedCorrectly() {
+ public void helpCommand_parsedCorrectly() throws IllegalValueException {
final String input = "help";
parseAndAssertCommandType(input, HelpCommand.class);
}
@Test
- public void clearCommand_parsedCorrectly() {
+ public void clearCommand_parsedCorrectly() throws IllegalValueException {
final String input = "clear";
parseAndAssertCommandType(input, ClearCommand.class);
}
@Test
- public void listCommand_parsedCorrectly() {
+ public void listCommand_parsedCorrectly() throws IllegalValueException {
final String input = "list";
parseAndAssertCommandType(input, ListCommand.class);
}
@Test
- public void exitCommand_parsedCorrectly() {
+ public void exitCommand_parsedCorrectly() throws IllegalValueException {
final String input = "exit";
parseAndAssertCommandType(input, ExitCommand.class);
}
@@ -70,21 +70,21 @@ public void exitCommand_parsedCorrectly() {
*/
@Test
- public void deleteCommand_noArgs() {
+ public void deleteCommand_noArgs() throws IllegalValueException {
final String[] inputs = { "delete", "delete " };
final String resultMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE);
parseAndAssertIncorrectWithMessage(resultMessage, inputs);
}
@Test
- public void deleteCommand_argsIsNotSingleNumber() {
+ public void deleteCommand_argsIsNotSingleNumber() throws IllegalValueException {
final String[] inputs = { "delete notAnumber ", "delete 8*wh12", "delete 1 2 3 4 5" };
final String resultMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE);
parseAndAssertIncorrectWithMessage(resultMessage, inputs);
}
@Test
- public void deleteCommand_numericArg_indexParsedCorrectly() {
+ public void deleteCommand_numericArg_indexParsedCorrectly() throws IllegalValueException {
final int testIndex = 1;
final String input = "delete " + testIndex;
final DeleteCommand result = parseAndAssertCommandType(input, DeleteCommand.class);
@@ -92,21 +92,21 @@ public void deleteCommand_numericArg_indexParsedCorrectly() {
}
@Test
- public void viewCommand_noArgs() {
+ public void viewCommand_noArgs() throws IllegalValueException {
final String[] inputs = { "view", "view " };
final String resultMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, ViewCommand.MESSAGE_USAGE);
parseAndAssertIncorrectWithMessage(resultMessage, inputs);
}
@Test
- public void viewCommand_argsIsNotSingleNumber() {
+ public void viewCommand_argsIsNotSingleNumber() throws IllegalValueException {
final String[] inputs = { "view notAnumber ", "view 8*wh12", "view 1 2 3 4 5" };
final String resultMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, ViewCommand.MESSAGE_USAGE);
parseAndAssertIncorrectWithMessage(resultMessage, inputs);
}
@Test
- public void viewCommand_numericArg_indexParsedCorrectly() {
+ public void viewCommand_numericArg_indexParsedCorrectly() throws IllegalValueException {
final int testIndex = 2;
final String input = "view " + testIndex;
final ViewCommand result = parseAndAssertCommandType(input, ViewCommand.class);
@@ -114,7 +114,7 @@ public void viewCommand_numericArg_indexParsedCorrectly() {
}
@Test
- public void viewAllCommand_noArgs() {
+ public void viewAllCommand_noArgs() throws IllegalValueException {
final String[] inputs = { "viewall", "viewall " };
final String resultMessage =
String.format(MESSAGE_INVALID_COMMAND_FORMAT, ViewAllCommand.MESSAGE_USAGE);
@@ -122,14 +122,14 @@ public void viewAllCommand_noArgs() {
}
@Test
- public void viewAllCommand_argsIsNotSingleNumber() {
+ public void viewAllCommand_argsIsNotSingleNumber() throws IllegalValueException {
final String[] inputs = { "viewall notAnumber ", "viewall 8*wh12", "viewall 1 2 3 4 5" };
final String resultMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, ViewAllCommand.MESSAGE_USAGE);
parseAndAssertIncorrectWithMessage(resultMessage, inputs);
}
@Test
- public void viewAllCommand_numericArg_indexParsedCorrectly() {
+ public void viewAllCommand_numericArg_indexParsedCorrectly() throws IllegalValueException {
final int testIndex = 3;
final String input = "viewall " + testIndex;
final ViewAllCommand result = parseAndAssertCommandType(input, ViewAllCommand.class);
@@ -141,7 +141,7 @@ public void viewAllCommand_numericArg_indexParsedCorrectly() {
*/
@Test
- public void findCommand_invalidArgs() {
+ public void findCommand_invalidArgs() throws IllegalValueException {
// no keywords
final String[] inputs = {
"find",
@@ -153,7 +153,7 @@ public void findCommand_invalidArgs() {
}
@Test
- public void findCommand_validArgs_parsedCorrectly() {
+ public void findCommand_validArgs_parsedCorrectly() throws IllegalValueException {
final String[] keywords = { "key1", "key2", "key3" };
final Set keySet = new HashSet<>(Arrays.asList(keywords));
@@ -164,7 +164,7 @@ public void findCommand_validArgs_parsedCorrectly() {
}
@Test
- public void findCommand_duplicateKeys_parsedCorrectly() {
+ public void findCommand_duplicateKeys_parsedCorrectly() throws IllegalValueException {
final String[] keywords = { "key1", "key2", "key3" };
final Set keySet = new HashSet<>(Arrays.asList(keywords));
@@ -180,7 +180,7 @@ public void findCommand_duplicateKeys_parsedCorrectly() {
*/
@Test
- public void addCommand_invalidArgs() {
+ public void addCommand_invalidArgs() throws IllegalValueException {
final String[] inputs = {
"add",
"add ",
@@ -197,7 +197,7 @@ public void addCommand_invalidArgs() {
}
@Test
- public void addCommand_invalidPersonDataInArgs() {
+ public void addCommand_invalidPersonDataInArgs() throws IllegalValueException {
final String invalidName = "[]\\[;]";
final String validName = Name.EXAMPLE;
final String invalidPhoneArg = "p/not__numbers";
@@ -226,7 +226,7 @@ public void addCommand_invalidPersonDataInArgs() {
}
@Test
- public void addCommand_validPersonData_parsedCorrectly() {
+ public void addCommand_validPersonData_parsedCorrectly() throws IllegalValueException {
final Person testPerson = generateTestPerson();
final String input = convertPersonToAddCommandString(testPerson);
final AddCommand result = parseAndAssertCommandType(input, AddCommand.class);
@@ -279,7 +279,7 @@ private static String convertPersonToAddCommandString(ReadOnlyPerson person) {
/**
* Asserts that parsing the given inputs will return IncorrectCommand with the given feedback message.
*/
- private void parseAndAssertIncorrectWithMessage(String feedbackMessage, String... inputs) {
+ private void parseAndAssertIncorrectWithMessage(String feedbackMessage, String... inputs) throws IllegalValueException {
for (String input : inputs) {
final IncorrectCommand result = parseAndAssertCommandType(input, IncorrectCommand.class);
assertEquals(result.feedbackToUser, feedbackMessage);
@@ -293,7 +293,7 @@ private void parseAndAssertIncorrectWithMessage(String feedbackMessage, String..
* @param expectedCommandClass expected class of returned command
* @return the parsed command object
*/
- private T parseAndAssertCommandType(String input, Class expectedCommandClass) {
+ private T parseAndAssertCommandType(String input, Class expectedCommandClass) throws IllegalValueException {
final Command result = parser.parseCommand(input);
assertTrue(result.getClass().isAssignableFrom(expectedCommandClass));
return (T) result;