diff --git a/docs/UserGuide.md b/docs/UserGuide.md index b0314a43bd4..ea3c2fd4d44 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -73,7 +73,7 @@ Shows a message listing out all the available commands and their purpose. Format: `help` For more information regarding the comamnd formats and examples, press `F1` to open up a help window (as shown in the picture below). -To close the help window, you can simply press `esc` on your keyboard (other methods such as `alt`+`F4` and clicking on +To close the help window, you can simply press `esc` on your keyboard (other methods such as `alt`+`F4` and clicking on the red `X` button on the top right corner of the window also works). ![help message](images/helpMessage.png) @@ -91,13 +91,17 @@ A person can have any number of tags (including 0) Examples: -* `add n/John Doe p/98765432 e/johnd@example.com r/STUDENT a/PGPR c/CS2101` +* `add n/John Doe p/98765432 e/johnd@example.com r/student a/PGPR c/CS2101` * `add n/Betsy Crowe t/friend e/betsycrowe@example.com r/TA a/COM2-0102 c/ST2334` Unlike the `edit` command, `t/` with an empty tag is not supported. If you want to not include any tag, leave out `t/TAG` entirely. Similarly, `p/` without any phone number is not supported, if you want to not specify the phone number, leave out `p/PHONE` entirely. +The allowed roles are `Student`, `TA`, or `Professor`. +The input is case-insensitive, and you can type an unambiguous prefix to specify the role. +For example, you can type `r/s` instead of `r/student` as shown above. + ### Listing all persons : `list` Shows a list of all persons in the address book. diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index 9ff478f450c..6a7aa886817 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -27,6 +27,8 @@ public class ParserUtil { public static final String MESSAGE_INVALID_INDEX = "Index is not a non-zero unsigned integer."; public static final String MESSAGE_DUPLICATE_INDEX = "There is a duplicate Index listed."; + public static final String MESSAGE_ROLE_CONSTRAINTS = + "Roles should be either 'STUDENT', 'TA', or 'PROFESSOR', or an unambiguous prefix of it."; /** * Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be @@ -168,18 +170,20 @@ public static Course parseCourse(String course) throws ParseException { } /** - * Parses a {@code String role} into a {@code Role}. + * Parses a {@code String role} from user input into a {@code Role}. * Leading and trailing whitespaces will be trimmed. + * Allows specifying a role case-insensitively, and matching by an unambiguous prefix. * * @throws ParseException if the given {@code role} is invalid. */ public static Role parseRole(String role) throws ParseException { requireNonNull(role); - String trimmedRole = role.trim(); - if (!Role.isValidRole(trimmedRole)) { - throw new ParseException(Role.MESSAGE_CONSTRAINTS); + List matchedRoles = ParserUtil.filterByPrefix(role.trim().toUpperCase(), Role.getAllRoles()); + if (matchedRoles.size() == 1) { + return Role.valueOf(matchedRoles.get(0)); + } else { + throw new ParseException(MESSAGE_ROLE_CONSTRAINTS); } - return Role.valueOf(trimmedRole); } /** diff --git a/src/main/java/seedu/address/model/person/Role.java b/src/main/java/seedu/address/model/person/Role.java index 0a912a1454a..bc58b25fd87 100644 --- a/src/main/java/seedu/address/model/person/Role.java +++ b/src/main/java/seedu/address/model/person/Role.java @@ -1,5 +1,7 @@ package seedu.address.model.person; +import java.util.Arrays; + /** * Represents a Person's role in the address book. * Guarantees: immutable; is valid as declared in {@link #isValidRole(String)} @@ -12,6 +14,13 @@ public enum Role { public static final String MESSAGE_CONSTRAINTS = "Roles should be either 'STUDENT', 'TA', or 'PROFESSOR'."; + /** + * Returns an array of strings containing all roles. + */ + public static String[] getAllRoles() { + return Arrays.stream(Role.values()).map(Role::name).toArray(size -> new String[size]); + } + /** * Returns true if a given string is a valid role. */ diff --git a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java index d142f868fa1..1e0c100a060 100644 --- a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java +++ b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java @@ -20,6 +20,7 @@ import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Phone; +import seedu.address.model.person.Role; import seedu.address.model.tag.Tag; public class ParserUtilTest { @@ -231,6 +232,30 @@ public void parseTags_collectionWithValidTags_returnsTagSet() throws Exception { assertEquals(expectedTagSet, actualTagSet); } + @Test + public void parseRole_null_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> ParserUtil.parseRole(null)); + } + + @Test + public void parseRole_invalidValue_throwsParseException() { + assertThrows(ParseException.class, () -> ParserUtil.parseRole("")); // empty string + assertThrows(ParseException.class, () -> ParserUtil.parseRole(" ")); // spaces only + assertThrows(ParseException.class, () -> ParserUtil.parseRole("STUDENT123")); + assertThrows(ParseException.class, () -> ParserUtil.parseRole("STUDENT-")); + } + + @Test + public void parseRole_validValue_returnsRole() throws Exception { + assertEquals(ParserUtil.parseRole("STUDENT "), Role.STUDENT); + assertEquals(ParserUtil.parseRole(" STUDENT"), Role.STUDENT); + assertEquals(ParserUtil.parseRole("student"), Role.STUDENT); + assertEquals(ParserUtil.parseRole("student"), Role.STUDENT); + assertEquals(ParserUtil.parseRole(" s "), Role.STUDENT); + assertEquals(ParserUtil.parseRole("t"), Role.TA); + assertEquals(ParserUtil.parseRole("pro"), Role.PROFESSOR); + } + @Test public void filterByPrefix_emptyPrefix_returnsFullList() { String[] words = {"Hello", "World", "Bye", "Life"}; diff --git a/src/test/java/seedu/address/model/person/RoleTest.java b/src/test/java/seedu/address/model/person/RoleTest.java new file mode 100644 index 00000000000..c8508acbca1 --- /dev/null +++ b/src/test/java/seedu/address/model/person/RoleTest.java @@ -0,0 +1,80 @@ +package seedu.address.model.person; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.address.testutil.Assert.assertThrows; + +import org.junit.jupiter.api.Test; + +public class RoleTest { + + @Test + public void valueOf_null_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> Role.valueOf(null)); + } + + @Test + public void valueOf_invalidRole_throwsIllegalArgumentException() { + String invalidRole = ""; + assertThrows(IllegalArgumentException.class, () -> Role.valueOf(invalidRole)); + } + + @Test + public void valueOf_validRole_success() { + String validRole = "STUDENT"; + assertEquals(Role.valueOf(validRole), Role.STUDENT); + } + + @Test + public void isValidRole() { + // null role + assertThrows(NullPointerException.class, () -> Role.isValidRole(null)); + + // invalid roles + assertFalse(Role.isValidRole("")); // empty string + assertFalse(Role.isValidRole(" ")); // spaces only + assertFalse(Role.isValidRole("professor")); // non-uppercase + assertFalse(Role.isValidRole("STUDENT ")); // spaces at the end + assertFalse(Role.isValidRole(" STUDENT")); // spaces at the front + assertFalse(Role.isValidRole("STUDENT123")); // numbers within characters + assertFalse(Role.isValidRole("STUDENT-")); // special characters + + // valid roles + assertTrue(Role.isValidRole("STUDENT")); + assertTrue(Role.isValidRole("PROFESSOR")); + assertTrue(Role.isValidRole("TA")); + } + + @Test + public void equals() { + Role role = Role.STUDENT; + + // same values -> returns true + assertTrue(role.equals(Role.STUDENT)); + + // same object -> returns true + assertTrue(role.equals(role)); + + // null -> returns false + assertFalse(role.equals(null)); + + // different types -> returns false + assertFalse(role.equals(5.0f)); + + // different values -> returns false + assertFalse(role.equals(Role.PROFESSOR)); + } + + @Test + public void hashcode() { + Role role = Role.STUDENT; + + // same values -> returns same hash code + assertEquals(role.hashCode(), Role.STUDENT.hashCode()); + + // different values -> returns different hash code + assertNotEquals(role.hashCode(), Role.PROFESSOR.hashCode()); + } +}