diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java index 588a4c2cfaf..16ff6d4251b 100644 --- a/src/main/java/seedu/address/logic/parser/CliSyntax.java +++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java @@ -11,6 +11,7 @@ public class CliSyntax { public static final Prefix PREFIX_EMAIL = new Prefix("e/"); public static final Prefix PREFIX_ADDRESS = new Prefix("a/"); public static final Prefix PREFIX_TAG = new Prefix("t/"); + public static final Prefix PREFIX_LEVEL = new Prefix("level/"); public static final Prefix PREFIX_UNITNUMBER = new Prefix("unitNo/"); public static final Prefix PREFIX_BLOCK = new Prefix("blk/"); public static final Prefix PREFIX_POSTALCODE = new Prefix("postal/"); diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index be3e9092af8..565fd8ffe32 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -10,6 +10,7 @@ import seedu.address.commons.util.StringUtil; import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.house.Block; +import seedu.address.model.house.Level; import seedu.address.model.house.PostalCode; import seedu.address.model.house.UnitNumber; import seedu.address.model.person.Address; @@ -126,6 +127,21 @@ public static Set parseTags(Collection tags) throws ParseException return tagSet; } + /** + * Parses a {@code String level} into a {@code Level}. + * Leading and trailing whitespaces will be trimmed. + * + * @throws ParseException if the given {@code level} is invalid. + */ + public static Level parseLevel(String level) throws ParseException { + requireNonNull(level); + String trimmedLevel = level.trim(); + if (!Level.isValidLevel(trimmedLevel)) { + throw new ParseException(Level.MESSAGE_CONSTRAINTS); + } + return new Level(trimmedLevel); + } + /** * Parses a {@code String unitNumber} into a {@code unitNumber}. * Leading and trailing whitespaces will be trimmed. diff --git a/src/main/java/seedu/address/model/house/Level.java b/src/main/java/seedu/address/model/house/Level.java new file mode 100644 index 00000000000..1198fd809a2 --- /dev/null +++ b/src/main/java/seedu/address/model/house/Level.java @@ -0,0 +1,63 @@ +package seedu.address.model.house; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.util.AppUtil.checkArgument; + + +/** + * Represents a House's level. + * Guarantees: immutable; is valid as declared in {@link #isValidLevel(String)} + */ +public class Level { + + public static final String MESSAGE_CONSTRAINTS = + "Level should only contain numbers, and it should only be at most 2 digits long"; + public static final String VALIDATION_REGEX = "\\d{1,2}"; + public static final String ZERO_REGEX = "^0+$"; + + public final String value; + + /** + * Constructs a {@code Level}. + * + * @param level A valid level. + */ + public Level(String level) { + requireNonNull(level); + checkArgument(isValidLevel(level), MESSAGE_CONSTRAINTS); + value = level; + } + + /** + * Returns true if a given string is a valid level. + */ + public static boolean isValidLevel(String test) { + return test.matches(VALIDATION_REGEX) && !test.matches(ZERO_REGEX); + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof Level)) { + return false; + } + + Level otherLevel = (Level) other; + return value.equals(otherLevel.value); + } + + @Override + public int hashCode() { + return value.hashCode(); + } + +} diff --git a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java index f363378c13b..ffa9343ec96 100644 --- a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java +++ b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java @@ -15,6 +15,7 @@ import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.house.Block; +import seedu.address.model.house.Level; import seedu.address.model.house.PostalCode; import seedu.address.model.house.UnitNumber; import seedu.address.model.person.Address; @@ -29,6 +30,7 @@ public class ParserUtilTest { private static final String INVALID_ADDRESS = " "; private static final String INVALID_EMAIL = "example.com"; private static final String INVALID_TAG = "#friend"; + private static final String INVALID_LEVEL = "aa"; private static final String INVALID_UNIT_NUMBER = "1234"; private static final String INVALID_BLOCK = "12a34"; private static final String INVALID_POSTALCODE = "5678990"; @@ -40,6 +42,7 @@ public class ParserUtilTest { private static final String VALID_POSTALCODE = "654321"; private static final String VALID_TAG_1 = "friend"; private static final String VALID_TAG_2 = "neighbour"; + private static final String VALID_LEVEL = "10"; private static final String VALID_UNIT_NUMBER = "123"; private static final String VALID_BLOCK = "205A"; @@ -227,6 +230,27 @@ public void parseTags_collectionWithValidTags_returnsTagSet() throws Exception { } @Test + public void parseLevel_null_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> ParserUtil.parseLevel((String) null)); + } + + @Test + public void parseLevel_invalidValue_throwsParseException() { + assertThrows(ParseException.class, () -> ParserUtil.parseLevel(INVALID_LEVEL)); + } + + @Test + public void parseLevel_validValueWithoutWhitespace_returnsLevel() throws Exception { + Level expectedLevel = new Level(VALID_LEVEL); + assertEquals(expectedLevel, ParserUtil.parseLevel(VALID_LEVEL)); + } + + @Test + public void parseLevel_validValueWithWhitespace_returnsTrimmedLevel() throws Exception { + String levelWithWhitespace = WHITESPACE + VALID_LEVEL + WHITESPACE; + Level expectedLevel = new Level(VALID_LEVEL); + assertEquals(expectedLevel, ParserUtil.parseLevel(levelWithWhitespace)); + } public void parseUnitNumber_null_throwsNullPointerException() { assertThrows(NullPointerException.class, () -> ParserUtil.parseUnitNumber((String) null)); } @@ -248,7 +272,6 @@ public void parseUnitNumber_validValueWithWhitespace_returnsTrimmedUnitNumber() UnitNumber expectedUnitNumber = new UnitNumber(VALID_UNIT_NUMBER); assertEquals(expectedUnitNumber, ParserUtil.parseUnitNumber(unitNumberWithWhitespace)); } - public void parseBlock_null_throwsNullPointerException() { assertThrows(NullPointerException.class, () -> ParserUtil.parseBlock((String) null)); } diff --git a/src/test/java/seedu/address/model/house/LevelTest.java b/src/test/java/seedu/address/model/house/LevelTest.java new file mode 100644 index 00000000000..0bdff302e7d --- /dev/null +++ b/src/test/java/seedu/address/model/house/LevelTest.java @@ -0,0 +1,69 @@ +package seedu.address.model.house; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.address.testutil.Assert.assertThrows; + +import org.junit.jupiter.api.Test; + +public class LevelTest { + + @Test + public void constructor_null_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> new Level(null)); + } + + @Test + public void constructor_invalidLevel_throwsIllegalArgumentException() { + String invalidLevel = ""; + assertThrows(IllegalArgumentException.class, () -> new Level(invalidLevel)); + } + + @Test + public void isValidLevel() { + // null level + assertThrows(NullPointerException.class, () -> Level.isValidLevel(null)); + + // blank levels + assertFalse(Level.isValidLevel("")); // empty string + assertFalse(Level.isValidLevel(" ")); // spaces only + + // invalid levels + assertFalse(Level.isValidLevel("0")); // 1 zero only + assertFalse(Level.isValidLevel("00")); // 2 zeroes only + assertFalse(Level.isValidLevel("a")); // non-digit only + assertFalse(Level.isValidLevel("aa")); // non-digit only + assertFalse(Level.isValidLevel("###")); // non-digit only + assertFalse(Level.isValidLevel("!@#")); // non-digit only + assertFalse(Level.isValidLevel("a1")); // digit + non-digit + assertFalse(Level.isValidLevel("1a")); // non-digit + digit + assertFalse(Level.isValidLevel("111")); // number of digits > 2 + assertFalse(Level.isValidLevel("44aa")); // number of digits >= 2 with letters + assertFalse(Level.isValidLevel("44aaaaa")); // number of digits >= 2 with letters + + // valid levels + assertTrue(Level.isValidLevel("1")); // one digit + assertTrue(Level.isValidLevel("11")); // two digits + assertTrue(Level.isValidLevel("01")); // two digits + } + + @Test + public void equals() { + Level level = new Level("99"); + + // same values -> returns true + assertTrue(level.equals(new Level("99"))); + + // same object -> returns true + assertTrue(level.equals(level)); + + // null -> returns false + assertFalse(level.equals(null)); + + // different types -> returns false + assertFalse(level.equals(5.0f)); + + // different values -> returns false + assertFalse(level.equals(new Level("11"))); + } +}