diff --git a/src/main/java/seedu/address/logic/Messages.java b/src/main/java/seedu/address/logic/Messages.java index 2ef635b1dfb..d10b6d96def 100644 --- a/src/main/java/seedu/address/logic/Messages.java +++ b/src/main/java/seedu/address/logic/Messages.java @@ -19,7 +19,12 @@ public class Messages { public static final String MESSAGE_INVALID_CUSTOMER_DISPLAYED_INDEX = "The customer index provided is invalid"; public static final String MESSAGE_INVALID_PROPERTY_DISPLAYED_INDEX = "The property index provided is invalid"; + + public static final String MESSAGE_CUSTOMERS_MATCH_OVERVIEW = "%1$d properties matched with customer "; + + public static final String MESSAGE_PROPERTIES_MATCH_OVERVIEW = "%1$d customers matched with property "; public static final String MESSAGE_CUSTOMERS_LISTED_OVERVIEW = "%1$d customers listed!"; + public static final String MESSAGE_PROPERTIES_LISTED_OVERVIEW = "%1$d properties listed!"; public static final String MESSAGE_DUPLICATE_FIELDS = "Multiple values specified for the following single-valued field(s): "; diff --git a/src/main/java/seedu/address/logic/commands/MatchCustomerCommand.java b/src/main/java/seedu/address/logic/commands/MatchCustomerCommand.java new file mode 100644 index 00000000000..47f50344db7 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/MatchCustomerCommand.java @@ -0,0 +1,88 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; + +import java.util.List; +import java.util.Set; + +import seedu.address.commons.core.index.Index; +import seedu.address.commons.util.ToStringBuilder; +import seedu.address.logic.Messages; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.customer.Budget; +import seedu.address.model.customer.Customer; +import seedu.address.model.property.Price; +import seedu.address.model.property.PriceAndTagsInRangePredicate; +import seedu.address.model.tag.Tag; + +/** + * Match all properties in the property book to the user based on specific tags + * and/or budget satisfy the customer criteria. + */ +public class MatchCustomerCommand extends Command { + public static final String COMMAND_WORD = "matchcust"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Match customers from the address book. \n" + + "Parameters: " + + "Index" + "\n" + + "Example: " + COMMAND_WORD + " 2"; + + public static final String MESSAGE_FAIL = "There is no customer with index "; + private Index targetIndex; + + /** + * Creates a MatchCustomerCommand to get all the specified {@code Property} + */ + public MatchCustomerCommand(Index targetIndex) { + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredCustomerList(); + + try { + Customer targetCustomer = lastShownList.get(targetIndex.getZeroBased()); + Budget budget = targetCustomer.getBudget(); + Set tags = targetCustomer.getTags(); + + Price maxPrice = budget.convertToPrice(); + PriceAndTagsInRangePredicate predicate = new PriceAndTagsInRangePredicate(maxPrice, tags); + + model.updateMatchedCustomerList(targetCustomer, predicate); + + return new CommandResult( + String.format( + Messages.MESSAGE_CUSTOMERS_MATCH_OVERVIEW + targetIndex.getOneBased(), + model.getFilteredPropertyList().size() + ) + ); + } catch (IndexOutOfBoundsException e) { + throw new CommandException(MESSAGE_FAIL + targetIndex.getOneBased()); + } + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof MatchCustomerCommand)) { + return false; + } + + MatchCustomerCommand otherMatchCustomerCommand = (MatchCustomerCommand) other; + return targetIndex.equals(otherMatchCustomerCommand.targetIndex); + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .add("Index", targetIndex) + .toString(); + } +} diff --git a/src/main/java/seedu/address/logic/commands/MatchPropertyCommand.java b/src/main/java/seedu/address/logic/commands/MatchPropertyCommand.java new file mode 100644 index 00000000000..c2fd273d3d1 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/MatchPropertyCommand.java @@ -0,0 +1,89 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; + +import java.util.List; +import java.util.Set; + +import seedu.address.commons.core.index.Index; +import seedu.address.commons.util.ToStringBuilder; +import seedu.address.logic.Messages; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.customer.Budget; +import seedu.address.model.customer.BudgetAndTagsInRangePredicate; +import seedu.address.model.property.Price; +import seedu.address.model.property.Property; +import seedu.address.model.tag.Tag; + +/** + * Match all properties in the property book to the user based on specific tags + * and/or budget satisfy the customer criteria. + */ +public class MatchPropertyCommand extends Command { + public static final String COMMAND_WORD = "matchprop"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Match properties from the property book. \n" + + "Parameters: " + + "Index" + "\n" + + "Example: " + COMMAND_WORD + " 2"; + + public static final String MESSAGE_FAIL = "There is no property with index "; + private Index targetIndex; + + /** + * Creates a MatchPropertyCommand to get all the specified {@code Customer} + */ + public MatchPropertyCommand(Index targetIndex) { + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredPropertyList(); + + try { + Property targetProperty = lastShownList.get(targetIndex.getZeroBased()); + + Price price = targetProperty.getPrice(); + Set tags = targetProperty.getTags(); + + Budget minBudget = price.convertToBudget(); + BudgetAndTagsInRangePredicate predicate = new BudgetAndTagsInRangePredicate(minBudget, tags); + + model.updateMatchedPropertyList(targetProperty, predicate); + + return new CommandResult( + String.format( + Messages.MESSAGE_PROPERTIES_MATCH_OVERVIEW + targetIndex.getOneBased(), + model.getFilteredCustomerList().size() + ) + ); + } catch (IndexOutOfBoundsException e) { + throw new CommandException(MESSAGE_FAIL + targetIndex.getOneBased()); + } + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof MatchPropertyCommand)) { + return false; + } + + MatchPropertyCommand otherMatchPropertyCommand = (MatchPropertyCommand) other; + return targetIndex.equals(otherMatchPropertyCommand.targetIndex); + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .add("Index", targetIndex) + .toString(); + } +} diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java index bf62df867de..b2db075abf0 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java @@ -22,6 +22,8 @@ import seedu.address.logic.commands.HelpCommand; import seedu.address.logic.commands.ListCustomerCommand; import seedu.address.logic.commands.ListPropertyCommand; +import seedu.address.logic.commands.MatchCustomerCommand; +import seedu.address.logic.commands.MatchPropertyCommand; import seedu.address.logic.parser.exceptions.ParseException; /** @@ -91,6 +93,12 @@ public Command parseCommand(String userInput) throws ParseException { case ListPropertyCommand.COMMAND_WORD: return new ListPropertyCommand(); + case MatchCustomerCommand.COMMAND_WORD: + return new MatchCustomerCommandParser().parse(arguments); + + case MatchPropertyCommand.COMMAND_WORD: + return new MatchPropertyCommandParser().parse(arguments); + case ExitCommand.COMMAND_WORD: return new ExitCommand(); diff --git a/src/main/java/seedu/address/logic/parser/MatchCustomerCommandParser.java b/src/main/java/seedu/address/logic/parser/MatchCustomerCommandParser.java new file mode 100644 index 00000000000..729f5ab444f --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/MatchCustomerCommandParser.java @@ -0,0 +1,37 @@ +package seedu.address.logic.parser; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; + +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.MatchCustomerCommand; +import seedu.address.logic.parser.exceptions.ParseException; + +/** + * Filters and lists all customers in address book whose budget and/or tags are selected. + */ +public class MatchCustomerCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the FilterCommand + * and returns a FilterCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public MatchCustomerCommand parse(String args) throws ParseException { + requireNonNull(args); + Index index; + + try { + index = ParserUtil.parseIndex(args); + } catch (ParseException pe) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, + MatchCustomerCommand.MESSAGE_USAGE), + pe + ); + } + + return new MatchCustomerCommand(index); + } + +} diff --git a/src/main/java/seedu/address/logic/parser/MatchPropertyCommandParser.java b/src/main/java/seedu/address/logic/parser/MatchPropertyCommandParser.java new file mode 100644 index 00000000000..a270a32d584 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/MatchPropertyCommandParser.java @@ -0,0 +1,37 @@ +package seedu.address.logic.parser; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; + +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.MatchPropertyCommand; +import seedu.address.logic.parser.exceptions.ParseException; + +/** + * Match and lists all customers in address book whose budget and/or tags satisfy with the property. + */ +public class MatchPropertyCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the MatchPropertyCommand + * and returns a MatchPropertyCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public MatchPropertyCommand parse(String args) throws ParseException { + requireNonNull(args); + Index index; + + try { + index = ParserUtil.parseIndex(args); + } catch (ParseException pe) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, + MatchPropertyCommand.MESSAGE_USAGE), + pe + ); + } + + return new MatchPropertyCommand(index); + } + +} diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index bc47435e938..f359e4f3d63 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -141,4 +141,16 @@ public interface Model { * @throws NullPointerException if {@code predicate} is null. */ void updateFilteredPropertyList(Predicate predicate); + + /** + * Deletes the given customer. + * The customer must exist in the address book. + */ + void updateMatchedCustomerList(Customer targetCustomer, Predicate predicate); + + /** + * Deletes the given property. + * The property must exist in the PropertyMatch. + */ + void updateMatchedPropertyList(Property targetProperty, Predicate predicate); } diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 585b4a41c84..e639f649050 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -12,7 +12,9 @@ import seedu.address.commons.core.GuiSettings; import seedu.address.commons.core.LogsCenter; import seedu.address.model.customer.Customer; +import seedu.address.model.customer.SameCustomerPredicate; import seedu.address.model.property.Property; +import seedu.address.model.property.SamePropertyPredicate; /** * Represents the in-memory model of the address book data. @@ -183,6 +185,14 @@ public void updateFilteredCustomerList(Predicate predicate) { filteredCustomers.setPredicate(predicate); } + @Override + public void updateMatchedCustomerList(Customer targetCustomer, Predicate predicate) { + requireAllNonNull(targetCustomer, predicate); + Predicate custPredicate = new SameCustomerPredicate(targetCustomer); + filteredCustomers.setPredicate(custPredicate); + filteredProperties.setPredicate(predicate); + } + //=========== Filtered Property List Accessors ============================================================= /** @@ -200,6 +210,13 @@ public void updateFilteredPropertyList(Predicate predicate) { filteredProperties.setPredicate(predicate); } + @Override + public void updateMatchedPropertyList(Property targetProperty, Predicate predicate) { + requireAllNonNull(targetProperty, predicate); + Predicate propPredicate = new SamePropertyPredicate(targetProperty); + filteredProperties.setPredicate(propPredicate); + filteredCustomers.setPredicate(predicate); + } @Override public boolean equals(Object other) { diff --git a/src/main/java/seedu/address/model/customer/Budget.java b/src/main/java/seedu/address/model/customer/Budget.java index c756d0d5df2..4bc3e18e377 100644 --- a/src/main/java/seedu/address/model/customer/Budget.java +++ b/src/main/java/seedu/address/model/customer/Budget.java @@ -4,6 +4,8 @@ import static java.util.Objects.requireNonNull; import static seedu.address.commons.util.AppUtil.checkArgument; +import seedu.address.model.property.Price; + /** * Represents a Customer's budget in the address book. * Guarantees: immutable; is valid as declared in {@link #isValidBudget(String)} @@ -37,7 +39,7 @@ public static boolean isValidBudget(String test) { } /** - * Returns true if the other budget is greater or equal this budget + * Returns true if the other budget is greater or equal this budget. * * @param other the other budget being compared * @return whether the other budget is greater or equal to this budget @@ -46,6 +48,14 @@ public boolean isInRangeBudget(Budget other) { return isNull(other) || amount >= other.amount; } + /** + * Convert the budget to a price object. + * + * @return a Price object that have the same amount with the budget. + */ + public Price convertToPrice() { + return new Price(value); + } @Override public String toString() { return "$" + value; diff --git a/src/main/java/seedu/address/model/customer/SameCustomerPredicate.java b/src/main/java/seedu/address/model/customer/SameCustomerPredicate.java new file mode 100644 index 00000000000..af08c7b5ea0 --- /dev/null +++ b/src/main/java/seedu/address/model/customer/SameCustomerPredicate.java @@ -0,0 +1,48 @@ +package seedu.address.model.customer; + +import java.util.function.Predicate; + +import seedu.address.commons.util.ToStringBuilder; + +/** + * Tests that a {@code Customer} is same with the given customer. + */ +public class SameCustomerPredicate implements Predicate { + + private final Customer customer; + + /** + * Constructs a {@code SameCustomerPredicate}. + * + * @param customer the specified customer + */ + public SameCustomerPredicate(Customer customer) { + this.customer = customer; + } + + @Override + public boolean test(Customer targetCustomer) { + return customer.equals(targetCustomer); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof SameCustomerPredicate)) { + return false; + } + + SameCustomerPredicate otherSameCustomerPredicate = (SameCustomerPredicate) other; + return this.customer == otherSameCustomerPredicate.customer; + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .add("Customer", customer).toString(); + } +} diff --git a/src/main/java/seedu/address/model/property/Price.java b/src/main/java/seedu/address/model/property/Price.java index 24c08b432d9..07001940e65 100644 --- a/src/main/java/seedu/address/model/property/Price.java +++ b/src/main/java/seedu/address/model/property/Price.java @@ -4,6 +4,8 @@ import static java.util.Objects.requireNonNull; import static seedu.address.commons.util.AppUtil.checkArgument; +import seedu.address.model.customer.Budget; + /** * Represents a Price in the Property book. * Guarantees: details are present and not null, field values are validated, immutable. @@ -46,6 +48,14 @@ public boolean isInRangePrice(Price other) { return isNull(other) || amount <= other.amount; } + /** + * Convert the price to a budget object. + * + * @return a budget object that have the same amount with the price. + */ + public Budget convertToBudget() { + return new Budget(value); + } @Override public String toString() { return "$" + value; diff --git a/src/main/java/seedu/address/model/property/Property.java b/src/main/java/seedu/address/model/property/Property.java index de7172da2c7..cc3e6b4c0f2 100644 --- a/src/main/java/seedu/address/model/property/Property.java +++ b/src/main/java/seedu/address/model/property/Property.java @@ -88,12 +88,12 @@ public boolean equals(Object other) { return false; } - Property otherPerson = (Property) other; - return propName.equals(otherPerson.propName) - && propPhone.equals(otherPerson.propPhone) - && price.equals(otherPerson.price) - && propAddress.equals(otherPerson.propAddress) - && tags.equals(otherPerson.tags); + Property otherProperty = (Property) other; + return propName.equals(otherProperty.propName) + && propPhone.equals(otherProperty.propPhone) + && price.equals(otherProperty.price) + && propAddress.equals(otherProperty.propAddress) + && tags.equals(otherProperty.tags); } @Override diff --git a/src/main/java/seedu/address/model/property/SamePropertyPredicate.java b/src/main/java/seedu/address/model/property/SamePropertyPredicate.java new file mode 100644 index 00000000000..16d6570ee50 --- /dev/null +++ b/src/main/java/seedu/address/model/property/SamePropertyPredicate.java @@ -0,0 +1,48 @@ +package seedu.address.model.property; + +import java.util.function.Predicate; + +import seedu.address.commons.util.ToStringBuilder; + +/** + * Tests that a {@code Property} is same with the given property. + */ +public class SamePropertyPredicate implements Predicate { + + private final Property property; + + /** + * Constructs a {@code SamePropertyPredicate}. + * + * @param property the specified property + */ + public SamePropertyPredicate(Property property) { + this.property = property; + } + + @Override + public boolean test(Property targetProperty) { + return property.equals(targetProperty); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof SamePropertyPredicate)) { + return false; + } + + SamePropertyPredicate otherSameCustomerPredicate = (SamePropertyPredicate) other; + return this.property == otherSameCustomerPredicate.property; + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .add("Property", property).toString(); + } +} diff --git a/src/main/java/seedu/address/storage/JsonAdaptedProperty.java b/src/main/java/seedu/address/storage/JsonAdaptedProperty.java index 0f2f3f93c91..10fdfc8bfe9 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedProperty.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedProperty.java @@ -81,6 +81,15 @@ public Property toModelType() throws IllegalValueException { } final PropName modelPropName = new PropName(name); + if (address == null) { + throw new IllegalValueException( + String.format(MISSING_FIELD_MESSAGE_FORMAT, PropAddress.class.getSimpleName())); + } + if (!PropAddress.isValidAddress(address)) { + throw new IllegalValueException(PropAddress.MESSAGE_CONSTRAINTS); + } + final PropAddress modelPropAddress = new PropAddress(address); + if (phone == null) { throw new IllegalValueException( String.format(MISSING_FIELD_MESSAGE_FORMAT, PropPhone.class.getSimpleName())); @@ -99,15 +108,6 @@ public Property toModelType() throws IllegalValueException { } final Price modelPrice = new Price(price); - if (address == null) { - throw new IllegalValueException( - String.format(MISSING_FIELD_MESSAGE_FORMAT, PropAddress.class.getSimpleName())); - } - if (!PropAddress.isValidAddress(address)) { - throw new IllegalValueException(PropAddress.MESSAGE_CONSTRAINTS); - } - final PropAddress modelPropAddress = new PropAddress(address); - final Set modelTags = new HashSet<>(personTags); return new Property(modelPropName, modelPropAddress, modelPropPhone, modelPrice, modelTags); } diff --git a/src/main/java/seedu/address/ui/PropertyCard.java b/src/main/java/seedu/address/ui/PropertyCard.java index 783c3347f87..d0bb37ab2bf 100644 --- a/src/main/java/seedu/address/ui/PropertyCard.java +++ b/src/main/java/seedu/address/ui/PropertyCard.java @@ -52,7 +52,7 @@ public PropertyCard(Property property, int displayedIndex) { name.setText(property.getName().fullName); phone.setText(property.getPhone().value); address.setText(property.getAddress().value); - price.setText(property.getPrice().value); + price.setText(property.getPrice().toString()); property.getTags().stream() .sorted(Comparator.comparing(tag -> tag.tagName)) .forEach(tag -> tags.getChildren().add(new Label(tag.tagName))); diff --git a/src/test/java/seedu/address/logic/commands/AddCustomerCommandTest.java b/src/test/java/seedu/address/logic/commands/AddCustomerCommandTest.java index 90798fcfcae..934f084fbb2 100644 --- a/src/test/java/seedu/address/logic/commands/AddCustomerCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/AddCustomerCommandTest.java @@ -208,6 +208,16 @@ public void updateFilteredCustomerList(Predicate predicate) { public void updateFilteredPropertyList(Predicate predicate) { throw new AssertionError("This method should not be called."); } + + @Override + public void updateMatchedCustomerList(Customer targetCustomer, Predicate predicate) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void updateMatchedPropertyList(Property targetProperty, Predicate predicate) { + throw new AssertionError("This method should not be called."); + } } /** diff --git a/src/test/java/seedu/address/logic/commands/AddPropertyCommandTest.java b/src/test/java/seedu/address/logic/commands/AddPropertyCommandTest.java index 8ea35c47e19..a6abb1227a5 100644 --- a/src/test/java/seedu/address/logic/commands/AddPropertyCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/AddPropertyCommandTest.java @@ -209,6 +209,16 @@ public void updateFilteredCustomerList(Predicate predicate) { public void updateFilteredPropertyList(Predicate predicate) { throw new AssertionError("This method should not be called."); } + + @Override + public void updateMatchedCustomerList(Customer targetCustomer, Predicate predicate) { + throw new AssertionError("This method should not be called."); + } + + @Override + public void updateMatchedPropertyList(Property targetProperty, Predicate predicate) { + throw new AssertionError("This method should not be called."); + } } /** diff --git a/src/test/java/seedu/address/logic/commands/MatchCustomerCommandTest.java b/src/test/java/seedu/address/logic/commands/MatchCustomerCommandTest.java new file mode 100644 index 00000000000..1603f7cf034 --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/MatchCustomerCommandTest.java @@ -0,0 +1,104 @@ +package seedu.address.logic.commands; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.address.logic.commands.CommandPropertyTestUtil.assertCommandFailure; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.testutil.TypicalCustomers.getTypicalAddressBook; +import static seedu.address.testutil.TypicalCustomers.getTypicalCustomers; +import static seedu.address.testutil.TypicalProperties.getTypicalPropertyBook; + +import java.util.Set; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import seedu.address.logic.Messages; +import seedu.address.logic.parser.MatchCustomerCommandParser; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; +import seedu.address.model.customer.Budget; +import seedu.address.model.customer.Customer; +import seedu.address.model.property.Price; +import seedu.address.model.property.PriceAndTagsInRangePredicate; +import seedu.address.model.tag.Tag; + +/** + * Contains integration tests (interaction with the Model) and unit tests for MatchCustomerCommand. + */ +public class MatchCustomerCommandTest { + + private Model model; + private Model expectedModel; + + @BeforeEach + public void setUp() { + model = new ModelManager(getTypicalAddressBook(), getTypicalPropertyBook(), new UserPrefs()); + expectedModel = new ModelManager(model.getAddressBook(), model.getPropertyBook(), new UserPrefs()); + } + + @Test + public void equals() { + MatchCustomerCommand matchFirstCustomerCommand = prepareIndex("1"); + MatchCustomerCommand matchSecondCustomerCommand = prepareIndex("2"); + + //same object returns true. + assertTrue(matchFirstCustomerCommand.equals(matchFirstCustomerCommand)); + + //same index returns true. + assertTrue(matchFirstCustomerCommand.equals(prepareIndex("1"))); + + //different types returns false. + assertFalse(matchFirstCustomerCommand.equals(1)); + assertFalse(matchFirstCustomerCommand.equals("1")); + + //null returns false. + assertFalse(matchFirstCustomerCommand.equals(null)); + + //different index return false + assertFalse(matchFirstCustomerCommand.equals(matchSecondCustomerCommand)); + assertFalse(matchFirstCustomerCommand.equals(prepareIndex("2"))); + + } + + @Test + public void execute_customerNotFound_showsError() { + String index = "100"; + MatchCustomerCommand matchCustomerCommand = prepareIndex(index); + assertCommandFailure(matchCustomerCommand, model, MatchCustomerCommand.MESSAGE_FAIL + index); + } + + @Test + public void execute_customerFound_propertyFiltered() { + String index = "1"; + + MatchCustomerCommand matchCustomerCommand = prepareIndex(index); + + Customer customer = getTypicalCustomers().get(0); + + Budget budget = customer.getBudget(); + Set tags = customer.getTags(); + + Price price = budget.convertToPrice(); + PriceAndTagsInRangePredicate predicate = new PriceAndTagsInRangePredicate(price, tags); + + expectedModel.updateMatchedCustomerList(customer, predicate); + + String expectedMessage = String.format( + Messages.MESSAGE_CUSTOMERS_MATCH_OVERVIEW + index, + expectedModel.getFilteredPropertyList().size() + ); + assertCommandSuccess(matchCustomerCommand, model, expectedMessage, expectedModel); + } + + private MatchCustomerCommand prepareIndex(String message) { + try { + return (new MatchCustomerCommandParser()).parse(message); + } catch (ParseException pe) { + assert false; + return null; + } + } +} diff --git a/src/test/java/seedu/address/logic/parser/MatchCustomerCommandParserTest.java b/src/test/java/seedu/address/logic/parser/MatchCustomerCommandParserTest.java new file mode 100644 index 00000000000..2a781e925af --- /dev/null +++ b/src/test/java/seedu/address/logic/parser/MatchCustomerCommandParserTest.java @@ -0,0 +1,41 @@ +package seedu.address.logic.parser; + +import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure; +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess; + +import org.junit.jupiter.api.Test; + +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.MatchCustomerCommand; +import seedu.address.logic.parser.exceptions.ParseException; + +public class MatchCustomerCommandParserTest { + private MatchCustomerCommandParser parser = new MatchCustomerCommandParser(); + + @Test + public void parse_emptyArg_throwsParseException() { + assertParseFailure(parser, " ", + String.format(MESSAGE_INVALID_COMMAND_FORMAT, MatchCustomerCommand.MESSAGE_USAGE)); + } + + @Test + public void parse_validArgs_returnsMatchCustomerCommand() throws ParseException { + String indexString = "1"; + Index index; + try { + index = ParserUtil.parseIndex(indexString); + } catch (ParseException pe) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, + MatchCustomerCommand.MESSAGE_USAGE), + pe + ); + } + String userInput = indexString; + + MatchCustomerCommand expectedMatchCustomerCommand = + new MatchCustomerCommand(index); + assertParseSuccess(parser, userInput, expectedMatchCustomerCommand); + } +} diff --git a/src/test/java/seedu/address/logic/parser/MatchPropertyCommandParserTest.java b/src/test/java/seedu/address/logic/parser/MatchPropertyCommandParserTest.java new file mode 100644 index 00000000000..a0c74f429c2 --- /dev/null +++ b/src/test/java/seedu/address/logic/parser/MatchPropertyCommandParserTest.java @@ -0,0 +1,41 @@ +package seedu.address.logic.parser; + +import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure; +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess; + +import org.junit.jupiter.api.Test; + +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.MatchPropertyCommand; +import seedu.address.logic.parser.exceptions.ParseException; + +public class MatchPropertyCommandParserTest { + private MatchPropertyCommandParser parser = new MatchPropertyCommandParser(); + + @Test + public void parse_emptyArg_throwsParseException() { + assertParseFailure(parser, " ", + String.format(MESSAGE_INVALID_COMMAND_FORMAT, MatchPropertyCommand.MESSAGE_USAGE)); + } + + @Test + public void parse_validArgs_returnsMatchCustomerCommand() throws ParseException { + String indexString = "1"; + Index index; + try { + index = ParserUtil.parseIndex(indexString); + } catch (ParseException pe) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, + MatchPropertyCommand.MESSAGE_USAGE), + pe + ); + } + String userInput = indexString; + + MatchPropertyCommand expectedMatchPropertyCommand = + new MatchPropertyCommand(index); + assertParseSuccess(parser, userInput, expectedMatchPropertyCommand); + } +} diff --git a/src/test/java/seedu/address/storage/JsonAdaptedPropertyTest.java b/src/test/java/seedu/address/storage/JsonAdaptedPropertyTest.java new file mode 100644 index 00000000000..c29f996d131 --- /dev/null +++ b/src/test/java/seedu/address/storage/JsonAdaptedPropertyTest.java @@ -0,0 +1,114 @@ +package seedu.address.storage; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static seedu.address.storage.JsonAdaptedProperty.MISSING_FIELD_MESSAGE_FORMAT; +import static seedu.address.testutil.Assert.assertThrows; +import static seedu.address.testutil.TypicalProperties.AQUAVIEW; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.Test; + +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.property.Price; +import seedu.address.model.property.PropAddress; +import seedu.address.model.property.PropName; +import seedu.address.model.property.PropPhone; + +public class JsonAdaptedPropertyTest { + private static final String INVALID_PROPNAME = " "; + private static final String INVALID_PROPPHONE = "+651234"; + private static final String INVALID_PRICE = "-1000"; + private static final String INVALID_PROPADDRESS = ""; + private static final String INVALID_TAG = "#friend"; + + private static final String VALID_PROPNAME = AQUAVIEW.getName().toString(); + private static final String VALID_PROPPHONE = AQUAVIEW.getPhone().toString(); + private static final String VALID_PROPADDRESS = AQUAVIEW.getAddress().toString(); + private static final String VALID_PRICE = AQUAVIEW.getPrice().toString(); + private static final List VALID_TAGS = AQUAVIEW.getTags().stream() + .map(JsonAdaptedTag::new) + .collect(Collectors.toList()); + + @Test + public void toModelType_validPropertyDetails_returnsProperty() throws Exception { + JsonAdaptedProperty property = new JsonAdaptedProperty(AQUAVIEW); + assertEquals(AQUAVIEW, property.toModelType()); + } + + @Test + public void toModelType_invalidName_throwsIllegalValueException() { + JsonAdaptedProperty property = + new JsonAdaptedProperty(INVALID_PROPNAME, VALID_PROPADDRESS, VALID_PROPPHONE, VALID_PRICE, VALID_TAGS); + String expectedMessage = PropName.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, property::toModelType); + } + + @Test + public void toModelType_nullName_throwsIllegalValueException() { + JsonAdaptedProperty property = new JsonAdaptedProperty(null, VALID_PROPADDRESS, VALID_PROPPHONE, + VALID_PRICE, VALID_TAGS); + String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, PropName.class.getSimpleName()); + assertThrows(IllegalValueException.class, expectedMessage, property::toModelType); + } + + @Test + public void toModelType_invalidAddress_throwsIllegalValueException() { + JsonAdaptedProperty property = new JsonAdaptedProperty(VALID_PROPNAME, INVALID_PROPADDRESS, VALID_PROPPHONE, + VALID_PRICE, VALID_TAGS); + String expectedMessage = PropAddress.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, property::toModelType); + } + + @Test + public void toModelType_nullAddress_throwsIllegalValueException() { + JsonAdaptedProperty property = new JsonAdaptedProperty(VALID_PROPNAME, null, VALID_PROPPHONE, + VALID_PRICE, VALID_TAGS); + String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, PropAddress.class.getSimpleName()); + assertThrows(IllegalValueException.class, expectedMessage, property::toModelType); + } + + @Test + public void toModelType_invalidPhone_throwsIllegalValueException() { + JsonAdaptedProperty property = new JsonAdaptedProperty(VALID_PROPNAME, VALID_PROPADDRESS, INVALID_PROPPHONE, + VALID_PRICE, VALID_TAGS); + String expectedMessage = PropPhone.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, property::toModelType); + } + + @Test + public void toModelType_nullPhone_throwsIllegalValueException() { + JsonAdaptedProperty property = new JsonAdaptedProperty(VALID_PROPNAME, VALID_PROPADDRESS, null, + VALID_PRICE, VALID_TAGS); + String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, PropPhone.class.getSimpleName()); + assertThrows(IllegalValueException.class, expectedMessage, property::toModelType); + } + + @Test + public void toModelType_invalidPrice_throwsIllegalValueException() { + JsonAdaptedProperty property = new JsonAdaptedProperty(VALID_PROPNAME, VALID_PROPADDRESS, VALID_PROPPHONE, + INVALID_PRICE, VALID_TAGS); + String expectedMessage = Price.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, property::toModelType); + } + + @Test + public void toModelType_nullPrice_throwsIllegalValueException() { + JsonAdaptedProperty property = new JsonAdaptedProperty(VALID_PROPNAME, VALID_PROPADDRESS, VALID_PROPPHONE, + null, VALID_TAGS); + String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Price.class.getSimpleName()); + assertThrows(IllegalValueException.class, expectedMessage, property::toModelType); + } + + @Test + public void toModelType_invalidTags_throwsIllegalValueException() { + List invalidTags = new ArrayList<>(VALID_TAGS); + invalidTags.add(new JsonAdaptedTag(INVALID_TAG)); + JsonAdaptedProperty property = + new JsonAdaptedProperty(VALID_PROPNAME, VALID_PROPADDRESS, VALID_PROPPHONE, VALID_PRICE, invalidTags); + assertThrows(IllegalValueException.class, property::toModelType); + } + +}