From 48b56ad4c4e81c987177afd1d744cac57dde8efe Mon Sep 17 00:00:00 2001 From: choonx99 Date: Sat, 28 Sep 2019 04:13:09 +0800 Subject: [PATCH 1/8] safe delete Address class --- .../address/logic/commands/AddCommand.java | 3 - .../address/logic/commands/EditCommand.java | 19 +------ .../logic/parser/AddCommandParser.java | 9 +-- .../seedu/address/logic/parser/CliSyntax.java | 1 - .../logic/parser/EditCommandParser.java | 6 +- .../address/logic/parser/ParserUtil.java | 16 ------ .../seedu/address/model/person/Address.java | 57 ------------------- .../seedu/address/model/person/Person.java | 15 +---- .../address/model/util/SampleDataUtil.java | 7 --- .../address/storage/JsonAdaptedPerson.java | 17 ++---- .../java/seedu/address/ui/PersonCard.java | 1 - .../invalidAndValidPersonAddressBook.json | 2 - .../invalidPersonAddressBook.json | 1 - .../duplicatePersonAddressBook.json | 2 - .../invalidPersonAddressBook.json | 3 +- .../typicalPersonsAddressBook.json | 7 --- .../logic/commands/CommandTestUtil.java | 8 +-- .../logic/parser/AddCommandParserTest.java | 5 -- .../logic/parser/EditCommandParserTest.java | 3 - .../address/logic/parser/ParserUtilTest.java | 24 -------- .../address/model/person/AddressTest.java | 36 ------------ .../storage/JsonAdaptedPersonTest.java | 32 +++-------- .../testutil/EditPersonDescriptorBuilder.java | 10 ---- .../seedu/address/testutil/PersonBuilder.java | 14 +---- .../seedu/address/testutil/PersonUtil.java | 1 - 25 files changed, 24 insertions(+), 275 deletions(-) delete mode 100644 src/main/java/seedu/address/model/person/Address.java delete mode 100644 src/test/java/seedu/address/model/person/AddressTest.java diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java index 71656d7c5c8..a6cff3044b6 100644 --- a/src/main/java/seedu/address/logic/commands/AddCommand.java +++ b/src/main/java/seedu/address/logic/commands/AddCommand.java @@ -1,7 +1,6 @@ package seedu.address.logic.commands; import static java.util.Objects.requireNonNull; -import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; @@ -23,13 +22,11 @@ public class AddCommand extends Command { + PREFIX_NAME + "NAME " + PREFIX_PHONE + "PHONE " + PREFIX_EMAIL + "EMAIL " - + PREFIX_ADDRESS + "ADDRESS " + "[" + PREFIX_TAG + "TAG]...\n" + "Example: " + COMMAND_WORD + " " + PREFIX_NAME + "John Doe " + PREFIX_PHONE + "98765432 " + PREFIX_EMAIL + "johnd@example.com " - + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 " + PREFIX_TAG + "friends " + PREFIX_TAG + "owesMoney"; diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java index 7e36114902f..71e7d5e98bc 100644 --- a/src/main/java/seedu/address/logic/commands/EditCommand.java +++ b/src/main/java/seedu/address/logic/commands/EditCommand.java @@ -1,7 +1,6 @@ package seedu.address.logic.commands; import static java.util.Objects.requireNonNull; -import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; @@ -19,7 +18,6 @@ import seedu.address.commons.util.CollectionUtil; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; -import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Person; @@ -40,7 +38,6 @@ public class EditCommand extends Command { + "[" + PREFIX_NAME + "NAME] " + "[" + PREFIX_PHONE + "PHONE] " + "[" + PREFIX_EMAIL + "EMAIL] " - + "[" + PREFIX_ADDRESS + "ADDRESS] " + "[" + PREFIX_TAG + "TAG]...\n" + "Example: " + COMMAND_WORD + " 1 " + PREFIX_PHONE + "91234567 " @@ -96,10 +93,9 @@ private static Person createEditedPerson(Person personToEdit, EditPersonDescript Name updatedName = editPersonDescriptor.getName().orElse(personToEdit.getName()); Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone()); Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail()); - Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress()); Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags()); - return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags); + return new Person(updatedName, updatedPhone, updatedEmail, updatedTags); } @Override @@ -128,7 +124,6 @@ public static class EditPersonDescriptor { private Name name; private Phone phone; private Email email; - private Address address; private Set tags; public EditPersonDescriptor() {} @@ -141,7 +136,6 @@ public EditPersonDescriptor(EditPersonDescriptor toCopy) { setName(toCopy.name); setPhone(toCopy.phone); setEmail(toCopy.email); - setAddress(toCopy.address); setTags(toCopy.tags); } @@ -149,7 +143,7 @@ public EditPersonDescriptor(EditPersonDescriptor toCopy) { * Returns true if at least one field is edited. */ public boolean isAnyFieldEdited() { - return CollectionUtil.isAnyNonNull(name, phone, email, address, tags); + return CollectionUtil.isAnyNonNull(name, phone, email, tags); } public void setName(Name name) { @@ -176,14 +170,6 @@ public Optional getEmail() { return Optional.ofNullable(email); } - public void setAddress(Address address) { - this.address = address; - } - - public Optional
getAddress() { - return Optional.ofNullable(address); - } - /** * Sets {@code tags} to this object's {@code tags}. * A defensive copy of {@code tags} is used internally. @@ -219,7 +205,6 @@ public boolean equals(Object other) { return getName().equals(e.getName()) && getPhone().equals(e.getPhone()) && getEmail().equals(e.getEmail()) - && getAddress().equals(e.getAddress()) && getTags().equals(e.getTags()); } } diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java index 3b8bfa035e8..c39a41a3935 100644 --- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/AddCommandParser.java @@ -1,7 +1,6 @@ package seedu.address.logic.parser; import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; @@ -12,7 +11,6 @@ import seedu.address.logic.commands.AddCommand; import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Person; @@ -31,9 +29,9 @@ public class AddCommandParser implements Parser { */ public AddCommand parse(String args) throws ParseException { ArgumentMultimap argMultimap = - ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG); + ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_TAG); - if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL) + if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL) || !argMultimap.getPreamble().isEmpty()) { throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE)); } @@ -41,10 +39,9 @@ public AddCommand parse(String args) throws ParseException { Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()); Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()); Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()); - Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()); Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG)); - Person person = new Person(name, phone, email, address, tagList); + Person person = new Person(name, phone, email, tagList); return new AddCommand(person); } diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java index 75b1a9bf119..9dd7deff4da 100644 --- a/src/main/java/seedu/address/logic/parser/CliSyntax.java +++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java @@ -9,7 +9,6 @@ public class CliSyntax { public static final Prefix PREFIX_NAME = new Prefix("n/"); public static final Prefix PREFIX_PHONE = new Prefix("p/"); 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/"); } diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java index 845644b7dea..bdfe5ad1978 100644 --- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/EditCommandParser.java @@ -2,7 +2,6 @@ import static java.util.Objects.requireNonNull; import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; @@ -32,7 +31,7 @@ public class EditCommandParser implements Parser { public EditCommand parse(String args) throws ParseException { requireNonNull(args); ArgumentMultimap argMultimap = - ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG); + ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_TAG); Index index; @@ -52,9 +51,6 @@ public EditCommand parse(String args) throws ParseException { if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) { editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get())); } - if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) { - editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get())); - } parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags); if (!editPersonDescriptor.isAnyFieldEdited()) { diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index b117acb9c55..9ab53095f44 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -9,7 +9,6 @@ import seedu.address.commons.core.index.Index; import seedu.address.commons.util.StringUtil; import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Phone; @@ -65,21 +64,6 @@ public static Phone parsePhone(String phone) throws ParseException { return new Phone(trimmedPhone); } - /** - * Parses a {@code String address} into an {@code Address}. - * Leading and trailing whitespaces will be trimmed. - * - * @throws ParseException if the given {@code address} is invalid. - */ - public static Address parseAddress(String address) throws ParseException { - requireNonNull(address); - String trimmedAddress = address.trim(); - if (!Address.isValidAddress(trimmedAddress)) { - throw new ParseException(Address.MESSAGE_CONSTRAINTS); - } - return new Address(trimmedAddress); - } - /** * Parses a {@code String email} into an {@code Email}. * Leading and trailing whitespaces will be trimmed. diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/seedu/address/model/person/Address.java deleted file mode 100644 index 60472ca22a0..00000000000 --- a/src/main/java/seedu/address/model/person/Address.java +++ /dev/null @@ -1,57 +0,0 @@ -package seedu.address.model.person; - -import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; - -/** - * Represents a Person's address in the address book. - * Guarantees: immutable; is valid as declared in {@link #isValidAddress(String)} - */ -public class Address { - - public static final String MESSAGE_CONSTRAINTS = "Addresses can take any values, and it should not be blank"; - - /* - * The first character of the address must not be a whitespace, - * otherwise " " (a blank string) becomes a valid input. - */ - public static final String VALIDATION_REGEX = "[^\\s].*"; - - public final String value; - - /** - * Constructs an {@code Address}. - * - * @param address A valid address. - */ - public Address(String address) { - requireNonNull(address); - checkArgument(isValidAddress(address), MESSAGE_CONSTRAINTS); - value = address; - } - - /** - * Returns true if a given string is a valid email. - */ - public static boolean isValidAddress(String test) { - return test.matches(VALIDATION_REGEX); - } - - @Override - public String toString() { - return value; - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof Address // instanceof handles nulls - && value.equals(((Address) other).value)); // state check - } - - @Override - public int hashCode() { - return value.hashCode(); - } - -} diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java index 557a7a60cd5..f43cae3f1a1 100644 --- a/src/main/java/seedu/address/model/person/Person.java +++ b/src/main/java/seedu/address/model/person/Person.java @@ -21,18 +21,16 @@ public class Person { private final Email email; // Data fields - private final Address address; private final Set tags = new HashSet<>(); /** * Every field must be present and not null. */ - public Person(Name name, Phone phone, Email email, Address address, Set tags) { - requireAllNonNull(name, phone, email, address, tags); + public Person(Name name, Phone phone, Email email, Set tags) { + requireAllNonNull(name, phone, email, tags); this.name = name; this.phone = phone; this.email = email; - this.address = address; this.tags.addAll(tags); } @@ -48,10 +46,6 @@ public Email getEmail() { return email; } - public Address getAddress() { - return address; - } - /** * Returns an immutable tag set, which throws {@code UnsupportedOperationException} * if modification is attempted. @@ -92,14 +86,13 @@ public boolean equals(Object other) { return otherPerson.getName().equals(getName()) && otherPerson.getPhone().equals(getPhone()) && otherPerson.getEmail().equals(getEmail()) - && otherPerson.getAddress().equals(getAddress()) && otherPerson.getTags().equals(getTags()); } @Override public int hashCode() { // use this method for custom fields hashing instead of implementing your own - return Objects.hash(name, phone, email, address, tags); + return Objects.hash(name, phone, email, tags); } @Override @@ -110,8 +103,6 @@ public String toString() { .append(getPhone()) .append(" Email: ") .append(getEmail()) - .append(" Address: ") - .append(getAddress()) .append(" Tags: "); getTags().forEach(builder::append); return builder.toString(); diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java index 1806da4facf..c8ca69d0cbc 100644 --- a/src/main/java/seedu/address/model/util/SampleDataUtil.java +++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java @@ -6,7 +6,6 @@ import seedu.address.model.AddressBook; import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Person; @@ -20,22 +19,16 @@ public class SampleDataUtil { public static Person[] getSamplePersons() { return new Person[] { new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"), - new Address("Blk 30 Geylang Street 29, #06-40"), getTagSet("friends")), new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"), - new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"), getTagSet("colleagues", "friends")), new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"), - new Address("Blk 11 Ang Mo Kio Street 74, #11-04"), getTagSet("neighbours")), new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"), - new Address("Blk 436 Serangoon Gardens Street 26, #16-43"), getTagSet("family")), new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"), - new Address("Blk 47 Tampines Street 20, #17-35"), getTagSet("classmates")), new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"), - new Address("Blk 45 Aljunied Street 85, #11-31"), getTagSet("colleagues")) }; } diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java index a6321cec2ea..76a9bc76b0a 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java @@ -10,7 +10,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Person; @@ -27,7 +26,6 @@ class JsonAdaptedPerson { private final String name; private final String phone; private final String email; - private final String address; private final List tagged = new ArrayList<>(); /** @@ -35,12 +33,11 @@ class JsonAdaptedPerson { */ @JsonCreator public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone, - @JsonProperty("email") String email, @JsonProperty("address") String address, + @JsonProperty("email") String email, @JsonProperty("tagged") List tagged) { this.name = name; this.phone = phone; this.email = email; - this.address = address; if (tagged != null) { this.tagged.addAll(tagged); } @@ -53,7 +50,6 @@ public JsonAdaptedPerson(Person source) { name = source.getName().fullName; phone = source.getPhone().value; email = source.getEmail().value; - address = source.getAddress().value; tagged.addAll(source.getTags().stream() .map(JsonAdaptedTag::new) .collect(Collectors.toList())); @@ -94,16 +90,11 @@ public Person toModelType() throws IllegalValueException { } final Email modelEmail = new Email(email); - if (address == null) { - throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName())); - } - if (!Address.isValidAddress(address)) { - throw new IllegalValueException(Address.MESSAGE_CONSTRAINTS); - } - final Address modelAddress = new Address(address); + + final Set modelTags = new HashSet<>(personTags); - return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags); + return new Person(modelName, modelPhone, modelEmail, modelTags); } } diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java index 0684b088868..85142fe6048 100644 --- a/src/main/java/seedu/address/ui/PersonCard.java +++ b/src/main/java/seedu/address/ui/PersonCard.java @@ -47,7 +47,6 @@ public PersonCard(Person person, int displayedIndex) { id.setText(displayedIndex + ". "); name.setText(person.getName().fullName); phone.setText(person.getPhone().value); - address.setText(person.getAddress().value); email.setText(person.getEmail().value); person.getTags().stream() .sorted(Comparator.comparing(tag -> tag.tagName)) diff --git a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json index 6a4d2b7181c..15047decade 100644 --- a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json +++ b/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json @@ -3,11 +3,9 @@ "name": "Valid Person", "phone": "9482424", "email": "hans@example.com", - "address": "4th street" }, { "name": "Person With Invalid Phone Field", "phone": "948asdf2424", "email": "hans@example.com", - "address": "4th street" } ] } diff --git a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json index ccd21f7d1a9..c89c9c85f0f 100644 --- a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json +++ b/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json @@ -3,6 +3,5 @@ "name": "Person with invalid name field: Ha!ns Mu@ster", "phone": "9482424", "email": "hans@example.com", - "address": "4th street" } ] } diff --git a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json index 48831cc7674..26cb38712ee 100644 --- a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json @@ -3,12 +3,10 @@ "name": "Alice Pauline", "phone": "94351253", "email": "alice@example.com", - "address": "123, Jurong West Ave 6, #08-111", "tagged": [ "friends" ] }, { "name": "Alice Pauline", "phone": "94351253", "email": "pauline@example.com", - "address": "4th street" } ] } diff --git a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json index ad3f135ae42..671f3da654c 100644 --- a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json @@ -2,7 +2,6 @@ "persons": [ { "name": "Hans Muster", "phone": "9482424", - "email": "invalid@email!3e", - "address": "4th street" + "email": "invalid@email!3e" } ] } diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json index f10eddee12e..51a5ce525a3 100644 --- a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json @@ -4,43 +4,36 @@ "name" : "Alice Pauline", "phone" : "94351253", "email" : "alice@example.com", - "address" : "123, Jurong West Ave 6, #08-111", "tagged" : [ "friends" ] }, { "name" : "Benson Meier", "phone" : "98765432", "email" : "johnd@example.com", - "address" : "311, Clementi Ave 2, #02-25", "tagged" : [ "owesMoney", "friends" ] }, { "name" : "Carl Kurz", "phone" : "95352563", "email" : "heinz@example.com", - "address" : "wall street", "tagged" : [ ] }, { "name" : "Daniel Meier", "phone" : "87652533", "email" : "cornelia@example.com", - "address" : "10th street", "tagged" : [ "friends" ] }, { "name" : "Elle Meyer", "phone" : "9482224", "email" : "werner@example.com", - "address" : "michegan ave", "tagged" : [ ] }, { "name" : "Fiona Kunz", "phone" : "9482427", "email" : "lydia@example.com", - "address" : "little tokyo", "tagged" : [ ] }, { "name" : "George Best", "phone" : "9482442", "email" : "anna@example.com", - "address" : "4th street", "tagged" : [ ] } ] } diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java index 643a1d08069..08a7a433a8e 100644 --- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java +++ b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java @@ -2,7 +2,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; @@ -43,15 +42,12 @@ public class CommandTestUtil { public static final String PHONE_DESC_BOB = " " + PREFIX_PHONE + VALID_PHONE_BOB; public static final String EMAIL_DESC_AMY = " " + PREFIX_EMAIL + VALID_EMAIL_AMY; public static final String EMAIL_DESC_BOB = " " + PREFIX_EMAIL + VALID_EMAIL_BOB; - public static final String ADDRESS_DESC_AMY = " " + PREFIX_ADDRESS + VALID_ADDRESS_AMY; - public static final String ADDRESS_DESC_BOB = " " + PREFIX_ADDRESS + VALID_ADDRESS_BOB; public static final String TAG_DESC_FRIEND = " " + PREFIX_TAG + VALID_TAG_FRIEND; public static final String TAG_DESC_HUSBAND = " " + PREFIX_TAG + VALID_TAG_HUSBAND; public static final String INVALID_NAME_DESC = " " + PREFIX_NAME + "James&"; // '&' not allowed in names public static final String INVALID_PHONE_DESC = " " + PREFIX_PHONE + "911a"; // 'a' not allowed in phones public static final String INVALID_EMAIL_DESC = " " + PREFIX_EMAIL + "bob!yahoo"; // missing '@' symbol - public static final String INVALID_ADDRESS_DESC = " " + PREFIX_ADDRESS; // empty string not allowed for addresses public static final String INVALID_TAG_DESC = " " + PREFIX_TAG + "hubby*"; // '*' not allowed in tags public static final String PREAMBLE_WHITESPACE = "\t \r \n"; @@ -62,10 +58,10 @@ public class CommandTestUtil { static { DESC_AMY = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY) - .withPhone(VALID_PHONE_AMY).withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY) + .withPhone(VALID_PHONE_AMY).withEmail(VALID_EMAIL_AMY) .withTags(VALID_TAG_FRIEND).build(); DESC_BOB = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB) - .withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB) + .withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB) .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build(); } diff --git a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java index 5cf487d7ebb..eaec6fea31a 100644 --- a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java +++ b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java @@ -32,7 +32,6 @@ import org.junit.jupiter.api.Test; import seedu.address.logic.commands.AddCommand; -import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Person; @@ -121,10 +120,6 @@ public void parse_invalidValue_failure() { assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + INVALID_EMAIL_DESC + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Email.MESSAGE_CONSTRAINTS); - // invalid address - assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + INVALID_ADDRESS_DESC - + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Address.MESSAGE_CONSTRAINTS); - // invalid tag assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB + INVALID_TAG_DESC + VALID_TAG_FRIEND, Tag.MESSAGE_CONSTRAINTS); diff --git a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java index 2ff31522486..b549285035b 100644 --- a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java +++ b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java @@ -5,7 +5,6 @@ import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB; import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY; import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB; -import static seedu.address.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC; import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC; import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC; import static seedu.address.logic.commands.CommandTestUtil.INVALID_PHONE_DESC; @@ -36,7 +35,6 @@ import seedu.address.commons.core.index.Index; import seedu.address.logic.commands.EditCommand; import seedu.address.logic.commands.EditCommand.EditPersonDescriptor; -import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Phone; @@ -84,7 +82,6 @@ public void parse_invalidValue_failure() { assertParseFailure(parser, "1" + INVALID_NAME_DESC, Name.MESSAGE_CONSTRAINTS); // invalid name assertParseFailure(parser, "1" + INVALID_PHONE_DESC, Phone.MESSAGE_CONSTRAINTS); // invalid phone assertParseFailure(parser, "1" + INVALID_EMAIL_DESC, Email.MESSAGE_CONSTRAINTS); // invalid email - assertParseFailure(parser, "1" + INVALID_ADDRESS_DESC, Address.MESSAGE_CONSTRAINTS); // invalid address assertParseFailure(parser, "1" + INVALID_TAG_DESC, Tag.MESSAGE_CONSTRAINTS); // invalid tag // invalid phone followed by valid email diff --git a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java index 4256788b1a7..2f0027be91f 100644 --- a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java +++ b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java @@ -14,7 +14,6 @@ import org.junit.jupiter.api.Test; import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Phone; @@ -102,29 +101,6 @@ public void parsePhone_validValueWithWhitespace_returnsTrimmedPhone() throws Exc assertEquals(expectedPhone, ParserUtil.parsePhone(phoneWithWhitespace)); } - @Test - public void parseAddress_null_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> ParserUtil.parseAddress((String) null)); - } - - @Test - public void parseAddress_invalidValue_throwsParseException() { - assertThrows(ParseException.class, () -> ParserUtil.parseAddress(INVALID_ADDRESS)); - } - - @Test - public void parseAddress_validValueWithoutWhitespace_returnsAddress() throws Exception { - Address expectedAddress = new Address(VALID_ADDRESS); - assertEquals(expectedAddress, ParserUtil.parseAddress(VALID_ADDRESS)); - } - - @Test - public void parseAddress_validValueWithWhitespace_returnsTrimmedAddress() throws Exception { - String addressWithWhitespace = WHITESPACE + VALID_ADDRESS + WHITESPACE; - Address expectedAddress = new Address(VALID_ADDRESS); - assertEquals(expectedAddress, ParserUtil.parseAddress(addressWithWhitespace)); - } - @Test public void parseEmail_null_throwsNullPointerException() { assertThrows(NullPointerException.class, () -> ParserUtil.parseEmail((String) null)); diff --git a/src/test/java/seedu/address/model/person/AddressTest.java b/src/test/java/seedu/address/model/person/AddressTest.java deleted file mode 100644 index dcd3be87b3a..00000000000 --- a/src/test/java/seedu/address/model/person/AddressTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package seedu.address.model.person; - -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 AddressTest { - - @Test - public void constructor_null_throwsNullPointerException() { - assertThrows(NullPointerException.class, () -> new Address(null)); - } - - @Test - public void constructor_invalidAddress_throwsIllegalArgumentException() { - String invalidAddress = ""; - assertThrows(IllegalArgumentException.class, () -> new Address(invalidAddress)); - } - - @Test - public void isValidAddress() { - // null address - assertThrows(NullPointerException.class, () -> Address.isValidAddress(null)); - - // invalid addresses - assertFalse(Address.isValidAddress("")); // empty string - assertFalse(Address.isValidAddress(" ")); // spaces only - - // valid addresses - assertTrue(Address.isValidAddress("Blk 456, Den Road, #01-355")); - assertTrue(Address.isValidAddress("-")); // one character - assertTrue(Address.isValidAddress("Leng Inc; 1234 Market St; San Francisco CA 2349879; USA")); // long address - } -} diff --git a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java b/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java index 83b11331cdb..cd3e64e7bba 100644 --- a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java +++ b/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java @@ -12,7 +12,6 @@ import org.junit.jupiter.api.Test; import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Phone; @@ -20,14 +19,12 @@ public class JsonAdaptedPersonTest { private static final String INVALID_NAME = "R@chel"; private static final String INVALID_PHONE = "+651234"; - 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 VALID_NAME = BENSON.getName().toString(); private static final String VALID_PHONE = BENSON.getPhone().toString(); private static final String VALID_EMAIL = BENSON.getEmail().toString(); - private static final String VALID_ADDRESS = BENSON.getAddress().toString(); private static final List VALID_TAGS = BENSON.getTags().stream() .map(JsonAdaptedTag::new) .collect(Collectors.toList()); @@ -41,14 +38,14 @@ public void toModelType_validPersonDetails_returnsPerson() throws Exception { @Test public void toModelType_invalidName_throwsIllegalValueException() { JsonAdaptedPerson person = - new JsonAdaptedPerson(INVALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS); + new JsonAdaptedPerson(INVALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_TAGS); String expectedMessage = Name.MESSAGE_CONSTRAINTS; assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @Test public void toModelType_nullName_throwsIllegalValueException() { - JsonAdaptedPerson person = new JsonAdaptedPerson(null, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS); + JsonAdaptedPerson person = new JsonAdaptedPerson(null, VALID_PHONE, VALID_EMAIL, VALID_TAGS); String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()); assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @@ -56,14 +53,14 @@ public void toModelType_nullName_throwsIllegalValueException() { @Test public void toModelType_invalidPhone_throwsIllegalValueException() { JsonAdaptedPerson person = - new JsonAdaptedPerson(VALID_NAME, INVALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS); + new JsonAdaptedPerson(VALID_NAME, INVALID_PHONE, VALID_EMAIL, VALID_TAGS); String expectedMessage = Phone.MESSAGE_CONSTRAINTS; assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @Test public void toModelType_nullPhone_throwsIllegalValueException() { - JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, null, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS); + JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, null, VALID_EMAIL, VALID_TAGS); String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName()); assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @@ -71,39 +68,24 @@ public void toModelType_nullPhone_throwsIllegalValueException() { @Test public void toModelType_invalidEmail_throwsIllegalValueException() { JsonAdaptedPerson person = - new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, INVALID_EMAIL, VALID_ADDRESS, VALID_TAGS); + new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, INVALID_EMAIL, VALID_TAGS); String expectedMessage = Email.MESSAGE_CONSTRAINTS; assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @Test public void toModelType_nullEmail_throwsIllegalValueException() { - JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, null, VALID_ADDRESS, VALID_TAGS); + JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, null, VALID_TAGS); String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName()); assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } - @Test - public void toModelType_invalidAddress_throwsIllegalValueException() { - JsonAdaptedPerson person = - new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, INVALID_ADDRESS, VALID_TAGS); - String expectedMessage = Address.MESSAGE_CONSTRAINTS; - assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); - } - - @Test - public void toModelType_nullAddress_throwsIllegalValueException() { - JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, null, VALID_TAGS); - String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName()); - assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); - } - @Test public void toModelType_invalidTags_throwsIllegalValueException() { List invalidTags = new ArrayList<>(VALID_TAGS); invalidTags.add(new JsonAdaptedTag(INVALID_TAG)); JsonAdaptedPerson person = - new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, invalidTags); + new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, invalidTags); assertThrows(IllegalValueException.class, person::toModelType); } diff --git a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java b/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java index 4584bd5044e..60f8b888d12 100644 --- a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java +++ b/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java @@ -5,7 +5,6 @@ import java.util.stream.Stream; import seedu.address.logic.commands.EditCommand.EditPersonDescriptor; -import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Person; @@ -35,7 +34,6 @@ public EditPersonDescriptorBuilder(Person person) { descriptor.setName(person.getName()); descriptor.setPhone(person.getPhone()); descriptor.setEmail(person.getEmail()); - descriptor.setAddress(person.getAddress()); descriptor.setTags(person.getTags()); } @@ -63,14 +61,6 @@ public EditPersonDescriptorBuilder withEmail(String email) { return this; } - /** - * Sets the {@code Address} of the {@code EditPersonDescriptor} that we are building. - */ - public EditPersonDescriptorBuilder withAddress(String address) { - descriptor.setAddress(new Address(address)); - return this; - } - /** * Parses the {@code tags} into a {@code Set} and set it to the {@code EditPersonDescriptor} * that we are building. diff --git a/src/test/java/seedu/address/testutil/PersonBuilder.java b/src/test/java/seedu/address/testutil/PersonBuilder.java index 5eff412178b..1f99937b467 100644 --- a/src/test/java/seedu/address/testutil/PersonBuilder.java +++ b/src/test/java/seedu/address/testutil/PersonBuilder.java @@ -3,7 +3,6 @@ import java.util.HashSet; import java.util.Set; -import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Person; @@ -24,14 +23,12 @@ public class PersonBuilder { private Name name; private Phone phone; private Email email; - private Address address; private Set tags; public PersonBuilder() { name = new Name(DEFAULT_NAME); phone = new Phone(DEFAULT_PHONE); email = new Email(DEFAULT_EMAIL); - address = new Address(DEFAULT_ADDRESS); tags = new HashSet<>(); } @@ -42,7 +39,6 @@ public PersonBuilder(Person personToCopy) { name = personToCopy.getName(); phone = personToCopy.getPhone(); email = personToCopy.getEmail(); - address = personToCopy.getAddress(); tags = new HashSet<>(personToCopy.getTags()); } @@ -62,14 +58,6 @@ public PersonBuilder withTags(String ... tags) { return this; } - /** - * Sets the {@code Address} of the {@code Person} that we are building. - */ - public PersonBuilder withAddress(String address) { - this.address = new Address(address); - return this; - } - /** * Sets the {@code Phone} of the {@code Person} that we are building. */ @@ -87,7 +75,7 @@ public PersonBuilder withEmail(String email) { } public Person build() { - return new Person(name, phone, email, address, tags); + return new Person(name, phone, email, tags); } } diff --git a/src/test/java/seedu/address/testutil/PersonUtil.java b/src/test/java/seedu/address/testutil/PersonUtil.java index 90849945183..9867b40ef9a 100644 --- a/src/test/java/seedu/address/testutil/PersonUtil.java +++ b/src/test/java/seedu/address/testutil/PersonUtil.java @@ -1,6 +1,5 @@ package seedu.address.testutil; -import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; From da8dc7c922d269d592098876f59ad89f1c2b16bd Mon Sep 17 00:00:00 2001 From: choonx99 Date: Wed, 2 Oct 2019 20:16:20 +0800 Subject: [PATCH 2/8] Remove trailing white space from contactus doc --- docs/ContactUs.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ContactUs.adoc b/docs/ContactUs.adoc index 2fcbfb7561d..bf2f1fb9719 100644 --- a/docs/ContactUs.adoc +++ b/docs/ContactUs.adoc @@ -4,7 +4,7 @@ * *Bug reports, Suggestions* : Post in our https://github.com/se-edu/addressbook-level3/issues[issue tracker] if you noticed bugs or have suggestions on how to improve. * *Contributing* : We welcome pull requests. Follow the process described https://github.com/oss-generic/process[here] -* *Email us* : You can also reach us at +* *Email us* : You can also reach us at Ng Choon Wah : e0310972@u.nus.edu Xiu Ziheng : e0140856@u.nus.edu From 76ee55e0028a6e2c02f4b16c6e70af5e02eb04ff Mon Sep 17 00:00:00 2001 From: choonx99 Date: Wed, 9 Oct 2019 22:16:14 +0800 Subject: [PATCH 3/8] revert removeAddr merge --- .../address/logic/commands/AddCommand.java | 3 + .../address/logic/commands/EditCommand.java | 19 ++++++- .../logic/parser/AddCommandParser.java | 9 ++- .../seedu/address/logic/parser/CliSyntax.java | 1 + .../logic/parser/EditCommandParser.java | 6 +- .../address/logic/parser/ParserUtil.java | 16 ++++++ .../seedu/address/model/person/Address.java | 57 +++++++++++++++++++ .../seedu/address/model/person/Person.java | 15 ++++- .../address/model/util/SampleDataUtil.java | 7 +++ .../address/storage/JsonAdaptedPerson.java | 17 ++++-- .../java/seedu/address/ui/PersonCard.java | 1 + .../invalidAndValidPersonAddressBook.json | 2 + .../invalidPersonAddressBook.json | 1 + .../duplicatePersonAddressBook.json | 2 + .../invalidPersonAddressBook.json | 3 +- .../typicalPersonsAddressBook.json | 7 +++ .../logic/commands/CommandTestUtil.java | 8 ++- .../logic/parser/AddCommandParserTest.java | 5 ++ .../logic/parser/EditCommandParserTest.java | 3 + .../address/logic/parser/ParserUtilTest.java | 24 ++++++++ .../address/model/person/AddressTest.java | 36 ++++++++++++ .../storage/JsonAdaptedPersonTest.java | 32 ++++++++--- .../testutil/EditPersonDescriptorBuilder.java | 10 ++++ .../seedu/address/testutil/PersonBuilder.java | 14 ++++- .../seedu/address/testutil/PersonUtil.java | 1 + 25 files changed, 275 insertions(+), 24 deletions(-) create mode 100644 src/main/java/seedu/address/model/person/Address.java create mode 100644 src/test/java/seedu/address/model/person/AddressTest.java diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java index a6cff3044b6..71656d7c5c8 100644 --- a/src/main/java/seedu/address/logic/commands/AddCommand.java +++ b/src/main/java/seedu/address/logic/commands/AddCommand.java @@ -1,6 +1,7 @@ package seedu.address.logic.commands; import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; @@ -22,11 +23,13 @@ public class AddCommand extends Command { + PREFIX_NAME + "NAME " + PREFIX_PHONE + "PHONE " + PREFIX_EMAIL + "EMAIL " + + PREFIX_ADDRESS + "ADDRESS " + "[" + PREFIX_TAG + "TAG]...\n" + "Example: " + COMMAND_WORD + " " + PREFIX_NAME + "John Doe " + PREFIX_PHONE + "98765432 " + PREFIX_EMAIL + "johnd@example.com " + + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 " + PREFIX_TAG + "friends " + PREFIX_TAG + "owesMoney"; diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java index 71e7d5e98bc..7e36114902f 100644 --- a/src/main/java/seedu/address/logic/commands/EditCommand.java +++ b/src/main/java/seedu/address/logic/commands/EditCommand.java @@ -1,6 +1,7 @@ package seedu.address.logic.commands; import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; @@ -18,6 +19,7 @@ import seedu.address.commons.util.CollectionUtil; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; +import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Person; @@ -38,6 +40,7 @@ public class EditCommand extends Command { + "[" + PREFIX_NAME + "NAME] " + "[" + PREFIX_PHONE + "PHONE] " + "[" + PREFIX_EMAIL + "EMAIL] " + + "[" + PREFIX_ADDRESS + "ADDRESS] " + "[" + PREFIX_TAG + "TAG]...\n" + "Example: " + COMMAND_WORD + " 1 " + PREFIX_PHONE + "91234567 " @@ -93,9 +96,10 @@ private static Person createEditedPerson(Person personToEdit, EditPersonDescript Name updatedName = editPersonDescriptor.getName().orElse(personToEdit.getName()); Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone()); Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail()); + Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress()); Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags()); - return new Person(updatedName, updatedPhone, updatedEmail, updatedTags); + return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags); } @Override @@ -124,6 +128,7 @@ public static class EditPersonDescriptor { private Name name; private Phone phone; private Email email; + private Address address; private Set tags; public EditPersonDescriptor() {} @@ -136,6 +141,7 @@ public EditPersonDescriptor(EditPersonDescriptor toCopy) { setName(toCopy.name); setPhone(toCopy.phone); setEmail(toCopy.email); + setAddress(toCopy.address); setTags(toCopy.tags); } @@ -143,7 +149,7 @@ public EditPersonDescriptor(EditPersonDescriptor toCopy) { * Returns true if at least one field is edited. */ public boolean isAnyFieldEdited() { - return CollectionUtil.isAnyNonNull(name, phone, email, tags); + return CollectionUtil.isAnyNonNull(name, phone, email, address, tags); } public void setName(Name name) { @@ -170,6 +176,14 @@ public Optional getEmail() { return Optional.ofNullable(email); } + public void setAddress(Address address) { + this.address = address; + } + + public Optional
getAddress() { + return Optional.ofNullable(address); + } + /** * Sets {@code tags} to this object's {@code tags}. * A defensive copy of {@code tags} is used internally. @@ -205,6 +219,7 @@ public boolean equals(Object other) { return getName().equals(e.getName()) && getPhone().equals(e.getPhone()) && getEmail().equals(e.getEmail()) + && getAddress().equals(e.getAddress()) && getTags().equals(e.getTags()); } } diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java index c39a41a3935..3b8bfa035e8 100644 --- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/AddCommandParser.java @@ -1,6 +1,7 @@ package seedu.address.logic.parser; import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; @@ -11,6 +12,7 @@ import seedu.address.logic.commands.AddCommand; import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Person; @@ -29,9 +31,9 @@ public class AddCommandParser implements Parser { */ public AddCommand parse(String args) throws ParseException { ArgumentMultimap argMultimap = - ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_TAG); + ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG); - if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL) + if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL) || !argMultimap.getPreamble().isEmpty()) { throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE)); } @@ -39,9 +41,10 @@ public AddCommand parse(String args) throws ParseException { Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()); Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()); Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()); + Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()); Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG)); - Person person = new Person(name, phone, email, tagList); + Person person = new Person(name, phone, email, address, tagList); return new AddCommand(person); } diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java index 9dd7deff4da..75b1a9bf119 100644 --- a/src/main/java/seedu/address/logic/parser/CliSyntax.java +++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java @@ -9,6 +9,7 @@ public class CliSyntax { public static final Prefix PREFIX_NAME = new Prefix("n/"); public static final Prefix PREFIX_PHONE = new Prefix("p/"); 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/"); } diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java index bdfe5ad1978..845644b7dea 100644 --- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/EditCommandParser.java @@ -2,6 +2,7 @@ import static java.util.Objects.requireNonNull; import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; @@ -31,7 +32,7 @@ public class EditCommandParser implements Parser { public EditCommand parse(String args) throws ParseException { requireNonNull(args); ArgumentMultimap argMultimap = - ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_TAG); + ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG); Index index; @@ -51,6 +52,9 @@ public EditCommand parse(String args) throws ParseException { if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) { editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get())); } + if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) { + editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get())); + } parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags); if (!editPersonDescriptor.isAnyFieldEdited()) { diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index 9ab53095f44..b117acb9c55 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -9,6 +9,7 @@ import seedu.address.commons.core.index.Index; import seedu.address.commons.util.StringUtil; import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Phone; @@ -64,6 +65,21 @@ public static Phone parsePhone(String phone) throws ParseException { return new Phone(trimmedPhone); } + /** + * Parses a {@code String address} into an {@code Address}. + * Leading and trailing whitespaces will be trimmed. + * + * @throws ParseException if the given {@code address} is invalid. + */ + public static Address parseAddress(String address) throws ParseException { + requireNonNull(address); + String trimmedAddress = address.trim(); + if (!Address.isValidAddress(trimmedAddress)) { + throw new ParseException(Address.MESSAGE_CONSTRAINTS); + } + return new Address(trimmedAddress); + } + /** * Parses a {@code String email} into an {@code Email}. * Leading and trailing whitespaces will be trimmed. diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/seedu/address/model/person/Address.java new file mode 100644 index 00000000000..60472ca22a0 --- /dev/null +++ b/src/main/java/seedu/address/model/person/Address.java @@ -0,0 +1,57 @@ +package seedu.address.model.person; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.util.AppUtil.checkArgument; + +/** + * Represents a Person's address in the address book. + * Guarantees: immutable; is valid as declared in {@link #isValidAddress(String)} + */ +public class Address { + + public static final String MESSAGE_CONSTRAINTS = "Addresses can take any values, and it should not be blank"; + + /* + * The first character of the address must not be a whitespace, + * otherwise " " (a blank string) becomes a valid input. + */ + public static final String VALIDATION_REGEX = "[^\\s].*"; + + public final String value; + + /** + * Constructs an {@code Address}. + * + * @param address A valid address. + */ + public Address(String address) { + requireNonNull(address); + checkArgument(isValidAddress(address), MESSAGE_CONSTRAINTS); + value = address; + } + + /** + * Returns true if a given string is a valid email. + */ + public static boolean isValidAddress(String test) { + return test.matches(VALIDATION_REGEX); + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Address // instanceof handles nulls + && value.equals(((Address) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } + +} diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java index f43cae3f1a1..557a7a60cd5 100644 --- a/src/main/java/seedu/address/model/person/Person.java +++ b/src/main/java/seedu/address/model/person/Person.java @@ -21,16 +21,18 @@ public class Person { private final Email email; // Data fields + private final Address address; private final Set tags = new HashSet<>(); /** * Every field must be present and not null. */ - public Person(Name name, Phone phone, Email email, Set tags) { - requireAllNonNull(name, phone, email, tags); + public Person(Name name, Phone phone, Email email, Address address, Set tags) { + requireAllNonNull(name, phone, email, address, tags); this.name = name; this.phone = phone; this.email = email; + this.address = address; this.tags.addAll(tags); } @@ -46,6 +48,10 @@ public Email getEmail() { return email; } + public Address getAddress() { + return address; + } + /** * Returns an immutable tag set, which throws {@code UnsupportedOperationException} * if modification is attempted. @@ -86,13 +92,14 @@ public boolean equals(Object other) { return otherPerson.getName().equals(getName()) && otherPerson.getPhone().equals(getPhone()) && otherPerson.getEmail().equals(getEmail()) + && otherPerson.getAddress().equals(getAddress()) && otherPerson.getTags().equals(getTags()); } @Override public int hashCode() { // use this method for custom fields hashing instead of implementing your own - return Objects.hash(name, phone, email, tags); + return Objects.hash(name, phone, email, address, tags); } @Override @@ -103,6 +110,8 @@ public String toString() { .append(getPhone()) .append(" Email: ") .append(getEmail()) + .append(" Address: ") + .append(getAddress()) .append(" Tags: "); getTags().forEach(builder::append); return builder.toString(); diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java index c8ca69d0cbc..1806da4facf 100644 --- a/src/main/java/seedu/address/model/util/SampleDataUtil.java +++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java @@ -6,6 +6,7 @@ import seedu.address.model.AddressBook; import seedu.address.model.ReadOnlyAddressBook; +import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Person; @@ -19,16 +20,22 @@ public class SampleDataUtil { public static Person[] getSamplePersons() { return new Person[] { new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"), + new Address("Blk 30 Geylang Street 29, #06-40"), getTagSet("friends")), new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"), + new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"), getTagSet("colleagues", "friends")), new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"), + new Address("Blk 11 Ang Mo Kio Street 74, #11-04"), getTagSet("neighbours")), new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"), + new Address("Blk 436 Serangoon Gardens Street 26, #16-43"), getTagSet("family")), new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"), + new Address("Blk 47 Tampines Street 20, #17-35"), getTagSet("classmates")), new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"), + new Address("Blk 45 Aljunied Street 85, #11-31"), getTagSet("colleagues")) }; } diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java index 76a9bc76b0a..a6321cec2ea 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java @@ -10,6 +10,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Person; @@ -26,6 +27,7 @@ class JsonAdaptedPerson { private final String name; private final String phone; private final String email; + private final String address; private final List tagged = new ArrayList<>(); /** @@ -33,11 +35,12 @@ class JsonAdaptedPerson { */ @JsonCreator public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone, - @JsonProperty("email") String email, + @JsonProperty("email") String email, @JsonProperty("address") String address, @JsonProperty("tagged") List tagged) { this.name = name; this.phone = phone; this.email = email; + this.address = address; if (tagged != null) { this.tagged.addAll(tagged); } @@ -50,6 +53,7 @@ public JsonAdaptedPerson(Person source) { name = source.getName().fullName; phone = source.getPhone().value; email = source.getEmail().value; + address = source.getAddress().value; tagged.addAll(source.getTags().stream() .map(JsonAdaptedTag::new) .collect(Collectors.toList())); @@ -90,11 +94,16 @@ public Person toModelType() throws IllegalValueException { } final Email modelEmail = new Email(email); - - + if (address == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName())); + } + if (!Address.isValidAddress(address)) { + throw new IllegalValueException(Address.MESSAGE_CONSTRAINTS); + } + final Address modelAddress = new Address(address); final Set modelTags = new HashSet<>(personTags); - return new Person(modelName, modelPhone, modelEmail, modelTags); + return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags); } } diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java index 85142fe6048..0684b088868 100644 --- a/src/main/java/seedu/address/ui/PersonCard.java +++ b/src/main/java/seedu/address/ui/PersonCard.java @@ -47,6 +47,7 @@ public PersonCard(Person person, int displayedIndex) { id.setText(displayedIndex + ". "); name.setText(person.getName().fullName); phone.setText(person.getPhone().value); + address.setText(person.getAddress().value); email.setText(person.getEmail().value); person.getTags().stream() .sorted(Comparator.comparing(tag -> tag.tagName)) diff --git a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json index 15047decade..6a4d2b7181c 100644 --- a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json +++ b/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json @@ -3,9 +3,11 @@ "name": "Valid Person", "phone": "9482424", "email": "hans@example.com", + "address": "4th street" }, { "name": "Person With Invalid Phone Field", "phone": "948asdf2424", "email": "hans@example.com", + "address": "4th street" } ] } diff --git a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json index c89c9c85f0f..ccd21f7d1a9 100644 --- a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json +++ b/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json @@ -3,5 +3,6 @@ "name": "Person with invalid name field: Ha!ns Mu@ster", "phone": "9482424", "email": "hans@example.com", + "address": "4th street" } ] } diff --git a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json index 26cb38712ee..48831cc7674 100644 --- a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json @@ -3,10 +3,12 @@ "name": "Alice Pauline", "phone": "94351253", "email": "alice@example.com", + "address": "123, Jurong West Ave 6, #08-111", "tagged": [ "friends" ] }, { "name": "Alice Pauline", "phone": "94351253", "email": "pauline@example.com", + "address": "4th street" } ] } diff --git a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json index 671f3da654c..ad3f135ae42 100644 --- a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json @@ -2,6 +2,7 @@ "persons": [ { "name": "Hans Muster", "phone": "9482424", - "email": "invalid@email!3e" + "email": "invalid@email!3e", + "address": "4th street" } ] } diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json index 51a5ce525a3..f10eddee12e 100644 --- a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json @@ -4,36 +4,43 @@ "name" : "Alice Pauline", "phone" : "94351253", "email" : "alice@example.com", + "address" : "123, Jurong West Ave 6, #08-111", "tagged" : [ "friends" ] }, { "name" : "Benson Meier", "phone" : "98765432", "email" : "johnd@example.com", + "address" : "311, Clementi Ave 2, #02-25", "tagged" : [ "owesMoney", "friends" ] }, { "name" : "Carl Kurz", "phone" : "95352563", "email" : "heinz@example.com", + "address" : "wall street", "tagged" : [ ] }, { "name" : "Daniel Meier", "phone" : "87652533", "email" : "cornelia@example.com", + "address" : "10th street", "tagged" : [ "friends" ] }, { "name" : "Elle Meyer", "phone" : "9482224", "email" : "werner@example.com", + "address" : "michegan ave", "tagged" : [ ] }, { "name" : "Fiona Kunz", "phone" : "9482427", "email" : "lydia@example.com", + "address" : "little tokyo", "tagged" : [ ] }, { "name" : "George Best", "phone" : "9482442", "email" : "anna@example.com", + "address" : "4th street", "tagged" : [ ] } ] } diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java index 08a7a433a8e..643a1d08069 100644 --- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java +++ b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; @@ -42,12 +43,15 @@ public class CommandTestUtil { public static final String PHONE_DESC_BOB = " " + PREFIX_PHONE + VALID_PHONE_BOB; public static final String EMAIL_DESC_AMY = " " + PREFIX_EMAIL + VALID_EMAIL_AMY; public static final String EMAIL_DESC_BOB = " " + PREFIX_EMAIL + VALID_EMAIL_BOB; + public static final String ADDRESS_DESC_AMY = " " + PREFIX_ADDRESS + VALID_ADDRESS_AMY; + public static final String ADDRESS_DESC_BOB = " " + PREFIX_ADDRESS + VALID_ADDRESS_BOB; public static final String TAG_DESC_FRIEND = " " + PREFIX_TAG + VALID_TAG_FRIEND; public static final String TAG_DESC_HUSBAND = " " + PREFIX_TAG + VALID_TAG_HUSBAND; public static final String INVALID_NAME_DESC = " " + PREFIX_NAME + "James&"; // '&' not allowed in names public static final String INVALID_PHONE_DESC = " " + PREFIX_PHONE + "911a"; // 'a' not allowed in phones public static final String INVALID_EMAIL_DESC = " " + PREFIX_EMAIL + "bob!yahoo"; // missing '@' symbol + public static final String INVALID_ADDRESS_DESC = " " + PREFIX_ADDRESS; // empty string not allowed for addresses public static final String INVALID_TAG_DESC = " " + PREFIX_TAG + "hubby*"; // '*' not allowed in tags public static final String PREAMBLE_WHITESPACE = "\t \r \n"; @@ -58,10 +62,10 @@ public class CommandTestUtil { static { DESC_AMY = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY) - .withPhone(VALID_PHONE_AMY).withEmail(VALID_EMAIL_AMY) + .withPhone(VALID_PHONE_AMY).withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY) .withTags(VALID_TAG_FRIEND).build(); DESC_BOB = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB) - .withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB) + .withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB) .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build(); } diff --git a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java index eaec6fea31a..5cf487d7ebb 100644 --- a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java +++ b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java @@ -32,6 +32,7 @@ import org.junit.jupiter.api.Test; import seedu.address.logic.commands.AddCommand; +import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Person; @@ -120,6 +121,10 @@ public void parse_invalidValue_failure() { assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + INVALID_EMAIL_DESC + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Email.MESSAGE_CONSTRAINTS); + // invalid address + assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + INVALID_ADDRESS_DESC + + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Address.MESSAGE_CONSTRAINTS); + // invalid tag assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB + INVALID_TAG_DESC + VALID_TAG_FRIEND, Tag.MESSAGE_CONSTRAINTS); diff --git a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java index b549285035b..2ff31522486 100644 --- a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java +++ b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java @@ -5,6 +5,7 @@ import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB; import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY; import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB; +import static seedu.address.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC; import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC; import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC; import static seedu.address.logic.commands.CommandTestUtil.INVALID_PHONE_DESC; @@ -35,6 +36,7 @@ import seedu.address.commons.core.index.Index; import seedu.address.logic.commands.EditCommand; import seedu.address.logic.commands.EditCommand.EditPersonDescriptor; +import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Phone; @@ -82,6 +84,7 @@ public void parse_invalidValue_failure() { assertParseFailure(parser, "1" + INVALID_NAME_DESC, Name.MESSAGE_CONSTRAINTS); // invalid name assertParseFailure(parser, "1" + INVALID_PHONE_DESC, Phone.MESSAGE_CONSTRAINTS); // invalid phone assertParseFailure(parser, "1" + INVALID_EMAIL_DESC, Email.MESSAGE_CONSTRAINTS); // invalid email + assertParseFailure(parser, "1" + INVALID_ADDRESS_DESC, Address.MESSAGE_CONSTRAINTS); // invalid address assertParseFailure(parser, "1" + INVALID_TAG_DESC, Tag.MESSAGE_CONSTRAINTS); // invalid tag // invalid phone followed by valid email diff --git a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java index 2f0027be91f..4256788b1a7 100644 --- a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java +++ b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java @@ -14,6 +14,7 @@ import org.junit.jupiter.api.Test; import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Phone; @@ -101,6 +102,29 @@ public void parsePhone_validValueWithWhitespace_returnsTrimmedPhone() throws Exc assertEquals(expectedPhone, ParserUtil.parsePhone(phoneWithWhitespace)); } + @Test + public void parseAddress_null_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> ParserUtil.parseAddress((String) null)); + } + + @Test + public void parseAddress_invalidValue_throwsParseException() { + assertThrows(ParseException.class, () -> ParserUtil.parseAddress(INVALID_ADDRESS)); + } + + @Test + public void parseAddress_validValueWithoutWhitespace_returnsAddress() throws Exception { + Address expectedAddress = new Address(VALID_ADDRESS); + assertEquals(expectedAddress, ParserUtil.parseAddress(VALID_ADDRESS)); + } + + @Test + public void parseAddress_validValueWithWhitespace_returnsTrimmedAddress() throws Exception { + String addressWithWhitespace = WHITESPACE + VALID_ADDRESS + WHITESPACE; + Address expectedAddress = new Address(VALID_ADDRESS); + assertEquals(expectedAddress, ParserUtil.parseAddress(addressWithWhitespace)); + } + @Test public void parseEmail_null_throwsNullPointerException() { assertThrows(NullPointerException.class, () -> ParserUtil.parseEmail((String) null)); diff --git a/src/test/java/seedu/address/model/person/AddressTest.java b/src/test/java/seedu/address/model/person/AddressTest.java new file mode 100644 index 00000000000..dcd3be87b3a --- /dev/null +++ b/src/test/java/seedu/address/model/person/AddressTest.java @@ -0,0 +1,36 @@ +package seedu.address.model.person; + +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 AddressTest { + + @Test + public void constructor_null_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> new Address(null)); + } + + @Test + public void constructor_invalidAddress_throwsIllegalArgumentException() { + String invalidAddress = ""; + assertThrows(IllegalArgumentException.class, () -> new Address(invalidAddress)); + } + + @Test + public void isValidAddress() { + // null address + assertThrows(NullPointerException.class, () -> Address.isValidAddress(null)); + + // invalid addresses + assertFalse(Address.isValidAddress("")); // empty string + assertFalse(Address.isValidAddress(" ")); // spaces only + + // valid addresses + assertTrue(Address.isValidAddress("Blk 456, Den Road, #01-355")); + assertTrue(Address.isValidAddress("-")); // one character + assertTrue(Address.isValidAddress("Leng Inc; 1234 Market St; San Francisco CA 2349879; USA")); // long address + } +} diff --git a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java b/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java index cd3e64e7bba..83b11331cdb 100644 --- a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java +++ b/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java @@ -12,6 +12,7 @@ import org.junit.jupiter.api.Test; import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Phone; @@ -19,12 +20,14 @@ public class JsonAdaptedPersonTest { private static final String INVALID_NAME = "R@chel"; private static final String INVALID_PHONE = "+651234"; + 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 VALID_NAME = BENSON.getName().toString(); private static final String VALID_PHONE = BENSON.getPhone().toString(); private static final String VALID_EMAIL = BENSON.getEmail().toString(); + private static final String VALID_ADDRESS = BENSON.getAddress().toString(); private static final List VALID_TAGS = BENSON.getTags().stream() .map(JsonAdaptedTag::new) .collect(Collectors.toList()); @@ -38,14 +41,14 @@ public void toModelType_validPersonDetails_returnsPerson() throws Exception { @Test public void toModelType_invalidName_throwsIllegalValueException() { JsonAdaptedPerson person = - new JsonAdaptedPerson(INVALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_TAGS); + new JsonAdaptedPerson(INVALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS); String expectedMessage = Name.MESSAGE_CONSTRAINTS; assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @Test public void toModelType_nullName_throwsIllegalValueException() { - JsonAdaptedPerson person = new JsonAdaptedPerson(null, VALID_PHONE, VALID_EMAIL, VALID_TAGS); + JsonAdaptedPerson person = new JsonAdaptedPerson(null, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS); String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()); assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @@ -53,14 +56,14 @@ public void toModelType_nullName_throwsIllegalValueException() { @Test public void toModelType_invalidPhone_throwsIllegalValueException() { JsonAdaptedPerson person = - new JsonAdaptedPerson(VALID_NAME, INVALID_PHONE, VALID_EMAIL, VALID_TAGS); + new JsonAdaptedPerson(VALID_NAME, INVALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS); String expectedMessage = Phone.MESSAGE_CONSTRAINTS; assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @Test public void toModelType_nullPhone_throwsIllegalValueException() { - JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, null, VALID_EMAIL, VALID_TAGS); + JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, null, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS); String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName()); assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @@ -68,24 +71,39 @@ public void toModelType_nullPhone_throwsIllegalValueException() { @Test public void toModelType_invalidEmail_throwsIllegalValueException() { JsonAdaptedPerson person = - new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, INVALID_EMAIL, VALID_TAGS); + new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, INVALID_EMAIL, VALID_ADDRESS, VALID_TAGS); String expectedMessage = Email.MESSAGE_CONSTRAINTS; assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } @Test public void toModelType_nullEmail_throwsIllegalValueException() { - JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, null, VALID_TAGS); + JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, null, VALID_ADDRESS, VALID_TAGS); String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName()); assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); } + @Test + public void toModelType_invalidAddress_throwsIllegalValueException() { + JsonAdaptedPerson person = + new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, INVALID_ADDRESS, VALID_TAGS); + String expectedMessage = Address.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); + } + + @Test + public void toModelType_nullAddress_throwsIllegalValueException() { + JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, null, VALID_TAGS); + String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName()); + assertThrows(IllegalValueException.class, expectedMessage, person::toModelType); + } + @Test public void toModelType_invalidTags_throwsIllegalValueException() { List invalidTags = new ArrayList<>(VALID_TAGS); invalidTags.add(new JsonAdaptedTag(INVALID_TAG)); JsonAdaptedPerson person = - new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, invalidTags); + new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, invalidTags); assertThrows(IllegalValueException.class, person::toModelType); } diff --git a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java b/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java index 60f8b888d12..4584bd5044e 100644 --- a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java +++ b/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java @@ -5,6 +5,7 @@ import java.util.stream.Stream; import seedu.address.logic.commands.EditCommand.EditPersonDescriptor; +import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Person; @@ -34,6 +35,7 @@ public EditPersonDescriptorBuilder(Person person) { descriptor.setName(person.getName()); descriptor.setPhone(person.getPhone()); descriptor.setEmail(person.getEmail()); + descriptor.setAddress(person.getAddress()); descriptor.setTags(person.getTags()); } @@ -61,6 +63,14 @@ public EditPersonDescriptorBuilder withEmail(String email) { return this; } + /** + * Sets the {@code Address} of the {@code EditPersonDescriptor} that we are building. + */ + public EditPersonDescriptorBuilder withAddress(String address) { + descriptor.setAddress(new Address(address)); + return this; + } + /** * Parses the {@code tags} into a {@code Set} and set it to the {@code EditPersonDescriptor} * that we are building. diff --git a/src/test/java/seedu/address/testutil/PersonBuilder.java b/src/test/java/seedu/address/testutil/PersonBuilder.java index 1f99937b467..5eff412178b 100644 --- a/src/test/java/seedu/address/testutil/PersonBuilder.java +++ b/src/test/java/seedu/address/testutil/PersonBuilder.java @@ -3,6 +3,7 @@ import java.util.HashSet; import java.util.Set; +import seedu.address.model.person.Address; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Person; @@ -23,12 +24,14 @@ public class PersonBuilder { private Name name; private Phone phone; private Email email; + private Address address; private Set tags; public PersonBuilder() { name = new Name(DEFAULT_NAME); phone = new Phone(DEFAULT_PHONE); email = new Email(DEFAULT_EMAIL); + address = new Address(DEFAULT_ADDRESS); tags = new HashSet<>(); } @@ -39,6 +42,7 @@ public PersonBuilder(Person personToCopy) { name = personToCopy.getName(); phone = personToCopy.getPhone(); email = personToCopy.getEmail(); + address = personToCopy.getAddress(); tags = new HashSet<>(personToCopy.getTags()); } @@ -58,6 +62,14 @@ public PersonBuilder withTags(String ... tags) { return this; } + /** + * Sets the {@code Address} of the {@code Person} that we are building. + */ + public PersonBuilder withAddress(String address) { + this.address = new Address(address); + return this; + } + /** * Sets the {@code Phone} of the {@code Person} that we are building. */ @@ -75,7 +87,7 @@ public PersonBuilder withEmail(String email) { } public Person build() { - return new Person(name, phone, email, tags); + return new Person(name, phone, email, address, tags); } } diff --git a/src/test/java/seedu/address/testutil/PersonUtil.java b/src/test/java/seedu/address/testutil/PersonUtil.java index 9867b40ef9a..90849945183 100644 --- a/src/test/java/seedu/address/testutil/PersonUtil.java +++ b/src/test/java/seedu/address/testutil/PersonUtil.java @@ -1,5 +1,6 @@ package seedu.address.testutil; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; From c43ce95d12c2df3caaa14fdb3d6bbf4db790fe0f Mon Sep 17 00:00:00 2001 From: choonx99 Date: Mon, 21 Oct 2019 23:40:00 +0800 Subject: [PATCH 4/8] added add budget function, checks to prevent budget period clashes, expenses to auto include into budget if date falls into budget period --- src/main/java/seedu/address/MainApp.java | 30 +++- .../seedu/address/logic/LogicManager.java | 6 + .../logic/commands/AddBudgetCommand.java | 68 ++++++++ .../address/logic/commands/AddCommand.java | 27 +++- .../logic/parser/AddBudgetCommandParser.java | 51 ++++++ .../seedu/address/logic/parser/CliSyntax.java | 1 + .../seedu/address/logic/parser/MymParser.java | 4 + src/main/java/seedu/address/model/Model.java | 56 +++++++ .../seedu/address/model/ModelManager.java | 80 +++++++++- .../java/seedu/address/model/UserPrefs.java | 16 +- .../seedu/address/model/budget/Budget.java | 143 +++++++++++++++++ .../address/model/budget/BudgetList.java | 149 ++++++++++++++++++ .../model/budget/ReadOnlyBudgetList.java | 15 ++ .../model/budget/UniqueBudgetList.java | 139 ++++++++++++++++ .../exceptions/BudgetNotFoundException.java | 6 + .../exceptions/DuplicateBudgetException.java | 11 ++ .../seedu/address/model/expense/Amount.java | 4 + .../seedu/address/model/expense/Date.java | 8 + .../address/model/util/SampleDataUtil.java | 10 ++ .../address/storage/BudgetListStorage.java | 47 ++++++ .../address/storage/JsonAdaptedBudget.java | 104 ++++++++++++ .../storage/JsonBudgetListStorage.java | 80 ++++++++++ .../storage/JsonSerializableBudgetList.java | 58 +++++++ .../java/seedu/address/storage/Storage.java | 13 +- .../seedu/address/storage/StorageManager.java | 35 +++- 25 files changed, 1139 insertions(+), 22 deletions(-) create mode 100644 src/main/java/seedu/address/logic/commands/AddBudgetCommand.java create mode 100644 src/main/java/seedu/address/logic/parser/AddBudgetCommandParser.java create mode 100644 src/main/java/seedu/address/model/budget/Budget.java create mode 100644 src/main/java/seedu/address/model/budget/BudgetList.java create mode 100644 src/main/java/seedu/address/model/budget/ReadOnlyBudgetList.java create mode 100644 src/main/java/seedu/address/model/budget/UniqueBudgetList.java create mode 100644 src/main/java/seedu/address/model/budget/exceptions/BudgetNotFoundException.java create mode 100644 src/main/java/seedu/address/model/budget/exceptions/DuplicateBudgetException.java create mode 100644 src/main/java/seedu/address/storage/BudgetListStorage.java create mode 100644 src/main/java/seedu/address/storage/JsonAdaptedBudget.java create mode 100644 src/main/java/seedu/address/storage/JsonBudgetListStorage.java create mode 100644 src/main/java/seedu/address/storage/JsonSerializableBudgetList.java diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java index af7a53a74ac..3a6d6861a92 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/seedu/address/MainApp.java @@ -21,13 +21,10 @@ import seedu.address.model.ReadOnlyExpenseList; import seedu.address.model.ReadOnlyUserPrefs; import seedu.address.model.UserPrefs; +import seedu.address.model.budget.BudgetList; +import seedu.address.model.budget.ReadOnlyBudgetList; import seedu.address.model.util.SampleDataUtil; -import seedu.address.storage.ExpenseListStorage; -import seedu.address.storage.JsonExpenseListStorage; -import seedu.address.storage.JsonUserPrefsStorage; -import seedu.address.storage.Storage; -import seedu.address.storage.StorageManager; -import seedu.address.storage.UserPrefsStorage; +import seedu.address.storage.*; import seedu.address.ui.Ui; import seedu.address.ui.UiManager; @@ -57,7 +54,8 @@ public void init() throws Exception { UserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(config.getUserPrefsFilePath()); UserPrefs userPrefs = initPrefs(userPrefsStorage); ExpenseListStorage expenseListStorage = new JsonExpenseListStorage(userPrefs.getExpenseListFilePath()); - storage = new StorageManager(expenseListStorage, userPrefsStorage); + BudgetListStorage budgetListStorage = new JsonBudgetListStorage(userPrefs.getBudgetListFilePath()); + storage = new StorageManager(expenseListStorage, budgetListStorage, userPrefsStorage); initLogging(config); @@ -75,7 +73,9 @@ public void init() throws Exception { */ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) { Optional expenseListOptional; + Optional budgetListOptional; ReadOnlyExpenseList initialData; + ReadOnlyBudgetList initialBudgets; try { expenseListOptional = storage.readExpenseList(); if (!expenseListOptional.isPresent()) { @@ -90,7 +90,21 @@ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) { initialData = new ExpenseList(); } - return new ModelManager(initialData, userPrefs); + try { + budgetListOptional = storage.readBudgetList(); + if (!budgetListOptional.isPresent()) { + logger.info("Data file not found. Will be starting with a sample BudgetList"); + } + initialBudgets = budgetListOptional.orElseGet(SampleDataUtil::getSampleBudgetList); + } catch (DataConversionException e) { + logger.warning("Data file not in the correct format. Will be starting with an empty BudgetList"); + initialBudgets = new BudgetList(); + } catch (IOException e) { + logger.warning("Problem while reading from the file. Will be starting with an empty BudgetList"); + initialBudgets = new BudgetList(); + } + + return new ModelManager(initialData, initialBudgets, userPrefs); } private void initLogging(Config config) { diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java index 23a371b477b..8238facb96a 100644 --- a/src/main/java/seedu/address/logic/LogicManager.java +++ b/src/main/java/seedu/address/logic/LogicManager.java @@ -49,6 +49,12 @@ public CommandResult execute(String commandText) throws CommandException, ParseE throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe); } + try { + storage.saveBudgetList(model.getBudgetList()); + } catch (IOException ioe) { + throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe); + } + return commandResult; } diff --git a/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java b/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java new file mode 100644 index 00000000000..bf74f940396 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java @@ -0,0 +1,68 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_AMOUNT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_END_DATE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; +import static seedu.address.model.budget.BudgetList.checkInputBudgetPeriodClashWithCurrentBudgets; + +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.budget.Budget; + +/** + * Adds a budget into the budget list. + */ +public class AddBudgetCommand extends Command { + + public static final String COMMAND_WORD = "budget"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a budget to the budget list.\n" + + "Parameters: " + + PREFIX_NAME + "NAME " + + PREFIX_AMOUNT + "AMOUNT " + + PREFIX_DATE + "START-DATE " + + PREFIX_END_DATE + "END-DATE...\n" + + "Example: " + COMMAND_WORD + " " + + PREFIX_NAME + "Japan Travel " + + PREFIX_AMOUNT + "$2000.00 " + + PREFIX_DATE + "12/12/2019 " + + PREFIX_END_DATE + "18/12/2019\n"; + + + public static final String MESSAGE_SUCCESS = "New budget added: %1$s"; + public static final String MESSAGE_DUPLICATE_BUDGET = "This budget already exists in the budget list"; + public static final String MESSAGE_BUDGET_CLASH = "This budget period clashes with another budget in the budget list"; + public static final String MESSAGE_START_BEFORE_END = "The budget end date has to be after its start date"; + + private final Budget toAdd; + + /** + * Creates an AddBudgetCommand to add the specified {@code Budget} + */ + public AddBudgetCommand(Budget budget) { + requireNonNull(budget); + toAdd = budget; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + if (toAdd.getEndDate().localDate.isBefore(toAdd.getStartDate().localDate)) { + throw new CommandException(MESSAGE_START_BEFORE_END); + } + + if (checkInputBudgetPeriodClashWithCurrentBudgets(toAdd)) { + throw new CommandException(MESSAGE_BUDGET_CLASH); + } + + if (model.hasBudget(toAdd)) { + throw new CommandException(MESSAGE_DUPLICATE_BUDGET); + } + + model.addBudget(toAdd); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + } +} \ No newline at end of file diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java index 52573b5f065..38b8637ffa2 100644 --- a/src/main/java/seedu/address/logic/commands/AddCommand.java +++ b/src/main/java/seedu/address/logic/commands/AddCommand.java @@ -5,11 +5,16 @@ import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; +import static seedu.address.model.budget.BudgetList.getBudgetExpenseFallsInto; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; +import seedu.address.model.budget.Budget; import seedu.address.model.expense.Expense; +import java.util.List; +import java.util.Optional; + /** * Adds an expense to the expense list. */ @@ -47,12 +52,24 @@ public AddCommand(Expense expense) { public CommandResult execute(Model model) throws CommandException { requireNonNull(model); - if (model.hasExpense(toAdd)) { - throw new CommandException(MESSAGE_DUPLICATE_EXPENSE); - } + // check if toAdd falls into any budget period + Optional b = getBudgetExpenseFallsInto(toAdd); + if (b.isPresent()) { + Budget toAddInto = b.get(); + if (toAddInto.budgetHasExpense(toAdd)) { + throw new CommandException(MESSAGE_DUPLICATE_EXPENSE); + } else { + toAddInto.addExpenseIntoBudget(toAdd); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + } + } else { + if (model.hasExpense(toAdd)) { + throw new CommandException(MESSAGE_DUPLICATE_EXPENSE); + } - model.addExpense(toAdd); - return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + model.addExpense(toAdd); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + } } @Override diff --git a/src/main/java/seedu/address/logic/parser/AddBudgetCommandParser.java b/src/main/java/seedu/address/logic/parser/AddBudgetCommandParser.java new file mode 100644 index 00000000000..09a158e2eb8 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/AddBudgetCommandParser.java @@ -0,0 +1,51 @@ +package seedu.address.logic.parser; + +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_AMOUNT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_END_DATE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; + +import seedu.address.logic.commands.AddBudgetCommand; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.budget.Budget; +import seedu.address.model.expense.Amount; +import seedu.address.model.expense.Date; +import seedu.address.model.expense.Name; + +import java.util.stream.Stream; + +/** + * Parses input arguments and creates a new AddBudgetCommand object + */ +public class AddBudgetCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the AddBudgetCommand + * and returns an AddBudgetCommand object for execution. + * + * @throws ParseException if the user input does not conform the expected format + */ + public AddBudgetCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_AMOUNT, PREFIX_DATE, PREFIX_END_DATE); + + if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_AMOUNT, PREFIX_DATE, PREFIX_END_DATE) + || !argMultimap.getPreamble().isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddBudgetCommand.MESSAGE_USAGE)); + } + + Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()); + Amount amount = ParserUtil.parseAmount(argMultimap.getValue(PREFIX_AMOUNT).get()); + Date startDate = ParserUtil.parseDate(argMultimap.getValue(PREFIX_DATE).get()); + Date endDate = ParserUtil.parseDate(argMultimap.getValue(PREFIX_END_DATE).get()); + + Budget budget = new Budget(name, amount, startDate, endDate); + + return new AddBudgetCommand(budget); + } + + private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } +} diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java index a482b3533ef..ac95627a079 100644 --- a/src/main/java/seedu/address/logic/parser/CliSyntax.java +++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java @@ -9,6 +9,7 @@ public class CliSyntax { public static final Prefix PREFIX_NAME = new Prefix("n/"); public static final Prefix PREFIX_AMOUNT = new Prefix("a/"); public static final Prefix PREFIX_DATE = new Prefix("d/"); + public static final Prefix PREFIX_END_DATE = new Prefix("ed/"); public static final Prefix PREFIX_TAG = new Prefix("t/"); } diff --git a/src/main/java/seedu/address/logic/parser/MymParser.java b/src/main/java/seedu/address/logic/parser/MymParser.java index 5d2a74d9051..84a8be2415f 100644 --- a/src/main/java/seedu/address/logic/parser/MymParser.java +++ b/src/main/java/seedu/address/logic/parser/MymParser.java @@ -7,6 +7,7 @@ import java.util.regex.Pattern; import seedu.address.logic.commands.AddCommand; +import seedu.address.logic.commands.AddBudgetCommand; import seedu.address.logic.commands.ClearCommand; import seedu.address.logic.commands.Command; import seedu.address.logic.commands.DeleteCommand; @@ -68,6 +69,9 @@ public Command parseCommand(String userInput) throws ParseException { case HelpCommand.COMMAND_WORD: return new HelpCommand(); + case AddBudgetCommand.COMMAND_WORD: + return new AddBudgetCommandParser().parse(arguments); + default: throw new ParseException(MESSAGE_UNKNOWN_COMMAND); } diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index 474a0a5c54f..304159dd3ff 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -5,6 +5,8 @@ import javafx.collections.ObservableList; import seedu.address.commons.core.GuiSettings; +import seedu.address.model.budget.Budget; +import seedu.address.model.budget.ReadOnlyBudgetList; import seedu.address.model.expense.Expense; /** @@ -13,6 +15,7 @@ public interface Model { /** {@code Predicate} that always evaluate to true */ Predicate PREDICATE_SHOW_ALL_EXPENSES = unused -> true; + Predicate PREDICATE_SHOW_ALL_BUDGETS = unused -> true; /** * Replaces user prefs data with the data in {@code userPrefs}. @@ -44,6 +47,16 @@ public interface Model { */ void setExpenseListFilePath(Path expenseListFilePath); + /** + * Returns the user prefs' budget list file path. + */ + Path getBudgetListFilePath(); + + /** + * Sets the user prefs' budget list file path. + */ + void setBudgetListFilePath(Path expenseListFilePath); + /** * Replaces expense list data with the data in {@code expenseList}. */ @@ -85,4 +98,47 @@ public interface Model { * @throws NullPointerException if {@code predicate} is null. */ void updateFilteredExpenseList(Predicate predicate); + + /** + * Replaces budget list data with the data in {@code budgetList}. + */ + void setBudgetList(ReadOnlyBudgetList budgetList); + + /** Returns the BudgetList */ + ReadOnlyBudgetList getBudgetList(); + + /** + * Returns true if a budget with the same identity as {@code budget} exists in the budget list. + */ + boolean hasBudget(Budget budget); + + /** + * Deletes the given budget. + * The budget must exist in the budget list. + */ + void deleteBudget(Budget target); + + /** + * Adds the given budget. + * {@code budget} must not already exist in the budget list. + */ + void addBudget(Budget budget); + + /** + * Replaces the given budget {@code target} with {@code editedBudget}. + * {@code target} must exist in the budget list. + * The budget identity of {@code editedBudget} must not be the same as + * another existing budget in the budget list. + */ + void setBudget(Budget target, Budget editedBudget); + + /** Returns an unmodifiable view of the filtered budget list */ + ObservableList getFilteredBudgetList(); + + /** + * Updates the filter of the filtered budget list to filter by the given {@code predicate}. + * @throws NullPointerException if {@code predicate} is null. + */ + void updateFilteredBudgetList(Predicate predicate); + } diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 074ba67b0a3..45ff4ac6944 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -11,6 +11,9 @@ import javafx.collections.transformation.FilteredList; import seedu.address.commons.core.GuiSettings; import seedu.address.commons.core.LogsCenter; +import seedu.address.model.budget.Budget; +import seedu.address.model.budget.BudgetList; +import seedu.address.model.budget.ReadOnlyBudgetList; import seedu.address.model.expense.Expense; /** @@ -20,25 +23,30 @@ public class ModelManager implements Model { private static final Logger logger = LogsCenter.getLogger(ModelManager.class); private final ExpenseList expenseList; + private final BudgetList budgetList; private final UserPrefs userPrefs; private final FilteredList filteredExpenses; + private final FilteredList filteredBudgets; /** * Initializes a ModelManager with the given expenseList and userPrefs. */ - public ModelManager(ReadOnlyExpenseList expenseList, ReadOnlyUserPrefs userPrefs) { + public ModelManager(ReadOnlyExpenseList expenseList, ReadOnlyBudgetList budgetList, ReadOnlyUserPrefs userPrefs) { super(); requireAllNonNull(expenseList, userPrefs); - logger.fine("Initializing with expense list: " + expenseList + " and user prefs " + userPrefs); + logger.fine("Initializing with expense list: " + expenseList + ", user prefs " + userPrefs + + " budget list: " + budgetList); this.expenseList = new ExpenseList(expenseList); + this.budgetList = new BudgetList(budgetList); this.userPrefs = new UserPrefs(userPrefs); filteredExpenses = new FilteredList<>(this.expenseList.getExpenseList()); + filteredBudgets = new FilteredList<>(this.budgetList.getBudgetList()); } public ModelManager() { - this(new ExpenseList(), new UserPrefs()); + this(new ExpenseList(), new BudgetList(), new UserPrefs()); } //=========== UserPrefs ================================================================================== @@ -76,6 +84,17 @@ public void setExpenseListFilePath(Path expenseListFilePath) { userPrefs.setExpenseListFilePath(expenseListFilePath); } + @Override + public Path getBudgetListFilePath() { + return userPrefs.getBudgetListFilePath(); + } + + @Override + public void setBudgetListFilePath(Path budgetListFilePath) { + requireNonNull(budgetListFilePath); + userPrefs.setBudgetListFilePath(budgetListFilePath); + } + //=========== ExpenseList ================================================================================ @Override @@ -116,7 +135,7 @@ public void setExpense(Expense target, Expense editedExpense) { /** * Returns an unmodifiable view of the list of {@code Expense} backed by the internal list of - * {@code versionedAddressBook} + * {@code versionedExpenseList} */ @Override public ObservableList getFilteredExpenseList() { @@ -148,4 +167,57 @@ public boolean equals(Object obj) { && filteredExpenses.equals(other.filteredExpenses); } + //=========== BudgetList ================================================================================ + + @Override + public void setBudgetList(ReadOnlyBudgetList budgetList) { + this.budgetList.resetData(budgetList); + } + + @Override + public ReadOnlyBudgetList getBudgetList() { + return budgetList; + } + + @Override + public boolean hasBudget(Budget budget) { + requireNonNull(budget); + return budgetList.hasBudget(budget); + } + + @Override + public void deleteBudget(Budget target) { + budgetList.removeBudget(target); + } + + @Override + public void addBudget(Budget budget) { + budgetList.addBudget(budget); + updateFilteredBudgetList(PREDICATE_SHOW_ALL_BUDGETS); + } + + @Override + public void setBudget(Budget target, Budget editedBudget) { + requireAllNonNull(target, editedBudget); + + budgetList.setBudget(target, editedBudget); + } + + //=========== Filtered Budget List Accessors ============================================================= + + /** + * Returns an unmodifiable view of the list of {@code Budget} backed by the internal list of + * {@code versionedExpenseList} + */ + @Override + public ObservableList getFilteredBudgetList() { + return filteredBudgets; + } + + @Override + public void updateFilteredBudgetList(Predicate predicate) { + requireNonNull(predicate); + filteredBudgets.setPredicate(predicate); + } + } diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/seedu/address/model/UserPrefs.java index 0826d1221fd..65a103a18e7 100644 --- a/src/main/java/seedu/address/model/UserPrefs.java +++ b/src/main/java/seedu/address/model/UserPrefs.java @@ -15,6 +15,7 @@ public class UserPrefs implements ReadOnlyUserPrefs { private GuiSettings guiSettings = new GuiSettings(); private Path expenseListFilePath = Paths.get("data", "expenselist.json"); + private Path budgetListFilePath = Paths.get("data", "budgetlist.json"); /** * Creates a {@code UserPrefs} with default values. @@ -57,6 +58,15 @@ public void setExpenseListFilePath(Path expenseListFilePath) { this.expenseListFilePath = expenseListFilePath; } + public Path getBudgetListFilePath() { + return budgetListFilePath; + } + + public void setBudgetListFilePath(Path budgetListFilePath) { + requireNonNull(budgetListFilePath); + this.budgetListFilePath = budgetListFilePath; + } + @Override public boolean equals(Object other) { if (other == this) { @@ -69,12 +79,13 @@ public boolean equals(Object other) { UserPrefs o = (UserPrefs) other; return guiSettings.equals(o.guiSettings) - && expenseListFilePath.equals(o.expenseListFilePath); + && expenseListFilePath.equals(o.expenseListFilePath) + && budgetListFilePath.equals(o.budgetListFilePath); } @Override public int hashCode() { - return Objects.hash(guiSettings, expenseListFilePath); + return Objects.hash(guiSettings, expenseListFilePath, budgetListFilePath); } @Override @@ -82,6 +93,7 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Gui Settings : " + guiSettings); sb.append("\nLocal data file location : " + expenseListFilePath); + sb.append("\n " + budgetListFilePath); return sb.toString(); } } diff --git a/src/main/java/seedu/address/model/budget/Budget.java b/src/main/java/seedu/address/model/budget/Budget.java new file mode 100644 index 00000000000..ce061e5d533 --- /dev/null +++ b/src/main/java/seedu/address/model/budget/Budget.java @@ -0,0 +1,143 @@ +package seedu.address.model.budget; + +import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; + +import java.time.LocalDate; +import java.util.Collections; +import java.util.Objects; + +import seedu.address.model.ExpenseList; +import seedu.address.model.expense.Amount; +import seedu.address.model.expense.Date; +import seedu.address.model.expense.Expense; +import seedu.address.model.expense.Name; +import seedu.address.model.tag.Tag; + +/** + * Represents an expense in the expense list. + * Guarantees: details are present and not null, field values are validated, immutable. + */ +public class Budget { + + // Identity fields + private final Name name; + + // Data Fields + private final Date startDate; + private final Date endDate; + private final Amount amount; + private Amount amountLeft; + + // Expense List + private final ExpenseList expenseList; + + /** + * Every field must be present and not null. + */ + public Budget(Name name, Amount amount, Date startDate, Date endDate) { + requireAllNonNull(name, amount, startDate, endDate); + this.name = name; + this.amount = amount; + this.amountLeft = amount; + this.startDate = startDate; + this.endDate = endDate; + this.expenseList = new ExpenseList(); + } + + public Name getName() { + return name; + } + + public Amount getAmount() { + return amount; + } + + public Amount getAmountLeft() { + return amountLeft; + } + + public Date getStartDate() { + return startDate; + } + + public Date getEndDate() { + return endDate; + } + + public ExpenseList getExpenseList() { return expenseList; } + + public void addExpenseIntoBudget(Expense expense) { + expenseList.addExpense(expense); + deductAmountLeft(expense); + } + + public boolean budgetHasExpense(Expense expense) { + return expenseList.hasExpense(expense); + } + + public boolean isDateWithinBudgetPeriod(Date date) { + return !date.localDate.isBefore(startDate.localDate) && !date.localDate.isAfter(endDate.localDate); + } + + public void deductAmountLeft(Expense expense) { + double amountLeft = this.amountLeft.getValue(); + amountLeft -= expense.getAmount().getValue(); + this.amountLeft = new Amount("" + amountLeft); + } + + + /** + * Returns true if both budgets have the same name. + * This defines a weaker notion of equality between two budgets. + */ + public boolean isSameBudget(Budget otherBudget) { + if (otherBudget == this) { + return true; + } + + return otherBudget != null + && otherBudget.getName().equals(getName()); + } + + /** + * Returns true if both budgets have the same identity and data fields. + * This defines a stronger notion of equality between two budgets. + */ + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof Budget)) { + return false; + } + + Budget otherBudget = (Budget) other; + return otherBudget.getName().equals(getName()) + && otherBudget.getAmount().equals(getAmount()) + && otherBudget.getStartDate().equals(getStartDate()) + && otherBudget.getEndDate().equals(getEndDate()); + } + + @Override + public int hashCode() { + // use this method for custom fields hashing instead of implementing your own + return Objects.hash(name, amount, startDate, endDate); + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("\n") + .append(getName()) + .append(" ") + .append(getAmount()) + .append("\n") + .append(getStartDate()) + .append("\n") + .append(getEndDate()) + .append("\n"); + return builder.toString(); + } +} diff --git a/src/main/java/seedu/address/model/budget/BudgetList.java b/src/main/java/seedu/address/model/budget/BudgetList.java new file mode 100644 index 00000000000..74a0e917a96 --- /dev/null +++ b/src/main/java/seedu/address/model/budget/BudgetList.java @@ -0,0 +1,149 @@ +package seedu.address.model.budget; + +import static java.util.Objects.requireNonNull; + +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; +import seedu.address.model.Model; + +import javafx.collections.ObservableList; +import java.util.Date; +import seedu.address.model.expense.Expense; + +/** + * Wraps all data at the budgetList level + * Duplicates are not allowed (by .isSameBudget comparison) + */ +public class BudgetList implements ReadOnlyBudgetList { + + private static UniqueBudgetList budgets; + + /* + * The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication + * between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html + * + * Note that non-static init blocks are not recommended to use. There are other ways to avoid duplication + * among constructors. + */ { + budgets = new UniqueBudgetList(); + } + + public BudgetList() { + } + + /** + * Creates an BudgetList using the Budgets in the {@code toBeCopied} + */ + public BudgetList(ReadOnlyBudgetList toBeCopied) { + this(); + resetData(toBeCopied); + } + + //// list overwrite operations + + /** + * Replaces the contents of the budget list with {@code budgets}. + * {@code budgets} must not contain duplicate budgets. + */ + public void setBudgets(List budgets) { + this.budgets.setBudgets(budgets); + } + + /** + * Resets the existing data of this {@code BudgetList} with {@code newData}. + */ + public void resetData(ReadOnlyBudgetList newData) { + requireNonNull(newData); + + setBudgets(newData.getBudgetList()); + } + + //// budget-level operations + + /** + * Returns true if a budget with the same identity as {@code budget} exists in the budget list. + */ + public boolean hasBudget(Budget budget) { + requireNonNull(budget); + return budgets.contains(budget); + } + + /** + * Adds a budget to the budget list. + * The budget must not already exist in the budget list. + */ + public void addBudget(Budget p) { + budgets.add(p); + } + + /** + * Replaces the given budget {@code target} in the list with {@code editedBudget}. + * {@code target} must exist in the budget list. + * The budget identity of {@code editedBudget} must not be the same as another existing budget in the budget + * list. + */ + public void setBudget(Budget target, Budget editedBudget) { + requireNonNull(editedBudget); + + budgets.setBudget(target, editedBudget); + } + + /** + * Removes {@code key} from this {@code BudgetList}. + * {@code key} must exist in the budget list. + */ + public void removeBudget(Budget key) { + budgets.remove(key); + } + + //// util methods + + public static Optional getBudgetExpenseFallsInto(Expense expense) { + Optional toReturn = Optional.empty(); + List lastShownList = budgets.asUnmodifiableObservableList(); + for (Budget budget : lastShownList) { + if (budget.isDateWithinBudgetPeriod(expense.getDate())) { + toReturn = Optional.of(budget); + break; + } + } + return toReturn; + } + + public static boolean checkInputBudgetPeriodClashWithCurrentBudgets(Budget newBudget) { + List lastShownList = budgets.asUnmodifiableObservableList(); + for (Budget budget : lastShownList) { + if (budget.isDateWithinBudgetPeriod(newBudget.getStartDate()) + || budget.isDateWithinBudgetPeriod(newBudget.getEndDate())) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return budgets.asUnmodifiableObservableList().size() + " budgets"; + // TODO: refine later + } + + @Override + public ObservableList getBudgetList() { + return budgets.asUnmodifiableObservableList(); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof BudgetList // instanceof handles nulls + && budgets.equals(((BudgetList) other).budgets)); + } + + + + @Override + public int hashCode() { + return budgets.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/budget/ReadOnlyBudgetList.java b/src/main/java/seedu/address/model/budget/ReadOnlyBudgetList.java new file mode 100644 index 00000000000..cb520f48fc8 --- /dev/null +++ b/src/main/java/seedu/address/model/budget/ReadOnlyBudgetList.java @@ -0,0 +1,15 @@ +package seedu.address.model.budget; + +import javafx.collections.ObservableList; + +/** + * Unmodifiable view of an expense list + */ +public interface ReadOnlyBudgetList { + + /** + * Returns an unmodifiable view of the expenses list. + * This list will not contain any duplicate expenses. + */ + ObservableList getBudgetList(); +} diff --git a/src/main/java/seedu/address/model/budget/UniqueBudgetList.java b/src/main/java/seedu/address/model/budget/UniqueBudgetList.java new file mode 100644 index 00000000000..e304521d510 --- /dev/null +++ b/src/main/java/seedu/address/model/budget/UniqueBudgetList.java @@ -0,0 +1,139 @@ +package seedu.address.model.budget; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; + +import java.util.Iterator; +import java.util.List; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import seedu.address.model.budget.exceptions.DuplicateBudgetException; +import seedu.address.model.budget.exceptions.BudgetNotFoundException; + +/** + * A list of budgets that enforces uniqueness between its elements and does not allow nulls. + * A budget is considered unique by comparing using {@code Budget#isSameBudget(Budget)}. As such, adding and + * updating of + * budgets uses Budget#isSameBudget(Budget) for equality so as to ensure that the budget being added or updated is + * unique in terms of identity in the UniqueBudgetList. However, the removal of a budget uses Budget#equals + * (Object) so + * as to ensure that the budget with exactly the same fields will be removed. + *

+ * Supports a minimal set of list operations. + * + * @see Budget#isSameBudget(Budget) + */ +public class UniqueBudgetList implements Iterable { + + private final ObservableList internalList = FXCollections.observableArrayList(); + private final ObservableList internalUnmodifiableList = + FXCollections.unmodifiableObservableList(internalList); + + /** + * Returns true if the list contains an equivalent budget as the given argument. + */ + public boolean contains(Budget toCheck) { + requireNonNull(toCheck); + return internalList.stream().anyMatch(toCheck::isSameBudget); + } + + /** + * Adds a budget to the list. + * The budget must not already exist in the list. + */ + public void add(Budget toAdd) { + requireNonNull(toAdd); + if (contains(toAdd)) { + throw new DuplicateBudgetException(); + } + internalList.add(toAdd); + } + + /** + * Replaces the budget {@code target} in the list with {@code editedBudget}. + * {@code target} must exist in the list. + * The budget identity of {@code editedBudget} must not be the same as another existing budget in the list. + */ + public void setBudget(Budget target, Budget editedBudget) { + requireAllNonNull(target, editedBudget); + + int index = internalList.indexOf(target); + if (index == -1) { + throw new BudgetNotFoundException(); + } + + if (!target.isSameBudget(editedBudget) && contains(editedBudget)) { + throw new DuplicateBudgetException(); + } + + internalList.set(index, editedBudget); + } + + /** + * Removes the equivalent budget from the list. + * The budget must exist in the list. + */ + public void remove(Budget toRemove) { + requireNonNull(toRemove); + if (!internalList.remove(toRemove)) { + throw new BudgetNotFoundException(); + } + } + + public void setBudgets(UniqueBudgetList replacement) { + requireNonNull(replacement); + internalList.setAll(replacement.internalList); + } + + /** + * Replaces the contents of this list with {@code budgets}. + * {@code budgets} must not contain duplicate budgets. + */ + public void setBudgets(List budgets) { + requireAllNonNull(budgets); + if (!budgetsAreUnique(budgets)) { + throw new DuplicateBudgetException(); + } + + internalList.setAll(budgets); + } + + /** + * Returns the backing list as an unmodifiable {@code ObservableList}. + */ + public ObservableList asUnmodifiableObservableList() { + return internalUnmodifiableList; + } + + @Override + public Iterator iterator() { + return internalList.iterator(); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof UniqueBudgetList // instanceof handles nulls + && internalList.equals(((UniqueBudgetList) other).internalList)); + } + + @Override + public int hashCode() { + return internalList.hashCode(); + } + + /** + * Returns true if {@code budgets} contains only unique budgets. + */ + private boolean budgetsAreUnique(List budgets) { + for (int i = 0; i < budgets.size() - 1; i++) { + for (int j = i + 1; j < budgets.size(); j++) { + if (budgets.get(i).isSameBudget(budgets.get(j))) { + return false; + } + } + } + return true; + } +} diff --git a/src/main/java/seedu/address/model/budget/exceptions/BudgetNotFoundException.java b/src/main/java/seedu/address/model/budget/exceptions/BudgetNotFoundException.java new file mode 100644 index 00000000000..daf71584654 --- /dev/null +++ b/src/main/java/seedu/address/model/budget/exceptions/BudgetNotFoundException.java @@ -0,0 +1,6 @@ +package seedu.address.model.budget.exceptions; + +/** + * Signals that the operation is unable to find the specified budget. + */ +public class BudgetNotFoundException extends RuntimeException {} diff --git a/src/main/java/seedu/address/model/budget/exceptions/DuplicateBudgetException.java b/src/main/java/seedu/address/model/budget/exceptions/DuplicateBudgetException.java new file mode 100644 index 00000000000..e20dc64865b --- /dev/null +++ b/src/main/java/seedu/address/model/budget/exceptions/DuplicateBudgetException.java @@ -0,0 +1,11 @@ +package seedu.address.model.budget.exceptions; + +/** + * Signals that the operation will result in duplicate Budgets + * (Budgets are considered duplicates if they have the same identity). + */ +public class DuplicateBudgetException extends RuntimeException { + public DuplicateBudgetException() { + super("Operation would result in duplicate budgets"); + } +} diff --git a/src/main/java/seedu/address/model/expense/Amount.java b/src/main/java/seedu/address/model/expense/Amount.java index ea7e47f3e88..0aab01fdde8 100644 --- a/src/main/java/seedu/address/model/expense/Amount.java +++ b/src/main/java/seedu/address/model/expense/Amount.java @@ -33,6 +33,10 @@ public static boolean isValidAmount(String test) { return test.matches(VALIDATION_REGEX); } + public double getValue() { + return Double.parseDouble(value.replaceAll("[^\\d.]","")); + } + @Override public String toString() { return value; diff --git a/src/main/java/seedu/address/model/expense/Date.java b/src/main/java/seedu/address/model/expense/Date.java index 1e1fa84a6b5..0b379bcc9cb 100644 --- a/src/main/java/seedu/address/model/expense/Date.java +++ b/src/main/java/seedu/address/model/expense/Date.java @@ -33,6 +33,7 @@ public class Date { public final String value; public final String rawValue; + public final LocalDate localDate; /** * Constructs an {@code Date}. @@ -40,6 +41,7 @@ public class Date { public Date() { rawValue = null; value = null; + localDate = null; } /** @@ -52,6 +54,9 @@ public Date(String date) { checkArgument(isValidDate(date), MESSAGE_CONSTRAINTS); rawValue = date; value = convertDate(date); + localDate = value.length() > 11 + ? LocalDate.parse(value, DateTimeFormatter.ofPattern("dd MMM yyyy, H:mma")) + : LocalDate.parse(value, DateTimeFormatter.ofPattern("dd MMM yyyy")); } /** @@ -65,6 +70,9 @@ public Date(String rawDate, boolean ifConverted) { checkArgument(isValidDate(rawDate), MESSAGE_CONSTRAINTS); rawValue = rawDate; value = ifConverted ? convertDate(rawDate) : rawDate; + localDate = value.length() > 11 + ? LocalDate.parse(value, DateTimeFormatter.ofPattern("dd MMM yyyy, H:mma")) + : LocalDate.parse(value, DateTimeFormatter.ofPattern("dd MMM yyyy")); } /** diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java index d1802ae22f2..c2f49756c49 100644 --- a/src/main/java/seedu/address/model/util/SampleDataUtil.java +++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java @@ -6,6 +6,9 @@ import seedu.address.model.ExpenseList; import seedu.address.model.ReadOnlyExpenseList; +import seedu.address.model.budget.Budget; +import seedu.address.model.budget.BudgetList; +import seedu.address.model.budget.ReadOnlyBudgetList; import seedu.address.model.expense.Amount; import seedu.address.model.expense.Date; import seedu.address.model.expense.Expense; @@ -42,6 +45,13 @@ public static ReadOnlyExpenseList getSampleExpenseList() { return sampleEl; } + public static ReadOnlyBudgetList getSampleBudgetList() { + BudgetList sampleB1 = new BudgetList(); + sampleB1.addBudget(new Budget(new Name("Japan Travel"), new Amount("$2000.00"), + new Date("12/12/2019"), new Date("18/12/2019"))); + return sampleB1; + } + /** * Returns a tag set containing the list of strings given. */ diff --git a/src/main/java/seedu/address/storage/BudgetListStorage.java b/src/main/java/seedu/address/storage/BudgetListStorage.java new file mode 100644 index 00000000000..b45a5e9840d --- /dev/null +++ b/src/main/java/seedu/address/storage/BudgetListStorage.java @@ -0,0 +1,47 @@ +package seedu.address.storage; + +import seedu.address.commons.exceptions.DataConversionException; +import seedu.address.model.budget.BudgetList; +import seedu.address.model.budget.ReadOnlyBudgetList; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; + +/** + * Represents a storage for {@link BudgetList}. + */ +public interface BudgetListStorage { + + /** + * Returns the file path of the data file. + */ + Path getBudgetListFilePath(); + + /** + * Returns BudgetList data as a {@link ReadOnlyBudgetList}. + * Returns {@code Optional.empty()} if storage file is not found. + * + * @throws DataConversionException if the data in storage is not in the expected format. + * @throws IOException if there was any problem when reading from the storage. + */ + Optional readBudgetList() throws DataConversionException, IOException; + + /** + * @see #getBudgetListFilePath() + */ + Optional readBudgetList(Path filePath) throws DataConversionException, IOException; + + /** + * Saves the given {@link ReadOnlyBudgetList} to the storage. + * + * @param budgetList cannot be null. + * @throws IOException if there was any problem writing to the file. + */ + void saveBudgetList(ReadOnlyBudgetList budgetList) throws IOException; + + /** + * @see #saveBudgetList(ReadOnlyBudgetList) + */ + void saveBudgetList(ReadOnlyBudgetList budgetList, Path filePath) throws IOException; +} diff --git a/src/main/java/seedu/address/storage/JsonAdaptedBudget.java b/src/main/java/seedu/address/storage/JsonAdaptedBudget.java new file mode 100644 index 00000000000..c798a84eed6 --- /dev/null +++ b/src/main/java/seedu/address/storage/JsonAdaptedBudget.java @@ -0,0 +1,104 @@ +package seedu.address.storage; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.ExpenseList; +import seedu.address.model.expense.Amount; +import seedu.address.model.expense.Date; +import seedu.address.model.budget.Budget; +import seedu.address.model.expense.Name; +import seedu.address.model.tag.Tag; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Jackson-friendly version of {@link Budget}. + */ +class JsonAdaptedBudget { + + public static final String MISSING_FIELD_MESSAGE_FORMAT = "%s field of a budget is missing!"; + + private final String name; + private final String amount; + private final String amountLeft; + private final String startDate; + private final String endDate; + private final JsonSerializableExpenseList expenseList; + + /** + * Constructs a {@code JsonAdaptedBudget} with the given budget details. + */ + @JsonCreator + public JsonAdaptedBudget(@JsonProperty("name") String name, @JsonProperty("amount") String amount, + @JsonProperty("amountLeft") String amountLeft, + @JsonProperty("startDate") String startDate, + @JsonProperty("endDate") String endDate, + @JsonProperty("expenseList") JsonSerializableExpenseList expenseList) { + this.name = name; + this.amount = amount; + this.amountLeft = amountLeft; + this.startDate = startDate; + this.endDate = endDate; + this.expenseList = expenseList; + } + + /** + * Converts a given {@code Budget} into this class for Jackson use. + */ + public JsonAdaptedBudget(Budget source) { + name = source.getName().fullName; + amount = source.getAmount().value; + amountLeft = source.getAmountLeft().value; + startDate = source.getStartDate().rawValue; + endDate = source.getEndDate().rawValue; + expenseList = new JsonSerializableExpenseList(source.getExpenseList()); + } + + /** + * Converts this Jackson-friendly adapted budget object into the model's {@code Budget} object. + * + * @throws IllegalValueException if there were any data constraints violated in the adapted budget. + */ + public Budget toModelType() throws IllegalValueException { + if (name == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName())); + } + if (!Name.isValidName(name)) { + throw new IllegalValueException(Name.MESSAGE_CONSTRAINTS); + } + final Name modelName = new Name(name); + + if (amount == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Amount.class.getSimpleName())); + } + if (!Amount.isValidAmount(amount)) { + throw new IllegalValueException(Amount.MESSAGE_CONSTRAINTS); + } + final Amount modelAmount = new Amount(amount); + + if (startDate == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Date.class.getSimpleName())); + } + if (!Date.isValidDate(startDate)) { + throw new IllegalValueException(Date.MESSAGE_CONSTRAINTS); + } + final Date modelStartDate = new Date(startDate); + + if (endDate == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Date.class.getSimpleName())); + } + if (!Date.isValidDate(endDate)) { + throw new IllegalValueException(Date.MESSAGE_CONSTRAINTS); + } + final Date modelEndDate = new Date(endDate); + + return new Budget(modelName, modelAmount, modelStartDate, modelEndDate); + + // need to do for budget expenselist also + } +} diff --git a/src/main/java/seedu/address/storage/JsonBudgetListStorage.java b/src/main/java/seedu/address/storage/JsonBudgetListStorage.java new file mode 100644 index 00000000000..6120ab45cb5 --- /dev/null +++ b/src/main/java/seedu/address/storage/JsonBudgetListStorage.java @@ -0,0 +1,80 @@ +package seedu.address.storage; + +import seedu.address.commons.core.LogsCenter; +import seedu.address.commons.exceptions.DataConversionException; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.commons.util.FileUtil; +import seedu.address.commons.util.JsonUtil; +import seedu.address.model.budget.ReadOnlyBudgetList; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; +import java.util.logging.Logger; + +import static java.util.Objects.requireNonNull; + +/** + * A class to access BudgetList data stored as a json file on the hard disk. + */ +public class JsonBudgetListStorage implements BudgetListStorage { + + private static final Logger logger = LogsCenter.getLogger(JsonBudgetListStorage.class); + + private Path filePath; + + public JsonBudgetListStorage(Path filePath) { + this.filePath = filePath; + } + + public Path getBudgetListFilePath() { + return filePath; + } + + @Override + public Optional readBudgetList() throws DataConversionException { + return readBudgetList(filePath); + } + + /** + * Similar to {@link #readBudgetList()}. + * + * @param filePath location of the data. Cannot be null. + * @throws DataConversionException if the file is not in the correct format. + */ + public Optional readBudgetList(Path filePath) throws DataConversionException { + requireNonNull(filePath); + + Optional jsonBudgetList = JsonUtil.readJsonFile( + filePath, JsonSerializableBudgetList.class); + if (!jsonBudgetList.isPresent()) { + return Optional.empty(); + } + + try { + return Optional.of(jsonBudgetList.get().toModelType()); + } catch (IllegalValueException ive) { + logger.info("Illegal values found in " + filePath + ": " + ive.getMessage()); + throw new DataConversionException(ive); + } + } + + @Override + public void saveBudgetList(ReadOnlyBudgetList addressBook) throws IOException { + saveBudgetList(addressBook, filePath); + } + + /** + * Similar to {@link #saveBudgetList(ReadOnlyBudgetList)}. + * + * @param filePath location of the data. Cannot be null. + */ + public void saveBudgetList(ReadOnlyBudgetList budgetList, Path filePath) throws IOException { + requireNonNull(budgetList); + requireNonNull(filePath); + + FileUtil.createIfMissing(filePath); + JsonUtil.saveJsonFile(new JsonSerializableBudgetList(budgetList), filePath); + } + +} diff --git a/src/main/java/seedu/address/storage/JsonSerializableBudgetList.java b/src/main/java/seedu/address/storage/JsonSerializableBudgetList.java new file mode 100644 index 00000000000..f29f6c58333 --- /dev/null +++ b/src/main/java/seedu/address/storage/JsonSerializableBudgetList.java @@ -0,0 +1,58 @@ +package seedu.address.storage; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonRootName; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.budget.BudgetList; +import seedu.address.model.budget.ReadOnlyBudgetList; +import seedu.address.model.budget.Budget; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * An Immutable BudgetList that is serializable to JSON format. + */ +@JsonRootName(value = "budgetlist") +class JsonSerializableBudgetList { + + public static final String MESSAGE_DUPLICATE_EXPENSE = "Budgets list contains duplicate budget(s)."; + + private final List budgets = new ArrayList<>(); + + /** + * Constructs a {@code JsonSerializableBudgetList} with the given budgets. + */ + @JsonCreator + public JsonSerializableBudgetList(@JsonProperty("budgets") List budgets) { + this.budgets.addAll(budgets); + } + + /** + * Converts a given {@code ReadOnlyBudgetList} into this class for Jackson use. + * + * @param source future changes to this will not affect the created {@code JsonSerializableBudgetList}. + */ + public JsonSerializableBudgetList(ReadOnlyBudgetList source) { + budgets.addAll(source.getBudgetList().stream().map(JsonAdaptedBudget::new).collect(Collectors.toList())); + } + + /** + * Converts this address book into the model's {@code BudgetList} object. + * + * @throws IllegalValueException if there were any data constraints violated. + */ + public BudgetList toModelType() throws IllegalValueException { + BudgetList budgetList = new BudgetList(); + for (JsonAdaptedBudget jsonAdaptedBudget : budgets) { + Budget budget = jsonAdaptedBudget.toModelType(); + if (budgetList.hasBudget(budget)) { + throw new IllegalValueException(MESSAGE_DUPLICATE_EXPENSE); + } + budgetList.addBudget(budget); + } + return budgetList; + } +} diff --git a/src/main/java/seedu/address/storage/Storage.java b/src/main/java/seedu/address/storage/Storage.java index 810a4445012..09f914a16fa 100644 --- a/src/main/java/seedu/address/storage/Storage.java +++ b/src/main/java/seedu/address/storage/Storage.java @@ -8,11 +8,12 @@ import seedu.address.model.ReadOnlyExpenseList; import seedu.address.model.ReadOnlyUserPrefs; import seedu.address.model.UserPrefs; +import seedu.address.model.budget.ReadOnlyBudgetList; /** * API of the Storage component */ -public interface Storage extends ExpenseListStorage, UserPrefsStorage { +public interface Storage extends ExpenseListStorage, BudgetListStorage, UserPrefsStorage { @Override Optional readUserPrefs() throws DataConversionException, IOException; @@ -27,6 +28,14 @@ public interface Storage extends ExpenseListStorage, UserPrefsStorage { Optional readExpenseList() throws DataConversionException, IOException; @Override - void saveExpenseList(ReadOnlyExpenseList addressBook) throws IOException; + void saveExpenseList(ReadOnlyExpenseList expenseList) throws IOException; + @Override + Path getBudgetListFilePath(); + + @Override + Optional readBudgetList() throws DataConversionException, IOException; + + @Override + void saveBudgetList(ReadOnlyBudgetList budgetList) throws IOException; } diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/seedu/address/storage/StorageManager.java index 72ea17c6048..bc4dab9fde4 100644 --- a/src/main/java/seedu/address/storage/StorageManager.java +++ b/src/main/java/seedu/address/storage/StorageManager.java @@ -10,6 +10,7 @@ import seedu.address.model.ReadOnlyExpenseList; import seedu.address.model.ReadOnlyUserPrefs; import seedu.address.model.UserPrefs; +import seedu.address.model.budget.ReadOnlyBudgetList; /** * Manages storage of ExpenseList data in local storage. @@ -18,12 +19,15 @@ public class StorageManager implements Storage { private static final Logger logger = LogsCenter.getLogger(StorageManager.class); private ExpenseListStorage expenseListStorage; + private BudgetListStorage budgetListStorage; private UserPrefsStorage userPrefsStorage; - public StorageManager(ExpenseListStorage expenseListStorage, UserPrefsStorage userPrefsStorage) { + public StorageManager(ExpenseListStorage expenseListStorage, + BudgetListStorage budgetListStorage, UserPrefsStorage userPrefsStorage) { super(); this.expenseListStorage = expenseListStorage; + this.budgetListStorage = budgetListStorage; this.userPrefsStorage = userPrefsStorage; } @@ -74,4 +78,33 @@ public void saveExpenseList(ReadOnlyExpenseList expenseList, Path filePath) thro expenseListStorage.saveExpenseList(expenseList, filePath); } + // ================ BudgetList methods ============================== + + @Override + public Path getBudgetListFilePath() { + return budgetListStorage.getBudgetListFilePath(); + } + + @Override + public Optional readBudgetList() throws DataConversionException, IOException { + return readBudgetList(budgetListStorage.getBudgetListFilePath()); + } + + @Override + public Optional readBudgetList(Path filePath) throws DataConversionException, IOException { + logger.fine("Attempting to read data from file: " + filePath); + return budgetListStorage.readBudgetList(filePath); + } + + @Override + public void saveBudgetList(ReadOnlyBudgetList budgetList) throws IOException { + saveBudgetList(budgetList, budgetListStorage.getBudgetListFilePath()); + } + + @Override + public void saveBudgetList(ReadOnlyBudgetList budgetList, Path filePath) throws IOException { + logger.fine("Attempting to write to data file: " + filePath); + budgetListStorage.saveBudgetList(budgetList, filePath); + } + } From 7db015d6143b7361f6b9f89ee5f9306a78ad4447 Mon Sep 17 00:00:00 2001 From: choonx99 Date: Tue, 22 Oct 2019 23:31:11 +0800 Subject: [PATCH 5/8] Fixed test cases for add budget --- .../logic/commands/AddBudgetCommand.java | 3 +- .../address/logic/commands/AddCommand.java | 26 ++---- .../logic/parser/AddBudgetCommandParser.java | 4 +- src/main/java/seedu/address/model/Model.java | 26 +++--- .../seedu/address/model/ModelManager.java | 36 +++++++- .../seedu/address/model/budget/Budget.java | 6 +- .../address/model/budget/BudgetList.java | 19 ++--- .../seedu/address/model/expense/Date.java | 5 +- .../address/model/util/SampleDataUtil.java | 4 +- .../address/storage/JsonAdaptedBudget.java | 11 ++- .../storage/JsonSerializableBudgetList.java | 6 +- .../storage/JsonSerializableExpenseList.java | 2 +- .../ExtraValuesUserPref.json | 3 +- .../TypicalUserPref.json | 3 +- .../seedu/address/logic/LogicManagerTest.java | 27 +++++- .../commands/AddCommandIntegrationTest.java | 26 +++++- .../logic/commands/AddCommandTest.java | 68 +++++++++++++++ .../logic/commands/ClearCommandTest.java | 5 +- .../logic/commands/DeleteCommandTest.java | 7 +- .../logic/commands/EditCommandTest.java | 11 +-- .../logic/commands/FindCommandTest.java | 5 +- .../logic/commands/ListCommandTest.java | 5 +- .../seedu/address/model/ModelManagerTest.java | 25 ++++-- .../storage/JsonUserPrefsStorageTest.java | 1 + .../address/storage/StorageManagerTest.java | 3 +- .../seedu/address/testutil/BudgetBuilder.java | 85 +++++++++++++++++++ .../address/testutil/BudgetListBuilder.java | 34 ++++++++ .../address/testutil/TypicalBudgets.java | 43 ++++++++++ 28 files changed, 410 insertions(+), 89 deletions(-) create mode 100644 src/test/java/seedu/address/testutil/BudgetBuilder.java create mode 100644 src/test/java/seedu/address/testutil/BudgetListBuilder.java create mode 100644 src/test/java/seedu/address/testutil/TypicalBudgets.java diff --git a/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java b/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java index bf74f940396..61abde7b256 100644 --- a/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java +++ b/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java @@ -5,7 +5,6 @@ import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE; import static seedu.address.logic.parser.CliSyntax.PREFIX_END_DATE; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; -import static seedu.address.model.budget.BudgetList.checkInputBudgetPeriodClashWithCurrentBudgets; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; @@ -54,7 +53,7 @@ public CommandResult execute(Model model) throws CommandException { throw new CommandException(MESSAGE_START_BEFORE_END); } - if (checkInputBudgetPeriodClashWithCurrentBudgets(toAdd)) { + if (model.hasBudgetPeriodClash(toAdd)) { throw new CommandException(MESSAGE_BUDGET_CLASH); } diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java index 38b8637ffa2..01d97010733 100644 --- a/src/main/java/seedu/address/logic/commands/AddCommand.java +++ b/src/main/java/seedu/address/logic/commands/AddCommand.java @@ -5,15 +5,11 @@ import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; -import static seedu.address.model.budget.BudgetList.getBudgetExpenseFallsInto; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; -import seedu.address.model.budget.Budget; import seedu.address.model.expense.Expense; -import java.util.List; -import java.util.Optional; /** * Adds an expense to the expense list. @@ -52,24 +48,12 @@ public AddCommand(Expense expense) { public CommandResult execute(Model model) throws CommandException { requireNonNull(model); - // check if toAdd falls into any budget period - Optional b = getBudgetExpenseFallsInto(toAdd); - if (b.isPresent()) { - Budget toAddInto = b.get(); - if (toAddInto.budgetHasExpense(toAdd)) { - throw new CommandException(MESSAGE_DUPLICATE_EXPENSE); - } else { - toAddInto.addExpenseIntoBudget(toAdd); - return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); - } - } else { - if (model.hasExpense(toAdd)) { - throw new CommandException(MESSAGE_DUPLICATE_EXPENSE); - } - - model.addExpense(toAdd); - return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + if (model.hasExpense(toAdd)) { + throw new CommandException(MESSAGE_DUPLICATE_EXPENSE); } + + model.addExpense(toAdd); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); } @Override diff --git a/src/main/java/seedu/address/logic/parser/AddBudgetCommandParser.java b/src/main/java/seedu/address/logic/parser/AddBudgetCommandParser.java index 09a158e2eb8..985e56ea5cd 100644 --- a/src/main/java/seedu/address/logic/parser/AddBudgetCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/AddBudgetCommandParser.java @@ -8,9 +8,11 @@ import seedu.address.logic.commands.AddBudgetCommand; import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.ExpenseList; import seedu.address.model.budget.Budget; import seedu.address.model.expense.Amount; import seedu.address.model.expense.Date; +import seedu.address.model.expense.Expense; import seedu.address.model.expense.Name; import java.util.stream.Stream; @@ -40,7 +42,7 @@ public AddBudgetCommand parse(String args) throws ParseException { Date startDate = ParserUtil.parseDate(argMultimap.getValue(PREFIX_DATE).get()); Date endDate = ParserUtil.parseDate(argMultimap.getValue(PREFIX_END_DATE).get()); - Budget budget = new Budget(name, amount, startDate, endDate); + Budget budget = new Budget(name, amount, amount, startDate, endDate, new ExpenseList()); return new AddBudgetCommand(budget); } diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index 304159dd3ff..b3e80af228a 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -1,6 +1,7 @@ package seedu.address.model; import java.nio.file.Path; +import java.util.Optional; import java.util.function.Predicate; import javafx.collections.ObservableList; @@ -47,16 +48,6 @@ public interface Model { */ void setExpenseListFilePath(Path expenseListFilePath); - /** - * Returns the user prefs' budget list file path. - */ - Path getBudgetListFilePath(); - - /** - * Sets the user prefs' budget list file path. - */ - void setBudgetListFilePath(Path expenseListFilePath); - /** * Replaces expense list data with the data in {@code expenseList}. */ @@ -99,6 +90,16 @@ public interface Model { */ void updateFilteredExpenseList(Predicate predicate); + /** + * Returns the user prefs' budget list file path. + */ + Path getBudgetListFilePath(); + + /** + * Sets the user prefs' budget list file path. + */ + void setBudgetListFilePath(Path expenseListFilePath); + /** * Replaces budget list data with the data in {@code budgetList}. */ @@ -141,4 +142,9 @@ public interface Model { */ void updateFilteredBudgetList(Predicate predicate); + boolean hasBudgetPeriodClash(Budget newBudget); + + Optional getBudgetExpenseFallsInto(Expense expense); + + boolean expenseFallsIntoABudget(Expense expense); } diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 45ff4ac6944..6b907532445 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -4,6 +4,7 @@ import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; import java.nio.file.Path; +import java.util.Optional; import java.util.function.Predicate; import java.util.logging.Logger; @@ -110,7 +111,11 @@ public ReadOnlyExpenseList getExpenseList() { @Override public boolean hasExpense(Expense expense) { requireNonNull(expense); - return expenseList.hasExpense(expense); + if (expenseFallsIntoABudget(expense)) { + return getBudgetExpenseFallsInto(expense).get().budgetHasExpense(expense); + } else { + return expenseList.hasExpense(expense); + } } @Override @@ -120,8 +125,12 @@ public void deleteExpense(Expense target) { @Override public void addExpense(Expense expense) { - expenseList.addExpense(expense); - updateFilteredExpenseList(PREDICATE_SHOW_ALL_EXPENSES); + if (expenseFallsIntoABudget(expense)) { + getBudgetExpenseFallsInto(expense).get().addExpenseIntoBudget(expense); + } else { + expenseList.addExpense(expense); + updateFilteredExpenseList(PREDICATE_SHOW_ALL_EXPENSES); + } } @Override @@ -164,7 +173,9 @@ public boolean equals(Object obj) { ModelManager other = (ModelManager) obj; return expenseList.equals(other.expenseList) && userPrefs.equals(other.userPrefs) - && filteredExpenses.equals(other.filteredExpenses); + && filteredExpenses.equals(other.filteredExpenses) + && budgetList.equals(other.budgetList) + && filteredBudgets.equals(other.filteredBudgets); } //=========== BudgetList ================================================================================ @@ -203,6 +214,23 @@ public void setBudget(Budget target, Budget editedBudget) { budgetList.setBudget(target, editedBudget); } + @Override + public Optional getBudgetExpenseFallsInto(Expense expense) { + requireNonNull(expense); + return budgetList.getBudgetExpenseFallsInto(expense); + } + + @Override + public boolean expenseFallsIntoABudget(Expense expense) { + return getBudgetExpenseFallsInto(expense).isPresent(); + } + + @Override + public boolean hasBudgetPeriodClash(Budget budget) { + requireNonNull(budget); + return budgetList.hasBudgetPeriodClash(budget); + } + //=========== Filtered Budget List Accessors ============================================================= /** diff --git a/src/main/java/seedu/address/model/budget/Budget.java b/src/main/java/seedu/address/model/budget/Budget.java index ce061e5d533..e1f9d533d1b 100644 --- a/src/main/java/seedu/address/model/budget/Budget.java +++ b/src/main/java/seedu/address/model/budget/Budget.java @@ -34,14 +34,14 @@ public class Budget { /** * Every field must be present and not null. */ - public Budget(Name name, Amount amount, Date startDate, Date endDate) { + public Budget(Name name, Amount amount, Amount amountLeft, Date startDate, Date endDate, ExpenseList expenseList) { requireAllNonNull(name, amount, startDate, endDate); this.name = name; this.amount = amount; - this.amountLeft = amount; + this.amountLeft = amountLeft; this.startDate = startDate; this.endDate = endDate; - this.expenseList = new ExpenseList(); + this.expenseList = expenseList; } public Name getName() { diff --git a/src/main/java/seedu/address/model/budget/BudgetList.java b/src/main/java/seedu/address/model/budget/BudgetList.java index 74a0e917a96..2194539f904 100644 --- a/src/main/java/seedu/address/model/budget/BudgetList.java +++ b/src/main/java/seedu/address/model/budget/BudgetList.java @@ -2,13 +2,10 @@ import static java.util.Objects.requireNonNull; -import java.time.LocalDate; import java.util.List; import java.util.Optional; -import seedu.address.model.Model; import javafx.collections.ObservableList; -import java.util.Date; import seedu.address.model.expense.Expense; /** @@ -17,7 +14,7 @@ */ public class BudgetList implements ReadOnlyBudgetList { - private static UniqueBudgetList budgets; + private final UniqueBudgetList budgets; /* * The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication @@ -99,9 +96,9 @@ public void removeBudget(Budget key) { //// util methods - public static Optional getBudgetExpenseFallsInto(Expense expense) { + public Optional getBudgetExpenseFallsInto(Expense expense) { Optional toReturn = Optional.empty(); - List lastShownList = budgets.asUnmodifiableObservableList(); + List lastShownList = getBudgetList(); for (Budget budget : lastShownList) { if (budget.isDateWithinBudgetPeriod(expense.getDate())) { toReturn = Optional.of(budget); @@ -111,8 +108,8 @@ public static Optional getBudgetExpenseFallsInto(Expense expense) { return toReturn; } - public static boolean checkInputBudgetPeriodClashWithCurrentBudgets(Budget newBudget) { - List lastShownList = budgets.asUnmodifiableObservableList(); + public boolean hasBudgetPeriodClash(Budget newBudget) { + List lastShownList = getBudgetList(); for (Budget budget : lastShownList) { if (budget.isDateWithinBudgetPeriod(newBudget.getStartDate()) || budget.isDateWithinBudgetPeriod(newBudget.getEndDate())) { @@ -136,12 +133,10 @@ public ObservableList getBudgetList() { @Override public boolean equals(Object other) { return other == this // short circuit if same object - || (other instanceof BudgetList // instanceof handles nulls - && budgets.equals(((BudgetList) other).budgets)); + || (other instanceof BudgetList // instanceof handles nulls + && budgets.equals(((BudgetList) other).budgets)); } - - @Override public int hashCode() { return budgets.hashCode(); diff --git a/src/main/java/seedu/address/model/expense/Date.java b/src/main/java/seedu/address/model/expense/Date.java index 0b379bcc9cb..b22fedb3e14 100644 --- a/src/main/java/seedu/address/model/expense/Date.java +++ b/src/main/java/seedu/address/model/expense/Date.java @@ -70,9 +70,10 @@ public Date(String rawDate, boolean ifConverted) { checkArgument(isValidDate(rawDate), MESSAGE_CONSTRAINTS); rawValue = rawDate; value = ifConverted ? convertDate(rawDate) : rawDate; - localDate = value.length() > 11 + localDate = ifConverted ? value.length() > 11 ? LocalDate.parse(value, DateTimeFormatter.ofPattern("dd MMM yyyy, H:mma")) - : LocalDate.parse(value, DateTimeFormatter.ofPattern("dd MMM yyyy")); + : LocalDate.parse(value, DateTimeFormatter.ofPattern("dd MMM yyyy")) + : LocalDate.parse(value, DateTimeFormatter.ofPattern("dd/MM/yyyy")); } /** diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java index c2f49756c49..0b930a81569 100644 --- a/src/main/java/seedu/address/model/util/SampleDataUtil.java +++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java @@ -47,8 +47,8 @@ public static ReadOnlyExpenseList getSampleExpenseList() { public static ReadOnlyBudgetList getSampleBudgetList() { BudgetList sampleB1 = new BudgetList(); - sampleB1.addBudget(new Budget(new Name("Japan Travel"), new Amount("$2000.00"), - new Date("12/12/2019"), new Date("18/12/2019"))); + sampleB1.addBudget(new Budget(new Name("Japan Travel"), new Amount("$2000.00"), new Amount("$2000.00"), + new Date("12/12/2019"), new Date("18/12/2019"), new ExpenseList())); return sampleB1; } diff --git a/src/main/java/seedu/address/storage/JsonAdaptedBudget.java b/src/main/java/seedu/address/storage/JsonAdaptedBudget.java index c798a84eed6..b0c5aaadcbf 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedBudget.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedBudget.java @@ -7,6 +7,7 @@ import seedu.address.model.expense.Amount; import seedu.address.model.expense.Date; import seedu.address.model.budget.Budget; +import seedu.address.model.expense.Expense; import seedu.address.model.expense.Name; import seedu.address.model.tag.Tag; @@ -81,6 +82,14 @@ public Budget toModelType() throws IllegalValueException { } final Amount modelAmount = new Amount(amount); + if (amountLeft == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Amount.class.getSimpleName())); + } + if (!Amount.isValidAmount(amount)) { + throw new IllegalValueException(Amount.MESSAGE_CONSTRAINTS); + } + final Amount modelAmountLeft = new Amount(amount); + if (startDate == null) { throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Date.class.getSimpleName())); } @@ -97,7 +106,7 @@ public Budget toModelType() throws IllegalValueException { } final Date modelEndDate = new Date(endDate); - return new Budget(modelName, modelAmount, modelStartDate, modelEndDate); + return new Budget(modelName, modelAmount, modelAmountLeft, modelStartDate, modelEndDate, new ExpenseList()); // need to do for budget expenselist also } diff --git a/src/main/java/seedu/address/storage/JsonSerializableBudgetList.java b/src/main/java/seedu/address/storage/JsonSerializableBudgetList.java index f29f6c58333..7a968649a14 100644 --- a/src/main/java/seedu/address/storage/JsonSerializableBudgetList.java +++ b/src/main/java/seedu/address/storage/JsonSerializableBudgetList.java @@ -18,7 +18,7 @@ @JsonRootName(value = "budgetlist") class JsonSerializableBudgetList { - public static final String MESSAGE_DUPLICATE_EXPENSE = "Budgets list contains duplicate budget(s)."; + public static final String MESSAGE_DUPLICATE_BUDGET = "Budgets list contains duplicate budget(s)."; private final List budgets = new ArrayList<>(); @@ -40,7 +40,7 @@ public JsonSerializableBudgetList(ReadOnlyBudgetList source) { } /** - * Converts this address book into the model's {@code BudgetList} object. + * Converts this budget list into the model's {@code BudgetList} object. * * @throws IllegalValueException if there were any data constraints violated. */ @@ -49,7 +49,7 @@ public BudgetList toModelType() throws IllegalValueException { for (JsonAdaptedBudget jsonAdaptedBudget : budgets) { Budget budget = jsonAdaptedBudget.toModelType(); if (budgetList.hasBudget(budget)) { - throw new IllegalValueException(MESSAGE_DUPLICATE_EXPENSE); + throw new IllegalValueException(MESSAGE_DUPLICATE_BUDGET); } budgetList.addBudget(budget); } diff --git a/src/main/java/seedu/address/storage/JsonSerializableExpenseList.java b/src/main/java/seedu/address/storage/JsonSerializableExpenseList.java index bc9034f4e5c..07e89e823a1 100644 --- a/src/main/java/seedu/address/storage/JsonSerializableExpenseList.java +++ b/src/main/java/seedu/address/storage/JsonSerializableExpenseList.java @@ -41,7 +41,7 @@ public JsonSerializableExpenseList(ReadOnlyExpenseList source) { } /** - * Converts this address book into the model's {@code ExpenseList} object. + * Converts this expense list into the model's {@code ExpenseList} object. * * @throws IllegalValueException if there were any data constraints violated. */ diff --git a/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json b/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json index 522eabc71c2..9139e9c8c0d 100644 --- a/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json +++ b/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json @@ -9,5 +9,6 @@ "z" : 99 } }, - "expenseListFilePath" : "expenselist.json" + "expenseListFilePath" : "expenselist.json", + "budgetListFilePath" : "budgetlist.json" } diff --git a/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json b/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json index a7c2aef7532..3b61d16a867 100644 --- a/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json +++ b/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json @@ -7,5 +7,6 @@ "y" : 100 } }, - "expenseListFilePath" : "expenselist.json" + "expenseListFilePath" : "expenselist.json", + "budgetListFilePath" : "budgetlist.json" } diff --git a/src/test/java/seedu/address/logic/LogicManagerTest.java b/src/test/java/seedu/address/logic/LogicManagerTest.java index d6fa8fdd52d..a2ae436eedd 100644 --- a/src/test/java/seedu/address/logic/LogicManagerTest.java +++ b/src/test/java/seedu/address/logic/LogicManagerTest.java @@ -25,7 +25,10 @@ import seedu.address.model.ModelManager; import seedu.address.model.ReadOnlyExpenseList; import seedu.address.model.UserPrefs; +import seedu.address.model.budget.BudgetList; +import seedu.address.model.budget.ReadOnlyBudgetList; import seedu.address.model.expense.Expense; +import seedu.address.storage.JsonBudgetListStorage; import seedu.address.storage.JsonExpenseListStorage; import seedu.address.storage.JsonUserPrefsStorage; import seedu.address.storage.StorageManager; @@ -44,8 +47,10 @@ public class LogicManagerTest { public void setUp() { JsonExpenseListStorage expenseListStorage = new JsonExpenseListStorage(temporaryFolder.resolve("expenseList.json")); + JsonBudgetListStorage budgetListStorage = + new JsonBudgetListStorage(temporaryFolder.resolve("budgetList.json")); JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(temporaryFolder.resolve("userPrefs.json")); - StorageManager storage = new StorageManager(expenseListStorage, userPrefsStorage); + StorageManager storage = new StorageManager(expenseListStorage, budgetListStorage, userPrefsStorage); logic = new LogicManager(model, storage); } @@ -72,9 +77,11 @@ public void execute_storageThrowsIoException_throwsCommandException() { // Setup LogicManager with JsonExpenseListIoExceptionThrowingStub JsonExpenseListStorage expenseListStorage = new JsonExpenseListIoExceptionThrowingStub(temporaryFolder.resolve("ioExceptionExpenseList.json")); + JsonBudgetListStorage budgetListStorage = + new JsonBudgetListIoExceptionThrowingStub(temporaryFolder.resolve("ioExceptionBudgetList.json")); JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(temporaryFolder.resolve("ioExceptionUserPrefs.json")); - StorageManager storage = new StorageManager(expenseListStorage, userPrefsStorage); + StorageManager storage = new StorageManager(expenseListStorage, budgetListStorage, userPrefsStorage); logic = new LogicManager(model, storage); // Execute add command @@ -127,7 +134,7 @@ private void assertCommandException(String inputCommand, String expectedMessage) */ private void assertCommandFailure(String inputCommand, Class expectedException, String expectedMessage) { - Model expectedModel = new ModelManager(model.getExpenseList(), new UserPrefs()); + Model expectedModel = new ModelManager(model.getExpenseList(), new BudgetList(), new UserPrefs()); assertCommandFailure(inputCommand, expectedException, expectedMessage, expectedModel); } @@ -157,4 +164,18 @@ public void saveExpenseList(ReadOnlyExpenseList expenseList, Path filePath) thro throw DUMMY_IO_EXCEPTION; } } + + /** + * A stub class to throw an {@code IOException} when the save method is called. + */ + private static class JsonBudgetListIoExceptionThrowingStub extends JsonBudgetListStorage { + private JsonBudgetListIoExceptionThrowingStub(Path filePath) { + super(filePath); + } + + @Override + public void saveBudgetList(ReadOnlyBudgetList budgetList, Path filePath) throws IOException { + throw DUMMY_IO_EXCEPTION; + } + } } diff --git a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java b/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java index b07c0d6da8e..c92d779bc11 100644 --- a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java +++ b/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java @@ -3,14 +3,19 @@ import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure; import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; import static seedu.address.testutil.TypicalExpenses.getTypicalExpenseList; +import static seedu.address.testutil.TypicalBudgets.getTypicalBudgetList; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import seedu.address.model.ExpenseList; import seedu.address.model.Model; import seedu.address.model.ModelManager; import seedu.address.model.UserPrefs; +import seedu.address.model.budget.Budget; +import seedu.address.model.budget.BudgetList; import seedu.address.model.expense.Expense; +import seedu.address.testutil.BudgetBuilder; import seedu.address.testutil.ExpenseBuilder; /** @@ -22,14 +27,14 @@ public class AddCommandIntegrationTest { @BeforeEach public void setUp() { - model = new ModelManager(getTypicalExpenseList(), new UserPrefs()); + model = new ModelManager(getTypicalExpenseList(), getTypicalBudgetList(), new UserPrefs()); } @Test public void execute_newExpense_success() { Expense validExpense = new ExpenseBuilder().build(); - Model expectedModel = new ModelManager(model.getExpenseList(), new UserPrefs()); + Model expectedModel = new ModelManager(model.getExpenseList(), getTypicalBudgetList(), new UserPrefs()); expectedModel.addExpense(validExpense); assertCommandSuccess(new AddCommand(validExpense), model, @@ -42,4 +47,21 @@ public void execute_duplicateExpense_throwsCommandException() { assertCommandFailure(new AddCommand(expenseInList), model, AddCommand.MESSAGE_DUPLICATE_EXPENSE); } + @Test + public void execute_newBudget_success() { + Budget validBudget = new BudgetBuilder().build(); + + Model expectedModel = new ModelManager(getTypicalExpenseList(), model.getBudgetList(), new UserPrefs()); + expectedModel.addBudget(validBudget); + + assertCommandSuccess(new AddBudgetCommand(validBudget), model, + String.format(AddBudgetCommand.MESSAGE_SUCCESS, validBudget), expectedModel); + } + + @Test + public void execute_clashBudget_throwsCommandException() { + Budget budgetInList = model.getBudgetList().getBudgetList().get(0); + assertCommandFailure(new AddBudgetCommand(budgetInList), model, AddBudgetCommand.MESSAGE_BUDGET_CLASH); + } + } diff --git a/src/test/java/seedu/address/logic/commands/AddCommandTest.java b/src/test/java/seedu/address/logic/commands/AddCommandTest.java index 7f4d0bef5c3..0ee03208fd2 100644 --- a/src/test/java/seedu/address/logic/commands/AddCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/AddCommandTest.java @@ -9,6 +9,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; +import java.util.Optional; import java.util.function.Predicate; import org.junit.jupiter.api.Test; @@ -20,6 +21,8 @@ import seedu.address.model.Model; import seedu.address.model.ReadOnlyExpenseList; import seedu.address.model.ReadOnlyUserPrefs; +import seedu.address.model.budget.Budget; +import seedu.address.model.budget.ReadOnlyBudgetList; import seedu.address.model.expense.Expense; import seedu.address.testutil.ExpenseBuilder; @@ -147,6 +150,71 @@ public ObservableList getFilteredExpenseList() { public void updateFilteredExpenseList(Predicate predicate) { throw new AssertionError("This method should not be called."); } + + @Override + public Path getBudgetListFilePath() { + throw new AssertionError("This method should not be called."); + } + + @Override + public void setBudgetListFilePath(Path budgetListFilePath) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void addBudget(Budget budget) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void setBudgetList(ReadOnlyBudgetList newData) { + throw new AssertionError("This method should not be called."); + } + + @Override + public ReadOnlyBudgetList getBudgetList() { + throw new AssertionError("This method should not be called."); + } + + @Override + public boolean hasBudget(Budget budget) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void deleteBudget(Budget target) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void setBudget(Budget target, Budget editedBudget) { + throw new AssertionError("This method should not be called."); + } + + @Override + public ObservableList getFilteredBudgetList() { + throw new AssertionError("This method should not be called."); + } + + @Override + public void updateFilteredBudgetList(Predicate predicate) { + throw new AssertionError("This method should not be called."); + } + + @Override + public Optional getBudgetExpenseFallsInto(Expense expense) { + throw new AssertionError("This method should not be called."); + } + + @Override + public boolean hasBudgetPeriodClash(Budget budget) { + throw new AssertionError("This method should not be called."); + } + + public boolean expenseFallsIntoABudget(Expense expense) { + throw new AssertionError("This method should not be called."); + } + } /** diff --git a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java b/src/test/java/seedu/address/logic/commands/ClearCommandTest.java index cb242c6802e..07cf88213f7 100644 --- a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/ClearCommandTest.java @@ -9,6 +9,7 @@ import seedu.address.model.Model; import seedu.address.model.ModelManager; import seedu.address.model.UserPrefs; +import seedu.address.model.budget.BudgetList; public class ClearCommandTest { @@ -22,8 +23,8 @@ public void execute_emptyExpenseList_success() { @Test public void execute_nonEmptyExpenseList_success() { - Model model = new ModelManager(getTypicalExpenseList(), new UserPrefs()); - Model expectedModel = new ModelManager(getTypicalExpenseList(), new UserPrefs()); + Model model = new ModelManager(getTypicalExpenseList(), new BudgetList(), new UserPrefs()); + Model expectedModel = new ModelManager(getTypicalExpenseList(), new BudgetList(), new UserPrefs()); expectedModel.setExpenseList(new ExpenseList()); assertCommandSuccess(new ClearCommand(), model, ClearCommand.MESSAGE_SUCCESS, expectedModel); diff --git a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java index 7f348b28046..07ec7ca12a5 100644 --- a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java @@ -16,6 +16,7 @@ import seedu.address.model.Model; import seedu.address.model.ModelManager; import seedu.address.model.UserPrefs; +import seedu.address.model.budget.BudgetList; import seedu.address.model.expense.Expense; /** @@ -24,7 +25,7 @@ */ public class DeleteCommandTest { - private Model model = new ModelManager(getTypicalExpenseList(), new UserPrefs()); + private Model model = new ModelManager(getTypicalExpenseList(), new BudgetList(),new UserPrefs()); @Test public void execute_validIndexUnfilteredList_success() { @@ -33,7 +34,7 @@ public void execute_validIndexUnfilteredList_success() { String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_EXPENSE_SUCCESS, expenseToDelete); - ModelManager expectedModel = new ModelManager(model.getExpenseList(), new UserPrefs()); + ModelManager expectedModel = new ModelManager(model.getExpenseList(), new BudgetList(), new UserPrefs()); expectedModel.deleteExpense(expenseToDelete); assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel); @@ -56,7 +57,7 @@ public void execute_validIndexFilteredList_success() { String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_EXPENSE_SUCCESS, expenseToDelete); - Model expectedModel = new ModelManager(model.getExpenseList(), new UserPrefs()); + Model expectedModel = new ModelManager(model.getExpenseList(), new BudgetList(), new UserPrefs()); expectedModel.deleteExpense(expenseToDelete); showNoExpense(expectedModel); diff --git a/src/test/java/seedu/address/logic/commands/EditCommandTest.java b/src/test/java/seedu/address/logic/commands/EditCommandTest.java index c2ae554cdcc..c4fee751b1e 100644 --- a/src/test/java/seedu/address/logic/commands/EditCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/EditCommandTest.java @@ -23,6 +23,7 @@ import seedu.address.model.Model; import seedu.address.model.ModelManager; import seedu.address.model.UserPrefs; +import seedu.address.model.budget.BudgetList; import seedu.address.model.expense.Expense; import seedu.address.testutil.EditExpenseDescriptorBuilder; import seedu.address.testutil.ExpenseBuilder; @@ -32,7 +33,7 @@ */ public class EditCommandTest { - private Model model = new ModelManager(getTypicalExpenseList(), new UserPrefs()); + private Model model = new ModelManager(getTypicalExpenseList(), new BudgetList(), new UserPrefs()); @Test public void execute_allFieldsSpecifiedUnfilteredList_success() { @@ -42,7 +43,7 @@ public void execute_allFieldsSpecifiedUnfilteredList_success() { String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_EXPENSE_SUCCESS, editedExpense); - Model expectedModel = new ModelManager(new ExpenseList(model.getExpenseList()), new UserPrefs()); + Model expectedModel = new ModelManager(new ExpenseList(model.getExpenseList()), new BudgetList(), new UserPrefs()); expectedModel.setExpense(model.getFilteredExpenseList().get(0), editedExpense); assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); @@ -63,7 +64,7 @@ public void execute_someFieldsSpecifiedUnfilteredList_success() { String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_EXPENSE_SUCCESS, editedExpense); - Model expectedModel = new ModelManager(new ExpenseList(model.getExpenseList()), new UserPrefs()); + Model expectedModel = new ModelManager(new ExpenseList(model.getExpenseList()), new BudgetList(), new UserPrefs()); expectedModel.setExpense(lastExpense, editedExpense); assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); @@ -76,7 +77,7 @@ public void execute_noFieldSpecifiedUnfilteredList_success() { String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_EXPENSE_SUCCESS, editedExpense); - Model expectedModel = new ModelManager(new ExpenseList(model.getExpenseList()), new UserPrefs()); + Model expectedModel = new ModelManager(new ExpenseList(model.getExpenseList()), new BudgetList(), new UserPrefs()); assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); } @@ -92,7 +93,7 @@ public void execute_filteredList_success() { String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_EXPENSE_SUCCESS, editedExpense); - Model expectedModel = new ModelManager(new ExpenseList(model.getExpenseList()), new UserPrefs()); + Model expectedModel = new ModelManager(new ExpenseList(model.getExpenseList()), new BudgetList(), new UserPrefs()); expectedModel.setExpense(model.getFilteredExpenseList().get(0), editedExpense); assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); diff --git a/src/test/java/seedu/address/logic/commands/FindCommandTest.java b/src/test/java/seedu/address/logic/commands/FindCommandTest.java index 0f84809337a..15b9391f3ec 100644 --- a/src/test/java/seedu/address/logic/commands/FindCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/FindCommandTest.java @@ -19,6 +19,7 @@ import seedu.address.model.Model; import seedu.address.model.ModelManager; import seedu.address.model.UserPrefs; +import seedu.address.model.budget.BudgetList; import seedu.address.model.expense.NameContainsKeywordsPredicate; /** @@ -26,8 +27,8 @@ */ public class FindCommandTest { - private Model model = new ModelManager(getTypicalExpenseList(), new UserPrefs()); - private Model expectedModel = new ModelManager(getTypicalExpenseList(), new UserPrefs()); + private Model model = new ModelManager(getTypicalExpenseList(), new BudgetList(), new UserPrefs()); + private Model expectedModel = new ModelManager(getTypicalExpenseList(), new BudgetList(), new UserPrefs()); @Test public void equals() { diff --git a/src/test/java/seedu/address/logic/commands/ListCommandTest.java b/src/test/java/seedu/address/logic/commands/ListCommandTest.java index bcea8b603cf..663447eb2b3 100644 --- a/src/test/java/seedu/address/logic/commands/ListCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/ListCommandTest.java @@ -11,6 +11,7 @@ import seedu.address.model.Model; import seedu.address.model.ModelManager; import seedu.address.model.UserPrefs; +import seedu.address.model.budget.BudgetList; /** * Contains integration tests (interaction with the Model) and unit tests for ListCommand. @@ -22,8 +23,8 @@ public class ListCommandTest { @BeforeEach public void setUp() { - model = new ModelManager(getTypicalExpenseList(), new UserPrefs()); - expectedModel = new ModelManager(model.getExpenseList(), new UserPrefs()); + model = new ModelManager(getTypicalExpenseList(), new BudgetList(), new UserPrefs()); + expectedModel = new ModelManager(model.getExpenseList(), new BudgetList(), new UserPrefs()); } @Test diff --git a/src/test/java/seedu/address/model/ModelManagerTest.java b/src/test/java/seedu/address/model/ModelManagerTest.java index c64864d6aab..43d52156f04 100644 --- a/src/test/java/seedu/address/model/ModelManagerTest.java +++ b/src/test/java/seedu/address/model/ModelManagerTest.java @@ -5,6 +5,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static seedu.address.model.Model.PREDICATE_SHOW_ALL_EXPENSES; import static seedu.address.testutil.Assert.assertThrows; +import static seedu.address.testutil.TypicalBudgets.JAPAN; +import static seedu.address.testutil.TypicalBudgets.KOREA; import static seedu.address.testutil.TypicalExpenses.FOOD; import static seedu.address.testutil.TypicalExpenses.SHOPPING; @@ -15,7 +17,9 @@ import org.junit.jupiter.api.Test; import seedu.address.commons.core.GuiSettings; +import seedu.address.model.budget.BudgetList; import seedu.address.model.expense.NameContainsKeywordsPredicate; +import seedu.address.testutil.BudgetListBuilder; import seedu.address.testutil.ExpenseListBuilder; public class ModelManagerTest { @@ -27,6 +31,7 @@ public void constructor() { assertEquals(new UserPrefs(), modelManager.getUserPrefs()); assertEquals(new GuiSettings(), modelManager.getGuiSettings()); assertEquals(new ExpenseList(), new ExpenseList(modelManager.getExpenseList())); + assertEquals(new BudgetList(), new BudgetList(modelManager.getBudgetList())); } @Test @@ -96,12 +101,14 @@ public void getFilteredExpenseList_modifyList_throwsUnsupportedOperationExceptio @Test public void equals() { ExpenseList expenseList = new ExpenseListBuilder().withExpense(FOOD).withExpense(SHOPPING).build(); + BudgetList budgetList = new BudgetListBuilder().withBudget(JAPAN).withBudget(KOREA).build(); ExpenseList differentExpenseList = new ExpenseList(); + BudgetList differentBudgetList = new BudgetList(); UserPrefs userPrefs = new UserPrefs(); // same values -> returns true - modelManager = new ModelManager(expenseList, userPrefs); - ModelManager modelManagerCopy = new ModelManager(expenseList, userPrefs); + modelManager = new ModelManager(expenseList, budgetList, userPrefs); + ModelManager modelManagerCopy = new ModelManager(expenseList, budgetList, userPrefs); assertTrue(modelManager.equals(modelManagerCopy)); // same object -> returns true @@ -114,12 +121,20 @@ public void equals() { assertFalse(modelManager.equals(5)); // different expenseList -> returns false - assertFalse(modelManager.equals(new ModelManager(differentExpenseList, userPrefs))); + assertFalse(modelManager.equals(new ModelManager(differentExpenseList, budgetList, userPrefs))); + + // different budgetList -> returns false + assertFalse(modelManager.equals(new ModelManager(expenseList, differentBudgetList, userPrefs))); // different filteredList -> returns false String[] keywords = FOOD.getName().fullName.split("\\s+"); modelManager.updateFilteredExpenseList(new NameContainsKeywordsPredicate(Arrays.asList(keywords))); - assertFalse(modelManager.equals(new ModelManager(expenseList, userPrefs))); + assertFalse(modelManager.equals(new ModelManager(expenseList, budgetList, userPrefs))); + + // different filteredBudgetList -> returns false +// String[] budgetKeyword = JAPAN.getName().fullName.split("\\s+"); +// modelManager.updateFilteredBudgetList(new NameContainsKeywordsPredicate(Arrays.asList(keywords))); +// assertFalse(modelManager.equals(new ModelManager(expenseList, budgetList, userPrefs))); // resets modelManager to initial state for upcoming tests modelManager.updateFilteredExpenseList(PREDICATE_SHOW_ALL_EXPENSES); @@ -127,6 +142,6 @@ public void equals() { // different userPrefs -> returns false UserPrefs differentUserPrefs = new UserPrefs(); differentUserPrefs.setExpenseListFilePath(Paths.get("differentFilePath")); - assertFalse(modelManager.equals(new ModelManager(expenseList, differentUserPrefs))); + assertFalse(modelManager.equals(new ModelManager(expenseList, budgetList, differentUserPrefs))); } } diff --git a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java b/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java index cf45c19944c..8b07fc963d2 100644 --- a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java +++ b/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java @@ -74,6 +74,7 @@ private UserPrefs getTypicalUserPrefs() { UserPrefs userPrefs = new UserPrefs(); userPrefs.setGuiSettings(new GuiSettings(1000, 500, 300, 100)); userPrefs.setExpenseListFilePath(Paths.get("expenselist.json")); + userPrefs.setBudgetListFilePath(Paths.get("budgetlist.json")); return userPrefs; } diff --git a/src/test/java/seedu/address/storage/StorageManagerTest.java b/src/test/java/seedu/address/storage/StorageManagerTest.java index 338c860e63c..381268878b5 100644 --- a/src/test/java/seedu/address/storage/StorageManagerTest.java +++ b/src/test/java/seedu/address/storage/StorageManagerTest.java @@ -25,8 +25,9 @@ public class StorageManagerTest { @BeforeEach public void setUp() { JsonExpenseListStorage expenseListStorage = new JsonExpenseListStorage(getTempFilePath("ab")); + JsonBudgetListStorage budgetListStorage = new JsonBudgetListStorage(getTempFilePath("bl")); JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(getTempFilePath("prefs")); - storageManager = new StorageManager(expenseListStorage, userPrefsStorage); + storageManager = new StorageManager(expenseListStorage, budgetListStorage, userPrefsStorage); } private Path getTempFilePath(String fileName) { diff --git a/src/test/java/seedu/address/testutil/BudgetBuilder.java b/src/test/java/seedu/address/testutil/BudgetBuilder.java new file mode 100644 index 00000000000..f8f1c51d63b --- /dev/null +++ b/src/test/java/seedu/address/testutil/BudgetBuilder.java @@ -0,0 +1,85 @@ +package seedu.address.testutil; + +import seedu.address.model.ExpenseList; +import seedu.address.model.expense.Amount; +import seedu.address.model.expense.Date; +import seedu.address.model.budget.Budget; +import static seedu.address.testutil.TypicalExpenses.getTypicalExpenseList; +import seedu.address.model.expense.Name; + +/** + * A utility class to help with building Budget objects. + */ +public class BudgetBuilder { + + public static final String DEFAULT_NAME = "Korea holiday"; + public static final String DEFAULT_AMOUNT = "$2500"; + public static String DEFAULT_AMOUNT_LEFT = "$2500"; + public static final String DEFAULT_START_DATE = "13/10/2019"; + public static final String DEFAULT_END_DATE = "25/10/2019"; + public static final ExpenseList DEFAULT_EXPENSE_LIST = getTypicalExpenseList(); + + private Name name; + private Amount amount; + private Amount amountLeft; + private Date startDate; + private Date endDate; + private ExpenseList expenseList; + + public BudgetBuilder() { + name = new Name(DEFAULT_NAME); + amount = new Amount(DEFAULT_AMOUNT); + amountLeft = new Amount(DEFAULT_AMOUNT_LEFT); + startDate = new Date(DEFAULT_START_DATE); + endDate = new Date(DEFAULT_END_DATE); + expenseList = new ExpenseList(DEFAULT_EXPENSE_LIST); + } + + /** + * Initializes the BudgetBuilder with the data of {@code budgetToCopy}. + */ + public BudgetBuilder(Budget budgetToCopy) { + name = budgetToCopy.getName(); + amount = budgetToCopy.getAmount(); + amountLeft = budgetToCopy.getAmountLeft(); + startDate = budgetToCopy.getStartDate(); + endDate = budgetToCopy.getEndDate(); + expenseList = budgetToCopy.getExpenseList(); + } + + /** + * Sets the {@code Name} of the {@code Budget} that we are building. + */ + public BudgetBuilder withName(String name) { + this.name = new Name(name); + return this; + } + + /** + * Sets the {@code Amount} of the {@code Budget} that we are building. + */ + public BudgetBuilder withAmount(String amount) { + this.amount = new Amount(amount); + return this; + } + + /** + * Sets the {@code startDate} of the {@code Budget} that we are building. + */ + public BudgetBuilder withStartDate(String date) { + this.startDate = new Date(date); + return this; + } + + /** + * Sets the {@code endDate} of the {@code Budget} that we are building. + */ + public BudgetBuilder withEndDate(String date) { + this.endDate = new Date(date); + return this; + } + + public Budget build() { + return new Budget(name, amount, amount, startDate, endDate, expenseList); + } +} diff --git a/src/test/java/seedu/address/testutil/BudgetListBuilder.java b/src/test/java/seedu/address/testutil/BudgetListBuilder.java new file mode 100644 index 00000000000..27c85fae5f2 --- /dev/null +++ b/src/test/java/seedu/address/testutil/BudgetListBuilder.java @@ -0,0 +1,34 @@ +package seedu.address.testutil; + +import seedu.address.model.budget.BudgetList; +import seedu.address.model.budget.Budget; + +/** + * A utility class to help with building BudgetList objects. + * Example usage:
+ * {@code BudgetList ab = new BudgetListBuilder().withBudget("Coffee", "Tea").build();} + */ +public class BudgetListBuilder { + + private BudgetList budgetList; + + public BudgetListBuilder() { + budgetList = new BudgetList(); + } + + public BudgetListBuilder(BudgetList budgetList) { + this.budgetList = budgetList; + } + + /** + * Adds a new {@code Budget} to the {@code BudgetList} that we are building. + */ + public BudgetListBuilder withBudget(Budget budget) { + budgetList.addBudget(budget); + return this; + } + + public BudgetList build() { + return budgetList; + } +} diff --git a/src/test/java/seedu/address/testutil/TypicalBudgets.java b/src/test/java/seedu/address/testutil/TypicalBudgets.java new file mode 100644 index 00000000000..96cc0f518eb --- /dev/null +++ b/src/test/java/seedu/address/testutil/TypicalBudgets.java @@ -0,0 +1,43 @@ +package seedu.address.testutil; + +import seedu.address.model.budget.BudgetList; +import seedu.address.model.budget.Budget; +import seedu.address.model.expense.Amount; +import seedu.address.model.expense.Date; +import seedu.address.model.expense.Name; + +import java.io.BufferedWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * A utility class containing a list of {@code Budget} objects to be used in tests. + */ +public class TypicalBudgets { + + public static final Budget KOREA = new BudgetBuilder().withName("Korea Trip").withAmount("$3000") + .withStartDate("5/1/2019").withEndDate("9/1/2019").build(); + public static final Budget JAPAN = new BudgetBuilder().withName("Japan Travel").withAmount("$5000") + .withStartDate("14/6/2019").withEndDate("23/6/2019").build(); + public static final Budget FRANCE = new BudgetBuilder().withName("France Fun").withAmount("8000") + .withStartDate("23/4/2019").withEndDate("11/5/2019").build(); + + + private TypicalBudgets() {} // prevents instantiation + + /** + * Returns an {@code BudgetList} with all the typical budgets. + */ + public static BudgetList getTypicalBudgetList() { + BudgetList ab = new BudgetList(); + for (Budget budget : getTypicalBudgets()) { + ab.addBudget(budget); + } + return ab; + } + + public static List getTypicalBudgets() { + return new ArrayList<>(Arrays.asList(KOREA, JAPAN, FRANCE)); + } +} \ No newline at end of file From d879fea8045cf152cf78caf59b2a6e0867db8f52 Mon Sep 17 00:00:00 2001 From: choonx99 Date: Wed, 23 Oct 2019 00:08:59 +0800 Subject: [PATCH 6/8] fixed expenselist storage inside budget and checkstyle errors --- .../seedu/address/logic/commands/AddBudgetCommand.java | 1 + src/main/java/seedu/address/model/budget/Budget.java | 10 ++++++---- .../java/seedu/address/storage/JsonAdaptedBudget.java | 10 +++++++--- .../seedu/address/storage/JsonExpenseListStorage.java | 4 ++-- .../java/seedu/address/testutil/TypicalBudgets.java | 4 ++-- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java b/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java index 61abde7b256..6b206a09dd8 100644 --- a/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java +++ b/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java @@ -64,4 +64,5 @@ public CommandResult execute(Model model) throws CommandException { model.addBudget(toAdd); return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); } + } \ No newline at end of file diff --git a/src/main/java/seedu/address/model/budget/Budget.java b/src/main/java/seedu/address/model/budget/Budget.java index e1f9d533d1b..c8b174b29ef 100644 --- a/src/main/java/seedu/address/model/budget/Budget.java +++ b/src/main/java/seedu/address/model/budget/Budget.java @@ -68,7 +68,7 @@ public Date getEndDate() { public void addExpenseIntoBudget(Expense expense) { expenseList.addExpense(expense); - deductAmountLeft(expense); + recalculateAmountLeft(); } public boolean budgetHasExpense(Expense expense) { @@ -79,9 +79,11 @@ public boolean isDateWithinBudgetPeriod(Date date) { return !date.localDate.isBefore(startDate.localDate) && !date.localDate.isAfter(endDate.localDate); } - public void deductAmountLeft(Expense expense) { - double amountLeft = this.amountLeft.getValue(); - amountLeft -= expense.getAmount().getValue(); + public void recalculateAmountLeft() { + double amountLeft = this.amount.getValue(); + for (Expense expense : expenseList.getExpenseList()) { + amountLeft -= expense.getAmount().getValue(); + } this.amountLeft = new Amount("" + amountLeft); } diff --git a/src/main/java/seedu/address/storage/JsonAdaptedBudget.java b/src/main/java/seedu/address/storage/JsonAdaptedBudget.java index b0c5aaadcbf..c7ab3f54e92 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedBudget.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedBudget.java @@ -85,10 +85,10 @@ public Budget toModelType() throws IllegalValueException { if (amountLeft == null) { throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Amount.class.getSimpleName())); } - if (!Amount.isValidAmount(amount)) { + if (!Amount.isValidAmount(amountLeft)) { throw new IllegalValueException(Amount.MESSAGE_CONSTRAINTS); } - final Amount modelAmountLeft = new Amount(amount); + final Amount modelAmountLeft = new Amount(amountLeft); if (startDate == null) { throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Date.class.getSimpleName())); @@ -106,7 +106,11 @@ public Budget toModelType() throws IllegalValueException { } final Date modelEndDate = new Date(endDate); - return new Budget(modelName, modelAmount, modelAmountLeft, modelStartDate, modelEndDate, new ExpenseList()); + if (expenseList == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, ExpenseList.class.getSimpleName())); + } + + return new Budget(modelName, modelAmount, modelAmountLeft, modelStartDate, modelEndDate, new ExpenseList(expenseList.toModelType())); // need to do for budget expenselist also } diff --git a/src/main/java/seedu/address/storage/JsonExpenseListStorage.java b/src/main/java/seedu/address/storage/JsonExpenseListStorage.java index 6ee04add01a..1484e95f922 100644 --- a/src/main/java/seedu/address/storage/JsonExpenseListStorage.java +++ b/src/main/java/seedu/address/storage/JsonExpenseListStorage.java @@ -60,8 +60,8 @@ public Optional readExpenseList(Path filePath) throws DataC } @Override - public void saveExpenseList(ReadOnlyExpenseList addressBook) throws IOException { - saveExpenseList(addressBook, filePath); + public void saveExpenseList(ReadOnlyExpenseList expenseList) throws IOException { + saveExpenseList(expenseList, filePath); } /** diff --git a/src/test/java/seedu/address/testutil/TypicalBudgets.java b/src/test/java/seedu/address/testutil/TypicalBudgets.java index 96cc0f518eb..977ac26e2e1 100644 --- a/src/test/java/seedu/address/testutil/TypicalBudgets.java +++ b/src/test/java/seedu/address/testutil/TypicalBudgets.java @@ -15,14 +15,13 @@ * A utility class containing a list of {@code Budget} objects to be used in tests. */ public class TypicalBudgets { - + public static final Budget KOREA = new BudgetBuilder().withName("Korea Trip").withAmount("$3000") .withStartDate("5/1/2019").withEndDate("9/1/2019").build(); public static final Budget JAPAN = new BudgetBuilder().withName("Japan Travel").withAmount("$5000") .withStartDate("14/6/2019").withEndDate("23/6/2019").build(); public static final Budget FRANCE = new BudgetBuilder().withName("France Fun").withAmount("8000") .withStartDate("23/4/2019").withEndDate("11/5/2019").build(); - private TypicalBudgets() {} // prevents instantiation @@ -40,4 +39,5 @@ public static BudgetList getTypicalBudgetList() { public static List getTypicalBudgets() { return new ArrayList<>(Arrays.asList(KOREA, JAPAN, FRANCE)); } + } \ No newline at end of file From 0172a6b0861b69f38bf37723cd02693a82639426 Mon Sep 17 00:00:00 2001 From: choonx99 Date: Wed, 23 Oct 2019 00:23:04 +0800 Subject: [PATCH 7/8] fix checkstyle error --- .../java/seedu/address/logic/commands/AddBudgetCommand.java | 3 +-- src/test/java/seedu/address/testutil/TypicalBudgets.java | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java b/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java index 6b206a09dd8..a146a9408de 100644 --- a/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java +++ b/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java @@ -64,5 +64,4 @@ public CommandResult execute(Model model) throws CommandException { model.addBudget(toAdd); return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); } - -} \ No newline at end of file +} diff --git a/src/test/java/seedu/address/testutil/TypicalBudgets.java b/src/test/java/seedu/address/testutil/TypicalBudgets.java index 977ac26e2e1..c7ecc255401 100644 --- a/src/test/java/seedu/address/testutil/TypicalBudgets.java +++ b/src/test/java/seedu/address/testutil/TypicalBudgets.java @@ -39,5 +39,4 @@ public static BudgetList getTypicalBudgetList() { public static List getTypicalBudgets() { return new ArrayList<>(Arrays.asList(KOREA, JAPAN, FRANCE)); } - -} \ No newline at end of file +} From 1085fc8e1dd0b0294e6ff3e24af10c2cd104f94f Mon Sep 17 00:00:00 2001 From: choonx99 Date: Wed, 23 Oct 2019 01:32:20 +0800 Subject: [PATCH 8/8] fixed checkstyle error --- src/main/java/seedu/address/MainApp.java | 10 ++++++++- .../logic/commands/AddBudgetCommand.java | 2 +- .../logic/parser/AddBudgetCommandParser.java | 5 ++--- .../seedu/address/logic/parser/MymParser.java | 2 +- .../seedu/address/model/budget/Budget.java | 22 ++++++++++++++----- .../address/model/budget/BudgetList.java | 7 +++++- .../model/budget/UniqueBudgetList.java | 2 +- .../seedu/address/model/expense/Amount.java | 2 +- .../address/storage/BudgetListStorage.java | 8 +++---- .../address/storage/JsonAdaptedBudget.java | 19 +++++----------- .../storage/JsonBudgetListStorage.java | 14 ++++++------ .../storage/JsonSerializableBudgetList.java | 11 +++++----- .../commands/AddCommandIntegrationTest.java | 4 +--- .../logic/commands/DeleteCommandTest.java | 2 +- .../logic/commands/EditCommandTest.java | 12 ++++++---- .../seedu/address/model/ModelManagerTest.java | 6 ++--- .../seedu/address/testutil/BudgetBuilder.java | 7 +++--- .../address/testutil/BudgetListBuilder.java | 2 +- .../address/testutil/TypicalBudgets.java | 10 +++------ 19 files changed, 82 insertions(+), 65 deletions(-) diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java index 3a6d6861a92..ab2fcefee7a 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/seedu/address/MainApp.java @@ -24,7 +24,15 @@ import seedu.address.model.budget.BudgetList; import seedu.address.model.budget.ReadOnlyBudgetList; import seedu.address.model.util.SampleDataUtil; -import seedu.address.storage.*; + +import seedu.address.storage.BudgetListStorage; +import seedu.address.storage.ExpenseListStorage; +import seedu.address.storage.JsonBudgetListStorage; +import seedu.address.storage.JsonExpenseListStorage; +import seedu.address.storage.JsonUserPrefsStorage; +import seedu.address.storage.Storage; +import seedu.address.storage.StorageManager; +import seedu.address.storage.UserPrefsStorage; import seedu.address.ui.Ui; import seedu.address.ui.UiManager; diff --git a/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java b/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java index a146a9408de..601946278b2 100644 --- a/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java +++ b/src/main/java/seedu/address/logic/commands/AddBudgetCommand.java @@ -32,7 +32,7 @@ public class AddBudgetCommand extends Command { public static final String MESSAGE_SUCCESS = "New budget added: %1$s"; public static final String MESSAGE_DUPLICATE_BUDGET = "This budget already exists in the budget list"; - public static final String MESSAGE_BUDGET_CLASH = "This budget period clashes with another budget in the budget list"; + public static final String MESSAGE_BUDGET_CLASH = "This budget period clashes with another budget"; public static final String MESSAGE_START_BEFORE_END = "The budget end date has to be after its start date"; private final Budget toAdd; diff --git a/src/main/java/seedu/address/logic/parser/AddBudgetCommandParser.java b/src/main/java/seedu/address/logic/parser/AddBudgetCommandParser.java index 985e56ea5cd..55cf8589a8d 100644 --- a/src/main/java/seedu/address/logic/parser/AddBudgetCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/AddBudgetCommandParser.java @@ -6,17 +6,16 @@ import static seedu.address.logic.parser.CliSyntax.PREFIX_END_DATE; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; +import java.util.stream.Stream; + import seedu.address.logic.commands.AddBudgetCommand; import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.ExpenseList; import seedu.address.model.budget.Budget; import seedu.address.model.expense.Amount; import seedu.address.model.expense.Date; -import seedu.address.model.expense.Expense; import seedu.address.model.expense.Name; -import java.util.stream.Stream; - /** * Parses input arguments and creates a new AddBudgetCommand object */ diff --git a/src/main/java/seedu/address/logic/parser/MymParser.java b/src/main/java/seedu/address/logic/parser/MymParser.java index 84a8be2415f..7be8ad3fbd2 100644 --- a/src/main/java/seedu/address/logic/parser/MymParser.java +++ b/src/main/java/seedu/address/logic/parser/MymParser.java @@ -6,8 +6,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import seedu.address.logic.commands.AddCommand; import seedu.address.logic.commands.AddBudgetCommand; +import seedu.address.logic.commands.AddCommand; import seedu.address.logic.commands.ClearCommand; import seedu.address.logic.commands.Command; import seedu.address.logic.commands.DeleteCommand; diff --git a/src/main/java/seedu/address/model/budget/Budget.java b/src/main/java/seedu/address/model/budget/Budget.java index c8b174b29ef..934d4f550d7 100644 --- a/src/main/java/seedu/address/model/budget/Budget.java +++ b/src/main/java/seedu/address/model/budget/Budget.java @@ -2,8 +2,6 @@ import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; -import java.time.LocalDate; -import java.util.Collections; import java.util.Objects; import seedu.address.model.ExpenseList; @@ -11,7 +9,6 @@ import seedu.address.model.expense.Date; import seedu.address.model.expense.Expense; import seedu.address.model.expense.Name; -import seedu.address.model.tag.Tag; /** * Represents an expense in the expense list. @@ -26,7 +23,7 @@ public class Budget { private final Date startDate; private final Date endDate; private final Amount amount; - private Amount amountLeft; + private Amount amountLeft; // Expense List private final ExpenseList expenseList; @@ -64,8 +61,14 @@ public Date getEndDate() { return endDate; } - public ExpenseList getExpenseList() { return expenseList; } + public ExpenseList getExpenseList() { + return expenseList; + } + /** + * Adds an expense into the expenselist inside the budget. + * @param expense an expense to be added into a budget. + */ public void addExpenseIntoBudget(Expense expense) { expenseList.addExpense(expense); recalculateAmountLeft(); @@ -75,10 +78,19 @@ public boolean budgetHasExpense(Expense expense) { return expenseList.hasExpense(expense); } + /** + * Checks whether a given date falls within any budget period. + * @param date a valid date. + * @return a boolean value. + */ public boolean isDateWithinBudgetPeriod(Date date) { return !date.localDate.isBefore(startDate.localDate) && !date.localDate.isAfter(endDate.localDate); } + /** + * Recalculates the amountLeft in budget after an expense is added into the budget. + * This is to prevent accidental amendments directly in the data file to result in wrong amount left. + */ public void recalculateAmountLeft() { double amountLeft = this.amount.getValue(); for (Expense expense : expenseList.getExpenseList()) { diff --git a/src/main/java/seedu/address/model/budget/BudgetList.java b/src/main/java/seedu/address/model/budget/BudgetList.java index 2194539f904..a909271db5a 100644 --- a/src/main/java/seedu/address/model/budget/BudgetList.java +++ b/src/main/java/seedu/address/model/budget/BudgetList.java @@ -16,7 +16,7 @@ public class BudgetList implements ReadOnlyBudgetList { private final UniqueBudgetList budgets; - /* + /* * The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication * between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html * @@ -108,6 +108,11 @@ public Optional getBudgetExpenseFallsInto(Expense expense) { return toReturn; } + /** + * Checks whether a new budget to be added clashes with any existing budget period. + * @param newBudget a valid budget. + * @return a boolean value. + */ public boolean hasBudgetPeriodClash(Budget newBudget) { List lastShownList = getBudgetList(); for (Budget budget : lastShownList) { diff --git a/src/main/java/seedu/address/model/budget/UniqueBudgetList.java b/src/main/java/seedu/address/model/budget/UniqueBudgetList.java index e304521d510..ea980d0c7f8 100644 --- a/src/main/java/seedu/address/model/budget/UniqueBudgetList.java +++ b/src/main/java/seedu/address/model/budget/UniqueBudgetList.java @@ -8,8 +8,8 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; -import seedu.address.model.budget.exceptions.DuplicateBudgetException; import seedu.address.model.budget.exceptions.BudgetNotFoundException; +import seedu.address.model.budget.exceptions.DuplicateBudgetException; /** * A list of budgets that enforces uniqueness between its elements and does not allow nulls. diff --git a/src/main/java/seedu/address/model/expense/Amount.java b/src/main/java/seedu/address/model/expense/Amount.java index 0aab01fdde8..ba4014b33cd 100644 --- a/src/main/java/seedu/address/model/expense/Amount.java +++ b/src/main/java/seedu/address/model/expense/Amount.java @@ -34,7 +34,7 @@ public static boolean isValidAmount(String test) { } public double getValue() { - return Double.parseDouble(value.replaceAll("[^\\d.]","")); + return Double.parseDouble(value.replaceAll("[^\\d.]", "")); } @Override diff --git a/src/main/java/seedu/address/storage/BudgetListStorage.java b/src/main/java/seedu/address/storage/BudgetListStorage.java index b45a5e9840d..9e1be542e0c 100644 --- a/src/main/java/seedu/address/storage/BudgetListStorage.java +++ b/src/main/java/seedu/address/storage/BudgetListStorage.java @@ -1,13 +1,13 @@ package seedu.address.storage; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.budget.BudgetList; -import seedu.address.model.budget.ReadOnlyBudgetList; - import java.io.IOException; import java.nio.file.Path; import java.util.Optional; +import seedu.address.commons.exceptions.DataConversionException; +import seedu.address.model.budget.BudgetList; +import seedu.address.model.budget.ReadOnlyBudgetList; + /** * Represents a storage for {@link BudgetList}. */ diff --git a/src/main/java/seedu/address/storage/JsonAdaptedBudget.java b/src/main/java/seedu/address/storage/JsonAdaptedBudget.java index c7ab3f54e92..5ee1150d4d7 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedBudget.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedBudget.java @@ -2,20 +2,13 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; + import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.model.ExpenseList; +import seedu.address.model.budget.Budget; import seedu.address.model.expense.Amount; import seedu.address.model.expense.Date; -import seedu.address.model.budget.Budget; -import seedu.address.model.expense.Expense; import seedu.address.model.expense.Name; -import seedu.address.model.tag.Tag; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; /** * Jackson-friendly version of {@link Budget}. @@ -107,11 +100,11 @@ public Budget toModelType() throws IllegalValueException { final Date modelEndDate = new Date(endDate); if (expenseList == null) { - throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, ExpenseList.class.getSimpleName())); + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + ExpenseList.class.getSimpleName())); } - return new Budget(modelName, modelAmount, modelAmountLeft, modelStartDate, modelEndDate, new ExpenseList(expenseList.toModelType())); - - // need to do for budget expenselist also + return new Budget(modelName, modelAmount, modelAmountLeft, modelStartDate, modelEndDate, + new ExpenseList(expenseList.toModelType())); } } diff --git a/src/main/java/seedu/address/storage/JsonBudgetListStorage.java b/src/main/java/seedu/address/storage/JsonBudgetListStorage.java index 6120ab45cb5..8e319b2154c 100644 --- a/src/main/java/seedu/address/storage/JsonBudgetListStorage.java +++ b/src/main/java/seedu/address/storage/JsonBudgetListStorage.java @@ -1,18 +1,18 @@ package seedu.address.storage; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.commons.util.FileUtil; -import seedu.address.commons.util.JsonUtil; -import seedu.address.model.budget.ReadOnlyBudgetList; +import static java.util.Objects.requireNonNull; import java.io.IOException; import java.nio.file.Path; import java.util.Optional; import java.util.logging.Logger; -import static java.util.Objects.requireNonNull; +import seedu.address.commons.core.LogsCenter; +import seedu.address.commons.exceptions.DataConversionException; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.commons.util.FileUtil; +import seedu.address.commons.util.JsonUtil; +import seedu.address.model.budget.ReadOnlyBudgetList; /** * A class to access BudgetList data stored as a json file on the hard disk. diff --git a/src/main/java/seedu/address/storage/JsonSerializableBudgetList.java b/src/main/java/seedu/address/storage/JsonSerializableBudgetList.java index 7a968649a14..d2c879dfc90 100644 --- a/src/main/java/seedu/address/storage/JsonSerializableBudgetList.java +++ b/src/main/java/seedu/address/storage/JsonSerializableBudgetList.java @@ -1,16 +1,17 @@ package seedu.address.storage; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonRootName; + import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.budget.Budget; import seedu.address.model.budget.BudgetList; import seedu.address.model.budget.ReadOnlyBudgetList; -import seedu.address.model.budget.Budget; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; /** * An Immutable BudgetList that is serializable to JSON format. diff --git a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java b/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java index c92d779bc11..5027341c81e 100644 --- a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java +++ b/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java @@ -2,18 +2,16 @@ import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure; import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; -import static seedu.address.testutil.TypicalExpenses.getTypicalExpenseList; import static seedu.address.testutil.TypicalBudgets.getTypicalBudgetList; +import static seedu.address.testutil.TypicalExpenses.getTypicalExpenseList; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import seedu.address.model.ExpenseList; import seedu.address.model.Model; import seedu.address.model.ModelManager; import seedu.address.model.UserPrefs; import seedu.address.model.budget.Budget; -import seedu.address.model.budget.BudgetList; import seedu.address.model.expense.Expense; import seedu.address.testutil.BudgetBuilder; import seedu.address.testutil.ExpenseBuilder; diff --git a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java index 07ec7ca12a5..df39d496405 100644 --- a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java @@ -25,7 +25,7 @@ */ public class DeleteCommandTest { - private Model model = new ModelManager(getTypicalExpenseList(), new BudgetList(),new UserPrefs()); + private Model model = new ModelManager(getTypicalExpenseList(), new BudgetList(), new UserPrefs()); @Test public void execute_validIndexUnfilteredList_success() { diff --git a/src/test/java/seedu/address/logic/commands/EditCommandTest.java b/src/test/java/seedu/address/logic/commands/EditCommandTest.java index c4fee751b1e..6424bfec6b2 100644 --- a/src/test/java/seedu/address/logic/commands/EditCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/EditCommandTest.java @@ -43,7 +43,8 @@ public void execute_allFieldsSpecifiedUnfilteredList_success() { String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_EXPENSE_SUCCESS, editedExpense); - Model expectedModel = new ModelManager(new ExpenseList(model.getExpenseList()), new BudgetList(), new UserPrefs()); + Model expectedModel = new ModelManager(new ExpenseList(model.getExpenseList()), + new BudgetList(), new UserPrefs()); expectedModel.setExpense(model.getFilteredExpenseList().get(0), editedExpense); assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); @@ -64,7 +65,8 @@ public void execute_someFieldsSpecifiedUnfilteredList_success() { String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_EXPENSE_SUCCESS, editedExpense); - Model expectedModel = new ModelManager(new ExpenseList(model.getExpenseList()), new BudgetList(), new UserPrefs()); + Model expectedModel = new ModelManager(new ExpenseList(model.getExpenseList()), + new BudgetList(), new UserPrefs()); expectedModel.setExpense(lastExpense, editedExpense); assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); @@ -77,7 +79,8 @@ public void execute_noFieldSpecifiedUnfilteredList_success() { String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_EXPENSE_SUCCESS, editedExpense); - Model expectedModel = new ModelManager(new ExpenseList(model.getExpenseList()), new BudgetList(), new UserPrefs()); + Model expectedModel = new ModelManager(new ExpenseList(model.getExpenseList()), + new BudgetList(), new UserPrefs()); assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); } @@ -93,7 +96,8 @@ public void execute_filteredList_success() { String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_EXPENSE_SUCCESS, editedExpense); - Model expectedModel = new ModelManager(new ExpenseList(model.getExpenseList()), new BudgetList(), new UserPrefs()); + Model expectedModel = new ModelManager(new ExpenseList(model.getExpenseList()), + new BudgetList(), new UserPrefs()); expectedModel.setExpense(model.getFilteredExpenseList().get(0), editedExpense); assertCommandSuccess(editCommand, model, expectedMessage, expectedModel); diff --git a/src/test/java/seedu/address/model/ModelManagerTest.java b/src/test/java/seedu/address/model/ModelManagerTest.java index 43d52156f04..5a92c151649 100644 --- a/src/test/java/seedu/address/model/ModelManagerTest.java +++ b/src/test/java/seedu/address/model/ModelManagerTest.java @@ -132,9 +132,9 @@ public void equals() { assertFalse(modelManager.equals(new ModelManager(expenseList, budgetList, userPrefs))); // different filteredBudgetList -> returns false -// String[] budgetKeyword = JAPAN.getName().fullName.split("\\s+"); -// modelManager.updateFilteredBudgetList(new NameContainsKeywordsPredicate(Arrays.asList(keywords))); -// assertFalse(modelManager.equals(new ModelManager(expenseList, budgetList, userPrefs))); + // String[] budgetKeyword = JAPAN.getName().fullName.split("\\s+"); + // modelManager.updateFilteredBudgetList(new NameContainsKeywordsPredicate(Arrays.asList(keywords))); + // assertFalse(modelManager.equals(new ModelManager(expenseList, budgetList, userPrefs))); // resets modelManager to initial state for upcoming tests modelManager.updateFilteredExpenseList(PREDICATE_SHOW_ALL_EXPENSES); diff --git a/src/test/java/seedu/address/testutil/BudgetBuilder.java b/src/test/java/seedu/address/testutil/BudgetBuilder.java index f8f1c51d63b..92ee6845e94 100644 --- a/src/test/java/seedu/address/testutil/BudgetBuilder.java +++ b/src/test/java/seedu/address/testutil/BudgetBuilder.java @@ -1,10 +1,11 @@ package seedu.address.testutil; +import static seedu.address.testutil.TypicalExpenses.getTypicalExpenseList; + import seedu.address.model.ExpenseList; +import seedu.address.model.budget.Budget; import seedu.address.model.expense.Amount; import seedu.address.model.expense.Date; -import seedu.address.model.budget.Budget; -import static seedu.address.testutil.TypicalExpenses.getTypicalExpenseList; import seedu.address.model.expense.Name; /** @@ -14,7 +15,7 @@ public class BudgetBuilder { public static final String DEFAULT_NAME = "Korea holiday"; public static final String DEFAULT_AMOUNT = "$2500"; - public static String DEFAULT_AMOUNT_LEFT = "$2500"; + public static final String DEFAULT_AMOUNT_LEFT = "$2500"; public static final String DEFAULT_START_DATE = "13/10/2019"; public static final String DEFAULT_END_DATE = "25/10/2019"; public static final ExpenseList DEFAULT_EXPENSE_LIST = getTypicalExpenseList(); diff --git a/src/test/java/seedu/address/testutil/BudgetListBuilder.java b/src/test/java/seedu/address/testutil/BudgetListBuilder.java index 27c85fae5f2..d9cc2ad4fc1 100644 --- a/src/test/java/seedu/address/testutil/BudgetListBuilder.java +++ b/src/test/java/seedu/address/testutil/BudgetListBuilder.java @@ -1,7 +1,7 @@ package seedu.address.testutil; -import seedu.address.model.budget.BudgetList; import seedu.address.model.budget.Budget; +import seedu.address.model.budget.BudgetList; /** * A utility class to help with building BudgetList objects. diff --git a/src/test/java/seedu/address/testutil/TypicalBudgets.java b/src/test/java/seedu/address/testutil/TypicalBudgets.java index c7ecc255401..9b9515ff2bd 100644 --- a/src/test/java/seedu/address/testutil/TypicalBudgets.java +++ b/src/test/java/seedu/address/testutil/TypicalBudgets.java @@ -1,16 +1,12 @@ package seedu.address.testutil; -import seedu.address.model.budget.BudgetList; -import seedu.address.model.budget.Budget; -import seedu.address.model.expense.Amount; -import seedu.address.model.expense.Date; -import seedu.address.model.expense.Name; - -import java.io.BufferedWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import seedu.address.model.budget.Budget; +import seedu.address.model.budget.BudgetList; + /** * A utility class containing a list of {@code Budget} objects to be used in tests. */