From cb81835c48dad436149dbe610951b99066e245f4 Mon Sep 17 00:00:00 2001 From: Shradheya Thakre Date: Tue, 31 Oct 2017 23:06:31 +0800 Subject: [PATCH 1/2] Collated Code --- collated/main/tshradheya-unused.md | 57 + collated/main/tshradheya.md | 1761 ++++++++++++++++++++++++++++ collated/test/tshradheya-unused.md | 56 + collated/test/tshradheya.md | 1670 ++++++++++++++++++++++++++ 4 files changed, 3544 insertions(+) create mode 100644 collated/main/tshradheya-unused.md create mode 100644 collated/main/tshradheya.md create mode 100644 collated/test/tshradheya-unused.md create mode 100644 collated/test/tshradheya.md diff --git a/collated/main/tshradheya-unused.md b/collated/main/tshradheya-unused.md new file mode 100644 index 000000000000..53f05bfd5546 --- /dev/null +++ b/collated/main/tshradheya-unused.md @@ -0,0 +1,57 @@ +# tshradheya-unused +###### \java\seedu\address\commons\events\storage\ReadAndStoreImage.java +``` java +package seedu.address.commons.events.storage; + +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_IMAGE; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +import seedu.address.logic.commands.DisplayPictureCommand; +import seedu.address.logic.parser.exceptions.ImageException; + +/** + * To read image from specified path and store in @file resources/pictures + */ +public class ReadAndStoreImage { + + /** + * @param path + * @return uniquePath new path in directory + */ + public String execute(String path, int newPath) throws IOException { + + File fileToRead = null; + BufferedImage image = null; + + File fileToWrite = null; + + String uniquePath = null; + + try { + fileToRead = new File(path); + image = new BufferedImage(963, 640, BufferedImage.TYPE_INT_ARGB); + image = ImageIO.read(fileToRead); + + uniquePath = Integer.toString(newPath); + + fileToWrite = new File("src\\main\\resources\\pictures\\" + uniquePath + ".jpg"); + ImageIO.write(image, "jpg", fileToWrite); + + + } catch (IOException e) { + throw new ImageException(String.format(MESSAGE_INVALID_IMAGE, + DisplayPictureCommand.MESSAGE_IMAGE_PATH_FAIL)); + } + + return uniquePath; + + } + + +} +``` diff --git a/collated/main/tshradheya.md b/collated/main/tshradheya.md new file mode 100644 index 000000000000..707b74d8762b --- /dev/null +++ b/collated/main/tshradheya.md @@ -0,0 +1,1761 @@ +# tshradheya +###### \java\seedu\address\commons\events\model\DisplayPictureChangedEvent.java +``` java +package seedu.address.commons.events.model; + +import seedu.address.commons.events.BaseEvent; + +/** + * Event to trigger reading and storing of image + */ +public class DisplayPictureChangedEvent extends BaseEvent { + + public final String path; + public final int newPath; + private boolean isRead; + + public DisplayPictureChangedEvent(String path, int newPath) { + this.path = path; + this.newPath = newPath; + isRead = true; + } + + public boolean isRead() { + return isRead; + } + + public void setRead(boolean b) { + isRead = b; + } + + @Override + public String toString() { + return newPath + " stored"; + } +} +``` +###### \java\seedu\address\commons\events\model\PopularContactChangedEvent.java +``` java +package seedu.address.commons.events.model; + +import seedu.address.commons.events.BaseEvent; +import seedu.address.model.Model; + +/** + * Event to handle change of popular contact list + */ +public class PopularContactChangedEvent extends BaseEvent { + + private Model model; + + public PopularContactChangedEvent(Model model) { + this.model = model; + } + + public Model getModel() { + return model; + } + + @Override + public String toString() { + return "Updated Popular Contact List"; + } +} +``` +###### \java\seedu\address\commons\events\ui\PopularContactPanelSelectionChangedEvent.java +``` java +package seedu.address.commons.events.ui; + +import seedu.address.commons.events.BaseEvent; +import seedu.address.ui.PopularContactCard; + +/** + * Represents a selection change in the Popular Contact Panel + */ +public class PopularContactPanelSelectionChangedEvent extends BaseEvent { + + private final PopularContactCard newSelection; + + public PopularContactPanelSelectionChangedEvent(PopularContactCard newSelection) { + this.newSelection = newSelection; + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } + + public PopularContactCard getNewSelection() { + return newSelection; + } +} +``` +###### \java\seedu\address\commons\events\ui\SendingEmailEvent.java +``` java +package seedu.address.commons.events.ui; + +import seedu.address.commons.events.BaseEvent; +import seedu.address.model.email.Body; +import seedu.address.model.email.Service; +import seedu.address.model.email.Subject; + +/** + * Event raised on 'email' command's successful execution + */ +public class SendingEmailEvent extends BaseEvent { + + public final String recipients; + public final Subject subject; + public final Body body; + public final Service service; + + public SendingEmailEvent(String recipients, Subject subject, Body body, Service service) { + this.recipients = recipients; + this.subject = subject; + this.body = body; + this.service = service; + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} +``` +###### \java\seedu\address\commons\events\ui\ShowLocationEvent.java +``` java +package seedu.address.commons.events.ui; + +import seedu.address.commons.events.BaseEvent; +import seedu.address.model.person.ReadOnlyPerson; + +/** + * Event raised on 'location' command's successful execution + */ +public class ShowLocationEvent extends BaseEvent { + + public final ReadOnlyPerson person; + + public ShowLocationEvent(ReadOnlyPerson person) { + this.person = person; + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} +``` +###### \java\seedu\address\logic\commands\DisplayPictureCommand.java +``` java +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_DISPLAYPICTURE; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.person.DisplayPicture; +import seedu.address.model.person.Person; +import seedu.address.model.person.ReadOnlyPerson; +import seedu.address.model.person.exceptions.DuplicatePersonException; +import seedu.address.model.person.exceptions.PersonNotFoundException; + +/** + * Adds a display picture to an existing person in address book + */ +public class DisplayPictureCommand extends Command { + + public static final String COMMAND_WORD = "displaypic"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds/Updates the profile picture of a person identified " + + "by the index number used in the last person listing. " + + "Existing Display picture will be updated by the image referenced in the input path. \n" + + "Parameters: INDEX (must be a positive integer) " + + PREFIX_DISPLAYPICTURE + "[PATH]\n" + + "Example: " + COMMAND_WORD + " 2 " + + "C:\\Users\\Admin\\Desktop\\pic.jpg"; + + public static final String MESSAGE_ADD_DISPLAYPICTURE_SUCCESS = "Added Display Picture to Person: %1$s"; + + public static final String MESSAGE_DELETE_DISPLAYPICTURE_SUCCESS = "Removed Display Picture from Person: %1$s"; + + public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book."; + + public static final String MESSAGE_IMAGE_PATH_FAIL = + "This specified path cannot be read. Please check it's validity and try again"; + + + private Index index; + private DisplayPicture displayPicture; + + /** + * @param index of the person in the filtered person list to edit the remark + * @param displayPicture of the person + */ + public DisplayPictureCommand(Index index, DisplayPicture displayPicture) { + requireNonNull(index); + requireNonNull(displayPicture); + + this.index = index; + this.displayPicture = displayPicture; + } + + @Override + public CommandResult execute() throws CommandException, IOException, URISyntaxException { + List lastShownList = model.getFilteredPersonList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + + ReadOnlyPerson personToEdit = lastShownList.get(index.getZeroBased()); + + if (displayPicture.getPath().equalsIgnoreCase("")) { + displayPicture.setPath(""); + + Person editedPerson = new Person(personToEdit.getName(), personToEdit.getPhone(), personToEdit.getEmail(), + personToEdit.getAddress(), personToEdit.getBirthday(), personToEdit.getNickname(), + displayPicture, personToEdit.getPopularityCounter(), personToEdit.getTags()); + + try { + model.updatePerson(personToEdit, editedPerson); + } catch (DuplicatePersonException dpe) { + throw new CommandException(MESSAGE_DUPLICATE_PERSON); + } catch (PersonNotFoundException pnfe) { + throw new AssertionError("The target person cannot be missing"); + } + model.updateFilteredListToShowAll(); + + return new CommandResult(generateSuccessMessage(editedPerson)); + } + + + boolean isExecutedProperly = model.addDisplayPicture(displayPicture.getPath(), + personToEdit.getEmail().hashCode()); + if (isExecutedProperly) { + displayPicture.setPath(Integer.toString(personToEdit.getEmail().hashCode())); + } else { + displayPicture.setPath(""); + return new CommandResult(generateFailureMessage()); + } + + Person editedPerson = new Person(personToEdit.getName(), personToEdit.getPhone(), personToEdit.getEmail(), + personToEdit.getAddress(), personToEdit.getBirthday(), personToEdit.getNickname(), + displayPicture, personToEdit.getPopularityCounter(), personToEdit.getTags()); + + try { + model.updatePerson(personToEdit, editedPerson); + } catch (DuplicatePersonException dpe) { + throw new CommandException(MESSAGE_DUPLICATE_PERSON); + } catch (PersonNotFoundException pnfe) { + throw new AssertionError("The target person cannot be missing"); + } + model.updateFilteredListToShowAll(); + + return new CommandResult(generateSuccessMessage(editedPerson)); + } + + /** + * Generates failure message + * @return String + */ + private String generateFailureMessage() { + return MESSAGE_IMAGE_PATH_FAIL; + } + + /** + * Generates success message + * @param personToEdit is checked + * @return String + */ + private String generateSuccessMessage(ReadOnlyPerson personToEdit) { + if (!displayPicture.getPath().isEmpty()) { + return String.format(MESSAGE_ADD_DISPLAYPICTURE_SUCCESS, personToEdit); + } else { + return String.format(MESSAGE_DELETE_DISPLAYPICTURE_SUCCESS, personToEdit); + } + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof DisplayPictureCommand)) { + return false; + } + + // state check + DisplayPictureCommand e = (DisplayPictureCommand) other; + return index.equals(e.index) + && displayPicture.equals(e.displayPicture); + } +} +``` +###### \java\seedu\address\logic\commands\EmailCommand.java +``` java +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL_BODY; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL_SERVICE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL_SUBJECT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL_TO; + +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.email.Body; +import seedu.address.model.email.Service; +import seedu.address.model.email.Subject; +import seedu.address.model.person.PersonContainsTagPredicate; + +/** + * Emails all people with a particular tag either using gmail/outlook + */ +public class EmailCommand extends Command { + + public static final String COMMAND_WORD = "email"; + public static final String MESSAGE_EMAIL_SENT = "Email ."; + public static final String MESSAGE_NOT_SENT = "Please enter a valid name/tag with a valid Email ID."; + public static final String EMAIL_SERVICE_GMAIL = "gmail"; + public static final String EMAIL_SERVICE_OUTLOOK = "outlook"; + public static final String MESSAGE_USAGE = COMMAND_WORD + ": people in the Address Book.\n" + + "The 'to' field is compulsory\n" + + "The 'to' field can take tag and it only supports one parameter.\n" + + "Parameters: " + + PREFIX_EMAIL_SERVICE + "SERVICE " + + PREFIX_EMAIL_TO + "TAGS " + + PREFIX_EMAIL_SUBJECT + "SUBJECT " + + PREFIX_EMAIL_BODY + "BODY \n" + + "Example: " + COMMAND_WORD + " " + + PREFIX_EMAIL_SERVICE + "gmail" + + PREFIX_EMAIL_TO + "cs2103" + + PREFIX_EMAIL_SUBJECT + "Meeting " + + PREFIX_EMAIL_BODY + "On Monday "; + + private PersonContainsTagPredicate predicate; + private Subject subject; + private Body body; + private Service service; + + public EmailCommand(PersonContainsTagPredicate predicate, Subject subject, Body body, Service service) { + this.predicate = predicate; + this.subject = subject; + this.body = body; + this.service = service; + + } + + /** + * Calls event for opening the url in browser panel + * @param recipients String of all recipients + * @throws ParseException when wrong recipients + */ + public void processEmail(String recipients) throws ParseException { + requireNonNull(recipients); + + if (recipients.equals("")) { + throw new ParseException("Invalid recipients"); + } + model.processEmailEvent(recipients, subject, body, service); + } + + /** + * Checks if service is one of the offered service of "gmail" or "outlook" + * @param service mentioned by the user + * @throws ParseException if not an offered service + */ + public void checkServiceValid(Service service) throws ParseException { + if (!service.service.equalsIgnoreCase(EMAIL_SERVICE_GMAIL) + && !service.service.equalsIgnoreCase(EMAIL_SERVICE_OUTLOOK)) { + throw new ParseException("Invalid service"); + } + } + + + @Override + public CommandResult execute() { + + + try { + checkServiceValid(service); + String emailTo = model.createEmailRecipients(predicate); + processEmail(emailTo); + } catch (ParseException e) { + e.printStackTrace(); + return new CommandResult(MESSAGE_NOT_SENT); + } + return new CommandResult(MESSAGE_EMAIL_SENT); + } + + public void setService(Service service) { + this.service = service; + } + + public void setBody(Body body) { + this.body = body; + } + + public void setSubject(Subject subject) { + this.subject = subject; + } + + public void setPredicate(PersonContainsTagPredicate predicate) { + this.predicate = predicate; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof EmailCommand // instanceof handles nulls + && this.predicate.equals(((EmailCommand) other).predicate)); // state check + } +} +``` +###### \java\seedu\address\logic\commands\LocationCommand.java +``` java +package seedu.address.logic.commands; + +import static seedu.address.logic.commands.EditCommand.MESSAGE_DUPLICATE_PERSON; + +import java.util.List; + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.person.ReadOnlyPerson; +import seedu.address.model.person.exceptions.DuplicatePersonException; +import seedu.address.model.person.exceptions.PersonNotFoundException; + +/** + * Shows location in Google maps of the specified person + */ +public class LocationCommand extends Command { + + public static final String COMMAND_WORD = "location"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Displays the location of specified person. " + + "Parameters: INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + " 1"; + + public static final String MESSAGE_FIND_LOCATION_SUCCESS = "Location of %1$s: %2$s"; + + private final Index index; + + public LocationCommand(Index index) { + this.index = index; + } + + @Override + public CommandResult execute() throws CommandException { + List lastShownList = model.getFilteredPersonList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + + ReadOnlyPerson personWhoseLocationIsToBeShown = lastShownList.get(index.getZeroBased()); + + try { + model.updatePersonsPopularityCounterByOne(lastShownList.get(index.getZeroBased())); + } catch (DuplicatePersonException dpe) { + throw new CommandException(MESSAGE_DUPLICATE_PERSON); + } catch (PersonNotFoundException pnfe) { + throw new AssertionError("The target person cannot be missing"); + } + + try { + model.showLocation(personWhoseLocationIsToBeShown); + } catch (PersonNotFoundException pnfe) { + assert false : "The target person cannot be missing"; + } + return new CommandResult(String.format(MESSAGE_FIND_LOCATION_SUCCESS, + personWhoseLocationIsToBeShown.getName().fullName, personWhoseLocationIsToBeShown.getAddress())); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof LocationCommand // instanceof handles nulls + && this.index.equals(((LocationCommand) other).index)); // state check + } + + +} +``` +###### \java\seedu\address\logic\commands\ViewTagCommand.java +``` java +package seedu.address.logic.commands; + +import seedu.address.model.person.PersonContainsTagPredicate; + +/** + * Finds and lists all persons in address book who are associated with the tag given in keywords + * Keyword matching is case sensitive. + */ + +public class ViewTagCommand extends Command { + + public static final String COMMAND_WORD = "viewtag"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons who are associated with the tag in " + + "the specified keywords (case-sensitive) and displays them as a list with index numbers.\n" + + "Parameters: KEYWORD\n" + + "Example: " + COMMAND_WORD + " cs2103"; + + + private final PersonContainsTagPredicate predicate; + + public ViewTagCommand(PersonContainsTagPredicate predicate) { + this.predicate = predicate; + } + + @Override + public CommandResult execute() { + model.updateFilteredPersonListForViewTag(predicate); + return new CommandResult(getMessageForPersonListShownSummary(model.getFilteredPersonList().size())); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ViewTagCommand // instanceof handles nulls + && this.predicate.equals(((ViewTagCommand) other).predicate)); // state check + } + + + + + + + + + + +} +``` +###### \java\seedu\address\logic\LogicManager.java +``` java + @Override + public ObservableList getListOfPersonsForPopularContacts() { + return model.getPopularContactList(); + } + +``` +###### \java\seedu\address\logic\parser\DisplayPictureCommandParser.java +``` java +package seedu.address.logic.parser; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; + +import seedu.address.commons.core.index.Index; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.logic.commands.DisplayPictureCommand; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.person.DisplayPicture; + +/** + * Parses input arguments and creates a new DisplayPictureCommand object + */ +public class DisplayPictureCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the DisplayPictureCommand + * and returns an DisplayPictureCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public DisplayPictureCommand parse(String args) throws ParseException { + requireNonNull(args); + String regex = "[\\s]+"; + String[] splitArgs = args.trim().split(regex, 2); + + Index index; + try { + index = ParserUtil.parseIndex(splitArgs[0]); + } catch (IllegalValueException ive) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, DisplayPictureCommand.MESSAGE_USAGE)); + } + + String path; + if (splitArgs.length > 1) { + path = splitArgs[1]; + } else { + path = ""; + } + + + return new DisplayPictureCommand(index, new DisplayPicture(path)); + } +} +``` +###### \java\seedu\address\logic\parser\EmailCommandParser.java +``` java +package seedu.address.logic.parser; + +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL_BODY; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL_SERVICE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL_SUBJECT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL_TO; + +import java.util.stream.Stream; + +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.logic.commands.EmailCommand; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.email.Body; +import seedu.address.model.email.Service; +import seedu.address.model.email.Subject; +import seedu.address.model.person.PersonContainsTagPredicate; + +/** + * Parses the input command and creates a EmailCommand object + */ +public class EmailCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the EmailCommand + * and returns an EmailCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public EmailCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args, PREFIX_EMAIL_SERVICE, PREFIX_EMAIL_TO, + PREFIX_EMAIL_SUBJECT, PREFIX_EMAIL_BODY); + + if (!arePrefixesPresent(argMultimap, PREFIX_EMAIL_SERVICE, PREFIX_EMAIL_TO)) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EmailCommand.MESSAGE_USAGE)); + } + + try { + Service service = new Service(argMultimap.getValue(PREFIX_EMAIL_SERVICE).get()); + String tagToWhichEmailHasToBeSent = + ParserUtil.parseRecipientTag(argMultimap.getValue(PREFIX_EMAIL_TO).get()); + Subject subject = new Subject(String.join("", + argMultimap.getAllValues(PREFIX_EMAIL_SUBJECT)).replace(" ", "+")); + Body body = new Body(String.join("", + argMultimap.getAllValues(PREFIX_EMAIL_BODY)).replace(" ", "+")); + return new EmailCommand(new PersonContainsTagPredicate(tagToWhichEmailHasToBeSent), subject, body, service); + } catch (IllegalValueException ive) { + throw new ParseException(ive.getMessage(), ive); + } + } + + /** + * Returns true if none of the prefixes contains empty {@code Optional} values in the given + * {@code ArgumentMultimap}. + */ + private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } + + +} +``` +###### \java\seedu\address\logic\parser\exceptions\ImageException.java +``` java +package seedu.address.logic.parser.exceptions; + +import java.io.IOException; + +/** + * Represents a image reading error encountered by a parser. + */ +public class ImageException extends IOException { + + public ImageException(String message) { + super(message); + } +} +``` +###### \java\seedu\address\logic\parser\LocationCommandParser.java +``` java +package seedu.address.logic.parser; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; + +import seedu.address.commons.core.index.Index; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.logic.commands.LocationCommand; +import seedu.address.logic.parser.exceptions.ParseException; + +/** + * Parses the `location' command + */ +public class LocationCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the LocationCommand + * and returns an LocationCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + @Override + public LocationCommand parse(String userInput) throws ParseException { + requireNonNull(userInput); + + Index index; + try { + index = ParserUtil.parseIndex(userInput); + } catch (IllegalValueException ive) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, LocationCommand.MESSAGE_USAGE)); + } + + return new LocationCommand(index); + } +} +``` +###### \java\seedu\address\logic\parser\ParserUtil.java +``` java + /** + * Parses a {@code Optional displayPicture} into an {@code Optional} + * if {@code path} is present. + * See header comment of this class regarding the use of {@code Optional} parameters. + */ + public static Optional parseDisplayPicture(Optional displayPicture) + throws IllegalValueException { + requireNonNull(displayPicture); + return displayPicture.isPresent() ? Optional.of(new DisplayPicture(displayPicture.get())) : Optional.empty(); + } + + /** + * Parses popularity counter for dummy purpose + * @param popularityCounter + * @return + * @throws IllegalValueException + */ + public static Optional parsePopularityCounter(Optional popularityCounter) + throws IllegalValueException { + requireNonNull(popularityCounter); + return popularityCounter.isPresent() + ? Optional.of(new PopularityCounter(Integer.parseInt(popularityCounter.get()))) : Optional.empty(); + } +``` +###### \java\seedu\address\logic\parser\ParserUtil.java +``` java + + /** + * Parses the given keyword tag into trimmed string + * @param tag keyword given by user + * @return trimmedTag which is trimmed for comparison purposes + * @throws IllegalValueException + */ + public static String parseRecipientTag(String tag) throws IllegalValueException { + requireNonNull(tag); + String trimmedTag = tag.trim(); + + return trimmedTag; + } +``` +###### \java\seedu\address\logic\parser\ViewTagCommandParser.java +``` java +package seedu.address.logic.parser; + +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; + +import seedu.address.logic.commands.ViewTagCommand; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.person.PersonContainsTagPredicate; + +/** + * Parses input arguments and creates a new ViewCommand object + */ +public class ViewTagCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the FindCommand + * and returns an FindCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public ViewTagCommand parse(String args) throws ParseException { + String trimmedArgs = args.trim(); + if (trimmedArgs.isEmpty()) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, ViewTagCommand.MESSAGE_USAGE)); + } + + return new ViewTagCommand(new PersonContainsTagPredicate(trimmedArgs)); + } + + + +} +``` +###### \java\seedu\address\model\email\Body.java +``` java +package seedu.address.model.email; + +import static java.util.Objects.requireNonNull; + +/** + * Represent's the body of an Email + */ +public class Body { + + public final String body; + + public Body(String body) { + requireNonNull(body); + String trimmedBody = body.trim(); + + this.body = trimmedBody; + } + + @Override + public String toString() { + return body; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Body // instanceof handles nulls + && this.body.equals(((Body) other).body)); // state check + } + + @Override + public int hashCode() { + return body.hashCode(); + } +} +``` +###### \java\seedu\address\model\email\Service.java +``` java +package seedu.address.model.email; + +import static java.util.Objects.requireNonNull; + +/** + * Specifies email service to use for processing email command + */ +public class Service { + public final String service; + + public Service(String service) { + requireNonNull(service); + String trimmedService = service.trim(); + + this.service = trimmedService; + } + + @Override + public String toString() { + return service; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Service // instanceof handles nulls + && this.service.equals(((Service) other).service)); // state check + } + + @Override + public int hashCode() { + return service.hashCode(); + } +} +``` +###### \java\seedu\address\model\email\Subject.java +``` java +package seedu.address.model.email; + +import static java.util.Objects.requireNonNull; + +/** + * Represent's subject of the Email being sent + */ +public class Subject { + + public final String subject; + + public Subject(String subject) { + requireNonNull(subject); + String trimmedSubject = subject.trim(); + + this.subject = trimmedSubject; + } + + @Override + public String toString() { + return subject; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Subject // instanceof handles nulls + && this.subject.equals(((Subject) other).subject)); // state check + } + + @Override + public int hashCode() { + return subject.hashCode(); + } +} +``` +###### \java\seedu\address\model\ModelManager.java +``` java + + /** Raises an event to indicate model has changed and favourite contacts might be updated */ + private void indicatePopularContactsChangedPossibility() { + raise(new PopularContactChangedEvent(this)); + + } + + /** Raises an event to indicate the picture has changed */ + private boolean indicateDisplayPictureChanged(String path, int newPath) throws IOException { + DisplayPictureChangedEvent displayPictureChangedEvent = new DisplayPictureChangedEvent(path, newPath); + raise(displayPictureChangedEvent); + return displayPictureChangedEvent.isRead(); + } +``` +###### \java\seedu\address\model\ModelManager.java +``` java + + @Override + public synchronized void addPerson(ReadOnlyPerson person) throws DuplicatePersonException { + addressBook.addPerson(person); + updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); + indicateAddressBookChanged(); + indicatePopularContactsChangedPossibility(); + updatePopularContactList(); + } + + @Override + public void updatePerson(ReadOnlyPerson target, ReadOnlyPerson editedPerson) + throws DuplicatePersonException, PersonNotFoundException { + requireAllNonNull(target, editedPerson); + + addressBook.updatePerson(target, editedPerson); + indicateAddressBookChanged(); + indicatePopularContactsChangedPossibility(); + updatePopularContactList(); + } +``` +###### \java\seedu\address\model\ModelManager.java +``` java + + @Override + public boolean addDisplayPicture(String path, int newPath) throws IOException { + return indicateDisplayPictureChanged(path, newPath); + } + + /** + * Shows location of the given person + */ + @Override + public void showLocation(ReadOnlyPerson person) throws PersonNotFoundException { + raise(new ShowLocationEvent(person)); + } + + /** + * Raises event for processing Email + */ + @Override + public void processEmailEvent(String recipients, Subject subject, Body body, Service service) { + raise(new SendingEmailEvent(recipients, subject, body, service)); + } + + /** + * Makes a string of all intended recipient through the given @predicate + */ + @Override + public String createEmailRecipients(Predicate predicate) { + requireNonNull(predicate); + + filteredPersonsForEmail.setPredicate(predicate); + increaseCounterByOneForATag(filteredPersonsForEmail); + + List validEmails = new ArrayList<>(); + for (ReadOnlyPerson person : filteredPersonsForEmail) { + if (Email.isValidEmail(person.getEmail().value)) { + validEmails.add(person.getEmail().value); + } + } + return String.join(",", validEmails); + } + + @Override + public void increaseCounterByOneForATag(List filteredPersonsForEmail) { + + for (ReadOnlyPerson person : filteredPersonsForEmail) { + try { + this.updatePersonsPopularityCounterByOne(person); + } catch (DuplicatePersonException dpe) { + assert false : "Duplicate"; + } catch (PersonNotFoundException pnfe) { + throw new AssertionError("The target person cannot be missing"); + } + } + } + + //=========== Update Popularity counter for the required commands ======================================= + + /** + * Increases the counter by 1 increasing popularity + * @param person whose popularity counter increased + */ + @Override + public void updatePersonsPopularityCounterByOne(ReadOnlyPerson person) throws DuplicatePersonException, + PersonNotFoundException { + ReadOnlyPerson editedPerson = increaseCounterByOne(person); + + addressBook.updatePerson(person, editedPerson); + indicateAddressBookChanged(); + indicatePopularContactsChangedPossibility(); + } + + @Override + public ReadOnlyPerson increaseCounterByOne(ReadOnlyPerson person) { + person.getPopularityCounter().increasePopularityCounter(); + return new Person(person.getName(), person.getPhone(), person.getEmail(), person.getAddress(), + person.getBirthday(), person.getNickname(), person.getDisplayPicture(), person.getPopularityCounter(), + person.getTags()); + } + + //=========== Filtered Popular Contact List Accessors and Mutators ======================================= + + /** + * Updates the popular contact list whenever address book is changed + */ + @Override + public void updatePopularContactList() { + refreshWithPopulatingAddressBook(); + listOfPersonsForPopularContacts.sort((o1, o2) -> + o2.getPopularityCounter().getCounter() - o1.getPopularityCounter().getCounter()); + + getOnlyTopFiveMaximum(); + } + + @Override + public void getOnlyTopFiveMaximum() { + while (listOfPersonsForPopularContacts.size() > 5) { + listOfPersonsForPopularContacts.remove(listOfPersonsForPopularContacts.size() - 1); + } + } + + @Override + public void refreshWithPopulatingAddressBook() { + listOfPersonsForPopularContacts = new ArrayList<>(this.addressBook.getPersonList()); + } + + @Override + public ObservableList getPopularContactList() { + updatePopularContactList(); + return FXCollections.observableList(listOfPersonsForPopularContacts); + } +``` +###### \java\seedu\address\model\ModelManager.java +``` java + + @Override + public void updateFilteredPersonListForViewTag(Predicate predicate) { + requireNonNull(predicate); + filteredPersons.setPredicate(predicate); + + increaseCounterByOneForATag(filteredPersons); + } +``` +###### \java\seedu\address\model\person\DisplayPicture.java +``` java +package seedu.address.model.person; + +import static java.util.Objects.requireNonNull; + +/** + * Represent's a person's display picture in the address book + * Guarantees : immutable; is always valid + */ +public class DisplayPicture { + + + private String path; + + public DisplayPicture(String path) { + requireNonNull(path); + this.path = path; + } + + @Override + public String toString() { + return path; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof DisplayPicture // instanceof handles nulls + && this.path.equals(((DisplayPicture) other).path)); // state check + } + + @Override + public int hashCode() { + return path.hashCode(); + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } +} +``` +###### \java\seedu\address\model\person\PersonContainsTagPredicate.java +``` java +package seedu.address.model.person; + +import java.util.Set; +import java.util.function.Predicate; + +import seedu.address.model.tag.Tag; + +/** + * Tests that a {@code ReadOnlyPerson}'s {@code Tags} matches the keyword given. + */ + +public class PersonContainsTagPredicate implements Predicate { + + private final String keyword; + + public PersonContainsTagPredicate(String keyword) { + this.keyword = keyword; + } + + @Override + public boolean test(ReadOnlyPerson person) { + Set tagsOfPerson = person.getTags(); + + return tagsOfPerson.stream() + .anyMatch(tagMatches -> tagMatches.getTagName().equalsIgnoreCase(keyword)); + + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof PersonContainsTagPredicate // instanceof handles nulls + && this.keyword.equals(((PersonContainsTagPredicate) other).keyword)); // state check + } + +} +``` +###### \java\seedu\address\model\person\PopularityCounter.java +``` java +package seedu.address.model.person; + +/** + * Represents a Person's frequency of visits in address book. + * Initially the value is 0 for all + */ +public class PopularityCounter { + + private int counter; + + public PopularityCounter() { + counter = 0; + } + + public PopularityCounter(int counter) { + this.counter = counter; + } + + /** + * Increases popularity by 1 when searched or viewed by selecting + */ + public void increasePopularityCounter() { + counter++; + } + + public void resetPopularityCounter() { + counter = 0; + } + + /** + * Gets popularity counter to form the favourite list of contacts + * @return popularity counter + */ + public int getCounter() { + return counter; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof PopularityCounter // instanceof handles nulls + && this.getCounter() == ((PopularityCounter) other).getCounter()); // state check + } +} +``` +###### \java\seedu\address\storage\AddressBookPictureStorage.java +``` java +package seedu.address.storage; + +import static java.util.Objects.requireNonNull; + +import java.io.File; +import java.io.IOException; + +import seedu.address.commons.util.FileUtil; + +/** + * To create a display picture resource folder + */ +public class AddressBookPictureStorage { + + private String filePath; + + public AddressBookPictureStorage(String filePath) { + this.filePath = filePath; + } + + /** + * Returns the file path of the pictures folder. + */ + public String getAddressBookPicturePath() { + return filePath; + } + + /** + * Creates a new folder for pictures storage + */ + public void createPictureStorageFolder() throws IOException { + requireNonNull(filePath); + + File file = new File(filePath); + FileUtil.createIfMissing(file); + + } +} +``` +###### \java\seedu\address\storage\DisplayPictureStorage.java +``` java +package seedu.address.storage; + +import java.awt.image.BufferedImage; +import java.io.IOException; + +/** + * Represents a storage for Display Picture. + */ +public interface DisplayPictureStorage { + + void readImageFromDevice(String imagePath, int newPath) throws IOException; + + void saveImageInDirectory(BufferedImage image, String uniquePath) throws IOException; + +} +``` +###### \java\seedu\address\storage\ImageDisplayPictureStorage.java +``` java +package seedu.address.storage; + +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_IMAGE; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +import seedu.address.logic.commands.DisplayPictureCommand; +import seedu.address.logic.parser.exceptions.ImageException; + +/** + * To read and store image + */ +public class ImageDisplayPictureStorage implements DisplayPictureStorage { + + public ImageDisplayPictureStorage() { + } + + /** + * Reads image from local device + * @throws IOException to display imagePath is wrong + */ + public void readImageFromDevice(String imagePath, int newPath) throws IOException { + File fileToRead = null; + BufferedImage image = null; + String uniquePath = null; + + try { + fileToRead = new File(imagePath); + image = new BufferedImage(963, 640, BufferedImage.TYPE_INT_ARGB); + image = ImageIO.read(fileToRead); + + uniquePath = Integer.toString(newPath); + + saveImageInDirectory(image, uniquePath); + } catch (IOException ioe) { + throw new ImageException(String.format(MESSAGE_INVALID_IMAGE, + DisplayPictureCommand.MESSAGE_IMAGE_PATH_FAIL)); + + } + } + + /** + * To store image in directory + * @throws IOException to display error message + */ + public void saveImageInDirectory(BufferedImage image, String uniquePath) throws IOException { + File fileToWrite = null; + try { + fileToWrite = new File("pictures/" + uniquePath + ".png"); + ImageIO.write(image, "png", fileToWrite); + } catch (IOException ioe) { + throw new ImageException(String.format(MESSAGE_INVALID_IMAGE, + DisplayPictureCommand.MESSAGE_IMAGE_PATH_FAIL)); + } + } + +} +``` +###### \java\seedu\address\storage\StorageManager.java +``` java + + @Override + public void readImageFromDevice(String path, int newPath) throws IOException { + logger.fine("Attempting to read from file: " + path); + displayPictureStorage.readImageFromDevice(path, newPath); + } + + @Override + public void saveImageInDirectory(BufferedImage image, String uniquePath) throws IOException { + logger.fine("Attempting to write to file: " + uniquePath); + displayPictureStorage.saveImageInDirectory(image, uniquePath); + } + + @Override + @Subscribe + public void handleDisplayPictureChangedEvent(DisplayPictureChangedEvent event) throws IOException { + logger.info(LogsCenter.getEventHandlingLogMessage(event, " Image changed, saving to file")); + try { + readImageFromDevice(event.path, event.newPath); + event.setRead(true); + } catch (IOException e) { + event.setRead(false); + raise(new DataSavingExceptionEvent(e)); + } + } + +} +``` +###### \java\seedu\address\ui\BrowserAndRemindersPanel.java +``` java + + private void bringBrowserToFront() { + browser.toFront(); + currentlyInFront = Node.BROWSER; + } + + /** + * Set's up the UI to bring browser to front and show location + */ + private void setUpToShowLocation() { + if (currentlyInFront == Node.REMINDERS) { + browser.toFront(); + currentlyInFront = Node.BROWSER; + raise(new TurnLabelsOffEvent()); + } + } + + /** + * Creates url from given address + * @param address of the specified person + */ + public String loadPersonLocation(String address) { + + String[] splitAddressByWords = address.split("\\s"); + + String keywordsOfUrl = ""; + + for (String word: splitAddressByWords) { + keywordsOfUrl += word; + keywordsOfUrl += "+"; + } + + loadPage(GOOGLE_MAPS_URL + keywordsOfUrl); + return GOOGLE_MAPS_URL + keywordsOfUrl; + } + + /** + * Sets up email Url for processing Email in Browser panel + * @param service mentioned email service + * @param recipients formed recipients string + * @param subject + * @param body + */ + private void setUpEmailUrl(String service, String recipients, String subject, String body) { + if (service.equalsIgnoreCase(EMAIL_SERVICE_GMAIL)) { + loadEmailUrlGmail(recipients, subject, body); + } else if (service.equalsIgnoreCase(EMAIL_SERVICE_OUTLOOK)) { + loadEmailUrlOutlook(recipients, subject, body); + } + } + + /** + * Loads page to send email through gmail + * @param recipients + * @param subject + * @param body + */ + public void loadEmailUrlGmail(String recipients, String subject, String body) { + try { + Desktop.getDesktop().browse(new URI(String.format(GMAIL_EMAIL_URL, recipients, subject, body))); + } catch (URISyntaxException urise) { + urise.printStackTrace(); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } + + /** + * Loads page to send email through outlook + * @param recipients + * @param subject + * @param body + */ + private void loadEmailUrlOutlook(String recipients, String subject, String body) { + try { + Desktop.getDesktop().browse(new URI(String.format(OUTLOOK_EMAIL_URL, recipients, subject, body))); + } catch (URISyntaxException urise) { + urise.printStackTrace(); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } + + @Subscribe + private void handlePersonPanelSelectionChangedEvent(PersonPanelSelectionChangedEvent event) { + logger.info(LogsCenter.getEventHandlingLogMessage(event)); + loadPersonPage(event.getNewSelection().person); + bringBrowserToFront(); + raise(new TurnLabelsOffEvent()); + } + + @Subscribe + private void handlePopularContactPanelSelectionChangedEvent(PopularContactPanelSelectionChangedEvent event) { + logger.info(LogsCenter.getEventHandlingLogMessage(event)); + loadPersonPage(event.getNewSelection().person); + bringBrowserToFront(); + raise(new TurnLabelsOffEvent()); + } + + + @Subscribe + private void handleBrowserPanelToggleEvent(BrowserAndRemindersPanelToggleEvent event) { + logger.info(LogsCenter.getEventHandlingLogMessage(event)); + toggleBrowserPanel(); + } + + @Subscribe + private void handleShowLocationEvent(ShowLocationEvent event) { + logger.info(LogsCenter.getEventHandlingLogMessage(event, + "Processing Location of " + event.person.getName().fullName)); + setUpToShowLocation(); + String url = loadPersonLocation(event.person.getAddress().value); + } + + @Subscribe + private void handleSendingEmailEvent(SendingEmailEvent event) { + logger.info(LogsCenter.getEventHandlingLogMessage(event, + "Processing email through service of " + event.service.service)); + setUpEmailUrl(event.service.service, event.recipients, event.subject.subject, event.body.body); + } + +``` +###### \java\seedu\address\ui\PersonCard.java +``` java + + /** + * Assigns URL to the image depending on the path + */ + private void assignImage(ReadOnlyPerson person) { + + if (!person.getDisplayPicture().getPath().equals("")) { + + Image image = new Image("file:" + "pictures/" + person.getDisplayPicture().getPath() + ".png", + IMAGE_WIDTH, IMAGE_HEIGHT, false, false); + + centerImage(); + displayPicture.setImage(image); + + } + } + +``` +###### \java\seedu\address\ui\PopularContactCard.java +``` java +package seedu.address.ui; + +import javafx.beans.binding.Bindings; +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; +import seedu.address.model.person.ReadOnlyPerson; + +/** + * An UI component that displays information of a Popular Contact + */ +public class PopularContactCard extends UiPart { + + private static final String FXML = "PopularContactCard.fxml"; + private static final Integer IMAGE_WIDTH = 70; + private static final Integer IMAGE_HEIGHT = 70; + + /** + * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX. + * As a consequence, UI elements' variable names cannot be set to such keywords + * or an exception will be thrown by JavaFX during runtime. + * + * @see The issue on AddressBook level 4 + */ + + public final ReadOnlyPerson person; + + @FXML + private VBox popularContactPane; + @FXML + private Label popularContactName; + @FXML + private ImageView popularContactDisplayPicture; + @FXML + private Label rank; + + public PopularContactCard(ReadOnlyPerson person, int displayedIndex) { + super(FXML); + this.person = person; + rank.setText("#" + displayedIndex + " "); + bindListeners(person); + } + + /** + * Binds the individual UI elements to observe their respective {@code Person} properties + * so that they will be notified of any changes. + */ + private void bindListeners(ReadOnlyPerson person) { + popularContactName.textProperty().bind(Bindings.convert(person.nameProperty())); + assignImage(person); + } + + /** + * Assigns URL to the image depending on the path + */ + private void assignImage(ReadOnlyPerson person) { + + if (!person.getDisplayPicture().getPath().equals("")) { + + Image image = new Image("file:" + "pictures/" + person.getDisplayPicture().getPath() + ".png", + IMAGE_WIDTH, IMAGE_HEIGHT, false, false); + + centerImage(); + popularContactDisplayPicture.setImage(image); + + } + } + + /** + * Centre the image in ImageView + */ + public void centerImage() { + Image image = popularContactDisplayPicture.getImage(); + if (image != null) { + double width; + double height; + + double ratioX = popularContactDisplayPicture.getFitWidth() / image.getWidth(); + double ratioY = popularContactDisplayPicture.getFitHeight() / image.getHeight(); + + double reducCoeff; + if (ratioX >= ratioY) { + reducCoeff = ratioY; + } else { + reducCoeff = ratioX; + } + + width = image.getWidth() * reducCoeff; + height = image.getHeight() * reducCoeff; + + popularContactDisplayPicture.setX((popularContactDisplayPicture.getFitWidth() - width) / 2); + popularContactDisplayPicture.setY((popularContactDisplayPicture.getFitHeight() - height) / 2); + + } + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof PersonCard)) { + return false; + } + + // state check + PopularContactCard card = (PopularContactCard) other; + return rank.getText().equals(card.rank.getText()) + && person.equals(card.person); + } +} +``` +###### \java\seedu\address\ui\PopularContactPanel.java +``` java +package seedu.address.ui; + +import java.util.logging.Logger; + +import org.fxmisc.easybind.EasyBind; + +import com.google.common.eventbus.Subscribe; + +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.layout.Region; +import seedu.address.commons.core.LogsCenter; +import seedu.address.commons.events.model.PopularContactChangedEvent; +import seedu.address.commons.events.ui.PopularContactPanelSelectionChangedEvent; +import seedu.address.model.person.ReadOnlyPerson; + +/** + * Panel to display top 5 popular most frequently accessed contacts. + */ +public class PopularContactPanel extends UiPart { + + private static final String FXML = "PopularContactPanel.fxml"; + private final Logger logger = LogsCenter.getLogger(PersonListPanel.class); + + @FXML + private ListView popularContactListView; + + public PopularContactPanel(ObservableList popularContactList) { + super(FXML); + setConnections(popularContactList); + registerAsAnEventHandler(this); + } + + private void setConnections(ObservableList popularContactList) { + ObservableList mappedList = EasyBind.map( + popularContactList, (person) -> new PopularContactCard(person, popularContactList.indexOf(person) + 1)); + popularContactListView.setItems(mappedList); + popularContactListView.setCellFactory(listView -> new PopularContactPanel.PersonListViewCell()); + setEventHandlerForSelectionChangeEvent(); + } + + private void setEventHandlerForSelectionChangeEvent() { + popularContactListView.getSelectionModel().selectedItemProperty() + .addListener((observable, oldValue, newValue) -> { + if (newValue != null) { + logger.fine("Selection in person list panel changed to : '" + newValue + "'"); + raise(new PopularContactPanelSelectionChangedEvent(newValue)); + } + }); + } + + /** + * Custom {@code ListCell} that displays the graphics of a {@code PopularContactCard}. + */ + class PersonListViewCell extends ListCell { + + @Override + protected void updateItem(PopularContactCard person, boolean empty) { + super.updateItem(person, empty); + + if (empty || person == null) { + setGraphic(null); + setText(null); + } else { + setGraphic(person.getRoot()); + } + } + } + + @Subscribe + public void handlePopularContactChangedEvent(PopularContactChangedEvent ppce) { + setConnections(ppce.getModel().getPopularContactList()); + } +} + +``` +###### \resources\view\MainWindow.fxml +``` fxml + + + + + + +``` +###### \resources\view\PopularContactCard.fxml +``` fxml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` +###### \resources\view\PopularContactPanel.fxml +``` fxml + + + + + + + + + + + + +``` diff --git a/collated/test/tshradheya-unused.md b/collated/test/tshradheya-unused.md new file mode 100644 index 000000000000..4685954a6559 --- /dev/null +++ b/collated/test/tshradheya-unused.md @@ -0,0 +1,56 @@ +# tshradheya-unused +###### \java\seedu\address\storage\ReadAndStoreImageTest.java +``` java +/*package seedu.address.storage; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; + +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import seedu.address.logic.parser.exceptions.ImageException; + +public class ReadAndStoreImageTest { + + private static final String IMAGE_NAME = "testDisplaypic"; + private static final String INVALID_IMAGE_NAME = "testDisplaypicWrong"; + private static final String VALID_EMAIL = "something@example.com"; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + + @Test + @Ignore + public void test_execute() throws IOException, URISyntaxException { + + String initialPath = new File("./src/test/resources/pictures/" + IMAGE_NAME + ".jpg").getAbsolutePath(); + + + ReadAndStoreImage readAndStoreImage = new ReadAndStoreImage(); + + String finalName = readAndStoreImage.execute(initialPath, VALID_EMAIL.hashCode()); + + assertEquals(finalName, Integer.toString(VALID_EMAIL.hashCode())); + } + + @Test + @Ignore + public void throwsImageException() throws IOException, URISyntaxException { + + String initialPath = "src\\test\\resources\\pictures\\" + INVALID_IMAGE_NAME + ".jpg"; + + ReadAndStoreImage readAndStoreImage = new ReadAndStoreImage(); + thrown.expect(ImageException.class); + String finalName = readAndStoreImage.execute(initialPath, VALID_EMAIL.hashCode()); + } + +} +*/ +``` diff --git a/collated/test/tshradheya.md b/collated/test/tshradheya.md new file mode 100644 index 000000000000..828d4ec24bdb --- /dev/null +++ b/collated/test/tshradheya.md @@ -0,0 +1,1670 @@ +# tshradheya +###### \java\guitests\guihandles\PopularContactCardHandle.java +``` java +package guitests.guihandles; + +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; + +/** + * Provides a handle to a person card in the Popular Contact list panel. + */ +public class PopularContactCardHandle extends NodeHandle { + + private static final String RANK_FEILD_ID = "#rank"; + private static final String NAME_FIELD_ID = "#popularContactName"; + private static final String DISPLAY_PICTURE_FIELD_ID = "#popularContactDisplayPicture"; + + private final Label idLabel; + private final Label nameLabel; + private final ImageView displayPictureImageView; + + public PopularContactCardHandle(Node cardNode) { + super(cardNode); + + this.idLabel = getChildNode(RANK_FEILD_ID); + this.nameLabel = getChildNode(NAME_FIELD_ID); + this.displayPictureImageView = getChildNode(DISPLAY_PICTURE_FIELD_ID); + + } + + public String getRank() { + return idLabel.getText(); + } + + public String getName() { + return nameLabel.getText(); + } + + public Image getDisplayPictureImageView() { + return displayPictureImageView.getImage(); + } +} +``` +###### \java\guitests\guihandles\PopularContactsPanelHandle.java +``` java +package guitests.guihandles; + +import java.util.List; +import java.util.Optional; + +import javafx.scene.control.ListView; +import seedu.address.model.person.ReadOnlyPerson; +import seedu.address.ui.PopularContactCard; + +/** + * Provides a handle for {@code PopularContactListPanel} containing the list of {@code PopularContactCard} + */ +public class PopularContactsPanelHandle extends NodeHandle> { + + public static final String PERSON_LIST_VIEW_ID = "#popularContactListView"; + + private Optional lastRememberedSelectedPopularContactCard; + + public PopularContactsPanelHandle(ListView personListPanelNode) { + super(personListPanelNode); + } + + /** + * Returns a handle to the selected {@code PersonCardHandle}. + * A maximum of 1 item can be selected at any time. + * @throws AssertionError if no card is selected, or more than 1 card is selected. + */ + public PopularContactCardHandle getHandleToSelectedCard() { + List personList = getRootNode().getSelectionModel().getSelectedItems(); + + if (personList.size() != 1) { + throw new AssertionError("Person list size expected 1."); + } + + return new PopularContactCardHandle(personList.get(0).getRoot()); + } + + /** + * Returns the index of the selected card. + */ + public int getSelectedCardIndex() { + return getRootNode().getSelectionModel().getSelectedIndex(); + } + + /** + * Returns true if a card is currently selected. + */ + public boolean isAnyCardSelected() { + List selectedCardsList = getRootNode().getSelectionModel().getSelectedItems(); + + if (selectedCardsList.size() > 1) { + throw new AssertionError("Card list size expected 0 or 1."); + } + + return !selectedCardsList.isEmpty(); + } + + /** + * Navigates the listview to display and select the person. + */ + public void navigateToCard(ReadOnlyPerson person) { + List cards = getRootNode().getItems(); + Optional matchingCard = cards.stream().filter(card -> card.person.equals(person)).findFirst(); + + if (!matchingCard.isPresent()) { + throw new IllegalArgumentException("Person does not exist."); + } + + guiRobot.interact(() -> { + getRootNode().scrollTo(matchingCard.get()); + getRootNode().getSelectionModel().select(matchingCard.get()); + }); + guiRobot.pauseForHuman(); + } + + /** + * Returns the person card handle of a person associated with the {@code index} in the list. + */ + public PopularContactCardHandle getPopularContactCardHandle(int index) { + return getPopularContactCardHandle(getRootNode().getItems().get(index).person); + } + + /** + * Returns the {@code PersonCardHandle} of the specified {@code person} in the list. + */ + public PopularContactCardHandle getPopularContactCardHandle(ReadOnlyPerson person) { + Optional handle = getRootNode().getItems().stream() + .filter(card -> card.person.equals(person)) + .map(card -> new PopularContactCardHandle(card.getRoot())) + .findFirst(); + return handle.orElseThrow(() -> new IllegalArgumentException("Person does not exist.")); + } + + /** + * Selects the {@code PersonCard} at {@code index} in the list. + */ + public void select(int index) { + getRootNode().getSelectionModel().select(index); + } + + /** + * Remembers the selected {@code PersonCard} in the list. + */ + public void rememberSelectedPersonCard() { + List selectedItems = getRootNode().getSelectionModel().getSelectedItems(); + + if (selectedItems.size() == 0) { + lastRememberedSelectedPopularContactCard = Optional.empty(); + } else { + lastRememberedSelectedPopularContactCard = Optional.of(selectedItems.get(0)); + } + } + + /** + * Returns true if the selected {@code PersonCard} is different from the value remembered by the most recent + * {@code rememberSelectedPersonCard()} call. + */ + public boolean isSelectedPersonCardChanged() { + List selectedItems = getRootNode().getSelectionModel().getSelectedItems(); + + if (selectedItems.size() == 0) { + return lastRememberedSelectedPopularContactCard.isPresent(); + } else { + return !lastRememberedSelectedPopularContactCard.isPresent() + || !lastRememberedSelectedPopularContactCard.get().equals(selectedItems.get(0)); + } + } + + /** + * Returns the size of the list. + */ + public int getListSize() { + return getRootNode().getItems().size(); + } +} +``` +###### \java\seedu\address\logic\commands\AddCommandTest.java +``` java + + @Override + public boolean addDisplayPicture(String path, int newPath) throws IOException { + fail("This method should not be called"); + return false; + } +``` +###### \java\seedu\address\logic\commands\AddCommandTest.java +``` java + + @Override + public void updateFilteredPersonListForViewTag(Predicate predicate) { + fail("This method should not be called."); + } + + @Override + public void increaseCounterByOneForATag(List filteredPersonList) { + fail("This method should not be called"); + } + + @Override + public ReadOnlyPerson increaseCounterByOne(ReadOnlyPerson person) { + fail("This method should not be called"); + return person; + } + + @Override + public ObservableList getPopularContactList() { + fail("This method should not be called"); + return new ImmutableObservableList<>(); + } + + @Override + public void refreshWithPopulatingAddressBook() { + fail("This method should not be called"); + } + + @Override + public void updatePopularContactList() { + fail("This method should not be called"); + } + + @Override + public void getOnlyTopFiveMaximum() { + fail("This method should not be called"); + } + + @Override + public void updatePersonsPopularityCounterByOne(ReadOnlyPerson person) throws DuplicatePersonException, + PersonNotFoundException { + fail("This method should not be called"); + } +``` +###### \java\seedu\address\logic\commands\AddCommandTest.java +``` java + + @Override + public void showLocation(ReadOnlyPerson person) { + fail("This method should not be called"); + } + + @Override + public void processEmailEvent(String recipients, Subject subject, Body body, Service service) { + fail("This method should not be called"); + } + + @Override + public String createEmailRecipients(Predicate predicate) { + fail("This method should not be called"); + return ""; + } +``` +###### \java\seedu\address\logic\commands\DisplayPictureCommandTest.java +``` java +package seedu.address.logic.commands; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static seedu.address.logic.commands.CommandTestUtil.DISPLAY_PICTURE_AMY; +import static seedu.address.logic.commands.CommandTestUtil.DISPLAY_PICTURE_BOB; +import static seedu.address.logic.commands.CommandTestUtil.VALID_DISPLAYPIC_ALICE; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.logic.commands.CommandTestUtil.showFirstPersonOnly; +import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON; +import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; +import static seedu.address.testutil.TypicalReminders.getUniqueTypicalReminders; + +import java.io.File; + +import org.junit.Test; + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.logic.CommandHistory; +import seedu.address.logic.UndoRedoStack; +import seedu.address.model.AddressBook; +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; +import seedu.address.model.person.DisplayPicture; +import seedu.address.model.person.Person; +import seedu.address.testutil.PersonBuilder; + +public class DisplayPictureCommandTest { + + public static final String INDEX_FIRST_PERSON_EMAIL = "alice@example.com"; + + public static final String DISPLAY_PICTURE_ALICE_PATH = + new File("./src/test/resources/pictures/" + VALID_DISPLAYPIC_ALICE) + .getAbsolutePath(); + + private static final String INVALID_PATH = " . /?no/2 t hing"; + private Model model = new ModelManager(getTypicalAddressBook(), getUniqueTypicalReminders(), new UserPrefs()); + + @Test + public void execute_setDisplayPicture_success() throws Exception { + Person editedPerson = new PersonBuilder(model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased())) + .withDisplayPicture(Integer.toString(INDEX_FIRST_PERSON_EMAIL.hashCode())).build(); + + DisplayPictureCommand displayPictureCommand = prepareCommand(INDEX_FIRST_PERSON, + DISPLAY_PICTURE_ALICE_PATH); + + String expectedMessage = String.format(DisplayPictureCommand.MESSAGE_ADD_DISPLAYPICTURE_SUCCESS, editedPerson); + + Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), + getUniqueTypicalReminders(), new UserPrefs()); + expectedModel.updatePerson(model.getFilteredPersonList().get(0), editedPerson); + + assertCommandSuccess(displayPictureCommand, model, expectedMessage, expectedModel); + } + + @Test + public void execute_setDisplayPicture_successWithNoPath() throws Exception { + Person editedPerson = new PersonBuilder(model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased())) + .withDisplayPicture("").build(); + + DisplayPictureCommand displayPictureCommand = prepareCommand(INDEX_FIRST_PERSON, + ""); + + String expectedMessage = String.format(DisplayPictureCommand.MESSAGE_DELETE_DISPLAYPICTURE_SUCCESS, + editedPerson); + + Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), + getUniqueTypicalReminders(), new UserPrefs()); + expectedModel.updatePerson(model.getFilteredPersonList().get(0), editedPerson); + + assertCommandSuccess(displayPictureCommand, model, expectedMessage, expectedModel); + } + + @Test + public void execute_invalidPersonIndexUnfilteredList_failure() throws Exception { + Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1); + DisplayPictureCommand displayPictureCommand = prepareCommand(outOfBoundIndex, DISPLAY_PICTURE_ALICE_PATH); + + assertCommandFailure(displayPictureCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + + @Test + public void execute_invalidPersonIndexFilteredList_failure() throws Exception { + showFirstPersonOnly(model); + Index outOfBoundIndex = INDEX_SECOND_PERSON; + // ensures that outOfBoundIndex is still within bounds of address book list + assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size()); + + DisplayPictureCommand displayPictureCommand = prepareCommand(outOfBoundIndex, DISPLAY_PICTURE_ALICE_PATH); + + assertCommandFailure(displayPictureCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + + + @Test + public void equals() { + final DisplayPictureCommand standardCommand = + new DisplayPictureCommand(INDEX_FIRST_PERSON, DISPLAY_PICTURE_AMY); + final DisplayPictureCommand commandWithSameValues = + new DisplayPictureCommand(INDEX_FIRST_PERSON, DISPLAY_PICTURE_AMY); + final DisplayPictureCommand commandWithDifferentIndex = + new DisplayPictureCommand(INDEX_SECOND_PERSON, DISPLAY_PICTURE_AMY); + final DisplayPictureCommand commandWithDifferentDisplayPicture = + new DisplayPictureCommand(INDEX_FIRST_PERSON, DISPLAY_PICTURE_BOB); + final DisplayPictureCommand commandWithDifferentValues = + new DisplayPictureCommand(INDEX_SECOND_PERSON, DISPLAY_PICTURE_BOB); + + // same object -> Returns true + assertTrue(standardCommand.equals(standardCommand)); + + // null -> returns false + assertFalse(standardCommand.equals(null)); + + // different types -> returns false + assertFalse(standardCommand.equals(new ClearCommand())); + + // different object, same type with same values -> return true + assertTrue(standardCommand.equals(commandWithSameValues)); + + // same type but different index -> returns false + assertFalse(standardCommand.equals(commandWithDifferentIndex)); + + // same type but different nickname -> returns false + assertFalse(standardCommand.equals(commandWithDifferentDisplayPicture)); + + // same type but different index and nickname -> returns false + assertFalse(standardCommand.equals(commandWithDifferentValues)); + } + + /** + * Returns an {@code DisplayPictureCommand} with parameters {@code index} and {@code displaypic} + */ + private DisplayPictureCommand prepareCommand(Index index, String displaypic) { + DisplayPictureCommand displayPictureCommand = new DisplayPictureCommand(index, new DisplayPicture(displaypic)); + displayPictureCommand.setData(model, new CommandHistory(), new UndoRedoStack()); + return displayPictureCommand; + } +} +``` +###### \java\seedu\address\logic\commands\EmailCommandTest.java +``` java +package seedu.address.logic.commands; + +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.email.Body; +import seedu.address.model.email.Service; +import seedu.address.model.email.Subject; +import seedu.address.model.person.PersonContainsTagPredicate; + + +public class EmailCommandTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void processEmailTestFail() throws ParseException { + thrown.expect(ParseException.class); + EmailCommand command = new EmailCommand(new PersonContainsTagPredicate("friends"), new Subject("hello"), + new Body("hi"), new Service("gmail")); + command.processEmail(""); + } + + @Test + public void checkServiceValid_throwsException() throws ParseException { + thrown.expect(ParseException.class); + EmailCommand command = new EmailCommand(new PersonContainsTagPredicate("friends"), new Subject("hello"), + new Body("hi"), new Service("gmail")); + command.checkServiceValid(new Service("notPresent")); + } + + @Test + public void executeParseExceptionThrown() { + EmailCommand command = new EmailCommand(new PersonContainsTagPredicate("friend"), new Subject("hello"), + new Body("hi"), new Service("non existing")); + CommandResult result = command.execute(); + assertEquals(result.feedbackToUser, EmailCommand.MESSAGE_NOT_SENT); + } + + @Test + public void equals() { + EmailCommand command = new EmailCommand(new PersonContainsTagPredicate("friends"), new Subject("hello"), + new Body("hi"), new Service("gmail")); + EmailCommand sameCommand = new EmailCommand(new PersonContainsTagPredicate("friends"), new Subject("hello"), + new Body("hi"), new Service("gmail")); + EmailCommand differentCommand = new EmailCommand(new PersonContainsTagPredicate("hmm"), new Subject("hi"), + new Body("yo"), new Service("outlook")); + + assertTrue(command.equals(sameCommand)); + + assertTrue(command.equals(command)); + + assertFalse(command == null); + + assertFalse(sameCommand.equals(differentCommand)); + } + + +} +``` +###### \java\seedu\address\logic\commands\LocationCommandTest.java +``` java +package seedu.address.logic.commands; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure; +import static seedu.address.logic.commands.CommandTestUtil.showFirstPersonOnly; +import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON; +import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON; +import static seedu.address.testutil.TypicalIndexes.INDEX_THIRD_PERSON; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; +import static seedu.address.testutil.TypicalReminders.getUniqueTypicalReminders; + +import org.junit.Rule; +import org.junit.Test; + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.commons.events.ui.ShowLocationEvent; +import seedu.address.logic.CommandHistory; +import seedu.address.logic.UndoRedoStack; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; +import seedu.address.ui.testutil.EventsCollectorRule; + +public class LocationCommandTest { + @Rule + public final EventsCollectorRule eventsCollectorRule = new EventsCollectorRule(); + + private Model model = new ModelManager(getTypicalAddressBook(), getUniqueTypicalReminders(), new UserPrefs()); + + @Test + public void execute_invalidPersonIndexUnfilteredList_failure() throws Exception { + Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1); + LocationCommand locationCommand = prepareCommand(outOfBoundIndex); + + assertCommandFailure(locationCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + + @Test + public void execute_invalidPersonIndexFilteredList_failure() throws Exception { + showFirstPersonOnly(model); + Index outOfBoundIndex = INDEX_SECOND_PERSON; + // ensures that outOfBoundIndex is still within bounds of address book list + assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size()); + + LocationCommand locationCommand = prepareCommand(outOfBoundIndex); + + assertCommandFailure(locationCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + + @Test + public void equals() { + final LocationCommand standardCommand = new LocationCommand(INDEX_FIRST_PERSON); + final LocationCommand commandWithSameIndex = new LocationCommand(INDEX_FIRST_PERSON); + final LocationCommand commandWithDifferentIndex = new LocationCommand(INDEX_SECOND_PERSON); + + + // same object -> Returns true + assertTrue(standardCommand.equals(standardCommand)); + + // null -> returns false + assertFalse(standardCommand.equals(null)); + + // different types -> returns false + assertFalse(standardCommand.equals(new ClearCommand())); + + // different object, same type with same values -> return true + assertTrue(standardCommand.equals(commandWithSameIndex)); + + // same type but different index -> returns false + assertFalse(standardCommand.equals(commandWithDifferentIndex)); + + } + + @Test + public void execute_validIndexUnfilteredList_success() { + Index lastPersonIndex = Index.fromOneBased(model.getFilteredPersonList().size()); + + assertExecutionSuccess(INDEX_FIRST_PERSON); + assertExecutionSuccess(INDEX_THIRD_PERSON); + assertExecutionSuccess(lastPersonIndex); + } + + @Test + public void checkIfEventCollected() throws CommandException { + LocationCommand locationCommand = prepareCommand(INDEX_FIRST_PERSON); + locationCommand.execute(); + assertTrue(eventsCollectorRule.eventsCollector.getMostRecent() instanceof ShowLocationEvent); + assertTrue(eventsCollectorRule.eventsCollector.getSize() == 3); + } + + /** + * Executes a {@code LocationCommand} with the given {@code index}, and checks that {@code ShowLocationEvent} + * is raised with the correct index. + */ + private void assertExecutionSuccess(Index index) { + LocationCommand locationCommand = prepareCommand(index); + + try { + CommandResult commandResult = locationCommand.execute(); + assertEquals(String.format(LocationCommand.MESSAGE_FIND_LOCATION_SUCCESS, + model.getFilteredPersonList().get(index.getZeroBased()).getName().fullName, + model.getFilteredPersonList().get(index.getZeroBased()).getAddress().value), + commandResult.feedbackToUser); + } catch (CommandException ce) { + throw new IllegalArgumentException("Execution of command should not fail.", ce); + } + + ShowLocationEvent lastEvent = (ShowLocationEvent) eventsCollectorRule.eventsCollector.getMostRecent(); + assertEquals(model.getFilteredPersonList().get(index.getZeroBased()), lastEvent.person); + } + + /** + * Returns an {@code LocationCommand} with parameters {@code index}} + */ + private LocationCommand prepareCommand(Index index) { + LocationCommand locationCommand = new LocationCommand(index); + locationCommand.setData(model, new CommandHistory(), new UndoRedoStack()); + return locationCommand; + } +} +``` +###### \java\seedu\address\logic\commands\ViewTagCommandTest.java +``` java +package seedu.address.logic.commands; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static seedu.address.commons.core.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW; +import static seedu.address.testutil.TypicalPersons.ALICE; +import static seedu.address.testutil.TypicalPersons.BENSON; +import static seedu.address.testutil.TypicalPersons.ELLE; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; +import static seedu.address.testutil.TypicalReminders.getUniqueTypicalReminders; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.junit.Test; + +import seedu.address.logic.CommandHistory; +import seedu.address.logic.UndoRedoStack; +import seedu.address.model.AddressBook; +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; +import seedu.address.model.person.PersonContainsTagPredicate; +import seedu.address.model.person.ReadOnlyPerson; + +public class ViewTagCommandTest { + + private Model model = new ModelManager(getTypicalAddressBook(), getUniqueTypicalReminders(), new UserPrefs()); + + @Test + public void equals() { + PersonContainsTagPredicate firstPredicate = + new PersonContainsTagPredicate("foo"); + PersonContainsTagPredicate secondPredicate = + new PersonContainsTagPredicate("bar"); + + ViewTagCommand viewTagFirstCommand = new ViewTagCommand(firstPredicate); + ViewTagCommand viewTagSecondCommand = new ViewTagCommand(secondPredicate); + + // same object -> returns true + assertTrue(viewTagFirstCommand.equals(viewTagFirstCommand)); + + // same values -> returns true + ViewTagCommand viewTagFirstCommandCopy = new ViewTagCommand(firstPredicate); + assertTrue(viewTagFirstCommand.equals(viewTagFirstCommandCopy)); + + // different types -> returns false + assertFalse(viewTagFirstCommand.equals(1)); + + // null -> returns false + assertFalse(viewTagFirstCommand.equals(null)); + + // different person -> returns false + assertFalse(viewTagFirstCommand.equals(viewTagSecondCommand)); + } + + @Test + public void execute_zeroKeywords_noPersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0); + ViewTagCommand command = prepareCommand(" "); + assertCommandSuccess(command, expectedMessage, Collections.emptyList()); + } + + @Test + public void execute_oneKeyword_multiplePersonsFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 2); + ViewTagCommand command = prepareCommand("friend"); + assertCommandSuccess(command, expectedMessage, Arrays.asList(ALICE, BENSON)); + } + + @Test + public void execute_oneKeyword_singlePersonFound() { + String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 1); + ViewTagCommand command = prepareCommand("enemy"); + assertCommandSuccess(command, expectedMessage, Collections.singletonList(ELLE)); + } + + /** + * Parses {@code keyword} into a {@code ViewTagCommand}. + */ + private ViewTagCommand prepareCommand(String keyword) { + ViewTagCommand command = + new ViewTagCommand(new PersonContainsTagPredicate(keyword)); + command.setData(model, new CommandHistory(), new UndoRedoStack()); + return command; + } + + /** + * Asserts that {@code command} is successfully executed, and
+ * - the command feedback is equal to {@code expectedMessage}
+ * - the {@code FilteredList} is equal to {@code expectedList}
+ * - the {@code AddressBook} in model remains the same after executing the {@code command} + */ + private void assertCommandSuccess(ViewTagCommand command, String expectedMessage, + List expectedList) { + AddressBook expectedAddressBook = new AddressBook(model.getAddressBook()); + CommandResult commandResult = command.execute(); + + assertEquals(expectedMessage, commandResult.feedbackToUser); + assertEquals(expectedList, model.getFilteredPersonList()); + assertEquals(expectedAddressBook, model.getAddressBook()); + } + +} +``` +###### \java\seedu\address\model\email\BodyTest.java +``` java +package seedu.address.model.email; + +import static junit.framework.TestCase.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class BodyTest { + + private Body body = new Body("gmail"); + private Body sameBody = new Body("gmail"); + private Body anotherBody = new Body("outlook"); + + @Test + public void service_equals() { + assertTrue(body.equals(sameBody)); + + assertFalse(body == null); + + assertTrue(body.equals(body)); + + assertFalse(body.equals(anotherBody)); + } +} +``` +###### \java\seedu\address\model\email\ServiceTest.java +``` java +package seedu.address.model.email; + +import static junit.framework.TestCase.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class ServiceTest { + private Service service = new Service("gmail"); + private Service sameService = new Service("gmail"); + private Service anotherService = new Service("outlook"); + + @Test + public void service_equals() { + assertTrue(service.equals(sameService)); + + assertFalse(service == null); + + assertTrue(service.equals(service)); + + assertFalse(service.equals(anotherService)); + } +} +``` +###### \java\seedu\address\model\email\SubjectTest.java +``` java +package seedu.address.model.email; + +import static junit.framework.TestCase.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class SubjectTest { + + private Subject subject = new Subject("message"); + private Subject sameSubject = new Subject("message"); + private Subject anotherSubject = new Subject("different message"); + + @Test + public void service_equals() { + assertTrue(subject.equals(sameSubject)); + + assertFalse(subject == null); + + assertTrue(subject.equals(subject)); + + assertFalse(subject.equals(anotherSubject)); + } +} +``` +###### \java\seedu\address\model\ModelManagerTest.java +``` java + + @Test + public void addDisplayPicture_eventRaised() throws IOException { + ModelManager modelManager = new ModelManager(); + modelManager.addDisplayPicture(TEST_DATA_FOLDER + "1137944384.png", 1137944384); + assertTrue(eventsCollectorRule.eventsCollector.getMostRecent() instanceof DisplayPictureChangedEvent); + } +``` +###### \java\seedu\address\model\person\DisplayPictureTest.java +``` java +package seedu.address.model.person; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static seedu.address.logic.commands.CommandTestUtil.VALID_DISPLAYPIC_AMY; +import static seedu.address.logic.commands.CommandTestUtil.VALID_DISPLAYPIC_BOB; + +import org.junit.Test; + +public class DisplayPictureTest { + @Test + public void equals() { + DisplayPicture standardDisplayPicture = new DisplayPicture(VALID_DISPLAYPIC_AMY); + DisplayPicture sameDisplayPicture = new DisplayPicture(VALID_DISPLAYPIC_AMY); + DisplayPicture differentDisplayPicture = new DisplayPicture(VALID_DISPLAYPIC_BOB); + + // same object -> returns true + assertTrue(standardDisplayPicture.equals(standardDisplayPicture)); + + // null -> returns false + assertFalse(standardDisplayPicture == null); + + // different type -> returns false + assertFalse(standardDisplayPicture.equals("String")); + + // different nickname -> returns false + assertFalse(sameDisplayPicture.equals(differentDisplayPicture)); + + // same nickname -> returns true + assertTrue(standardDisplayPicture.equals(sameDisplayPicture)); + } +} +``` +###### \java\seedu\address\model\person\EmailTest.java +``` java +package seedu.address.model.person; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class EmailTest { + + @Test + public void isValidEmail() { + // blank email + assertFalse(Email.isValidEmail("")); // empty string + assertFalse(Email.isValidEmail(" ")); // spaces only + + // missing parts + assertFalse(Email.isValidEmail("@example.com")); // missing local part + assertFalse(Email.isValidEmail("peterjackexample.com")); // missing '@' symbol + assertFalse(Email.isValidEmail("peterjack@")); // missing domain name + + // invalid parts + assertFalse(Email.isValidEmail("-@example.com")); // invalid local part + assertFalse(Email.isValidEmail("peterjack@-")); // invalid domain name + assertFalse(Email.isValidEmail("peter jack@example.com")); // spaces in local part + assertFalse(Email.isValidEmail("peterjack@exam ple.com")); // spaces in domain name + assertFalse(Email.isValidEmail("peterjack@@example.com")); // double '@' symbol + assertFalse(Email.isValidEmail("peter@jack@example.com")); // '@' symbol in local part + assertFalse(Email.isValidEmail("peterjack@example@com")); // '@' symbol in domain name + + // valid email + assertTrue(Email.isValidEmail("PeterJack_1190@example.com")); + assertTrue(Email.isValidEmail("a@b")); // minimal + assertTrue(Email.isValidEmail("test@localhost")); // alphabets only + assertTrue(Email.isValidEmail("123@145")); // numeric local part and domain name + assertTrue(Email.isValidEmail("a1@example1.com")); // mixture of alphanumeric and dot characters + assertTrue(Email.isValidEmail("_user_@_e_x_a_m_p_l_e_.com_")); // underscores + assertTrue(Email.isValidEmail("peter_jack@very_very_very_long_example.com")); // long domain name + assertTrue(Email.isValidEmail("if.you.dream.it_you.can.do.it@example.com")); // long local part + } +} +``` +###### \java\seedu\address\model\person\PersonContainsTagPredicateTest.java +``` java +package seedu.address.model.person; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import seedu.address.testutil.PersonBuilder; + +public class PersonContainsTagPredicateTest { + + @Test + public void equals() { + + String firstPredicateKeyword = "foo"; + String secondPredicateKeyword = "bar"; + + PersonContainsTagPredicate firstPredicate = new PersonContainsTagPredicate(firstPredicateKeyword); + PersonContainsTagPredicate secondPredicate = new PersonContainsTagPredicate(secondPredicateKeyword); + + // same object -> returns true + assertTrue(firstPredicate.equals(firstPredicate)); + + // same values -> returns true + PersonContainsTagPredicate firstPredicateCopy = new PersonContainsTagPredicate(firstPredicateKeyword); + assertTrue(firstPredicate.equals(firstPredicateCopy)); + + // different types -> returns false + assertFalse(firstPredicate.equals(1)); + + // null -> returns false + assertFalse(firstPredicate.equals(null)); + + // different person -> returns false + assertFalse(firstPredicate.equals(secondPredicate)); + } + + @Test + public void test_personContainsTag_returnsTrue() { + + // multiple people having 'friend' tag + PersonContainsTagPredicate predicate = new PersonContainsTagPredicate("friend"); + assertTrue(predicate.test(new PersonBuilder().withTags("friend").build())); + + // one person having the tag + predicate = new PersonContainsTagPredicate("enemy"); + assertTrue(predicate.test(new PersonBuilder().withTags("enemy").build())); + + // mixed-case tag + predicate = new PersonContainsTagPredicate("coLLeagUe"); + assertTrue(predicate.test(new PersonBuilder().withTags("colleague").build())); + + // no one with the tag + predicate = new PersonContainsTagPredicate("cs2103"); + assertTrue(predicate.test(new PersonBuilder().withTags("cs2103").build())); + + } + + @Test + public void test_personDoesNotContainTag_returnsFalse() { + + // no keywords + PersonContainsTagPredicate predicate = new PersonContainsTagPredicate(""); + assertFalse(predicate.test(new PersonBuilder().withTags("enemy").build())); + + // not matching + predicate = new PersonContainsTagPredicate("friend"); + assertFalse(predicate.test(new PersonBuilder().withTags("enemy").build())); + + // people associated with empty tag + predicate = new PersonContainsTagPredicate(""); + assertFalse(predicate.test(new PersonBuilder().withTags("friend").build())); + + // keyword matches name but not tag + predicate = new PersonContainsTagPredicate("Alice"); + assertFalse(predicate.test(new PersonBuilder().withName("Alice").build())); + + } +} +``` +###### \java\seedu\address\model\person\PopularityCounterTest.java +``` java +package seedu.address.model.person; + +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNotSame; + +import org.junit.Test; + +public class PopularityCounterTest { + + @Test + public void popularityCounterEquals() { + + PopularityCounter popularityCounter = new PopularityCounter(); + PopularityCounter samePopularityCounter = new PopularityCounter(); + + assertEquals(popularityCounter, samePopularityCounter); + + samePopularityCounter.increasePopularityCounter(); + + assertNotSame(popularityCounter, samePopularityCounter); + } +} +``` +###### \java\seedu\address\storage\AddressBookPictureStorageTest.java +``` java +package seedu.address.storage; + +import static junit.framework.TestCase.assertEquals; + +import java.io.IOException; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class AddressBookPictureStorageTest { + + private static final String PATH = "/pictures/default.png"; + private static final String INVALID_PATH = ".2? 2./"; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void createTest() { + AddressBookPictureStorage addressBookPictureStorage = new AddressBookPictureStorage(PATH); + assertEquals(addressBookPictureStorage.getAddressBookPicturePath(), PATH); + } + + /*@Test + public void createPicturesPath_throwsIoException() throws IOException { + thrown.expect(IOException.class); + AddressBookPictureStorage addressBookPictureStorage = new AddressBookPictureStorage(INVALID_PATH); + addressBookPictureStorage.createPictureStorageFolder(); + } + */ + + @Test + public void saveAddressBookPicturePath_nullFilePath_throwsNullPointerException() throws IOException { + thrown.expect(NullPointerException.class); + AddressBookPictureStorage addressBookPictureStorage = new AddressBookPictureStorage(null); + addressBookPictureStorage.createPictureStorageFolder(); + } +} +``` +###### \java\seedu\address\storage\ImageDisplayPictureStorageTest.java +``` java +package seedu.address.storage; + +import java.io.IOException; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; + +import seedu.address.commons.util.FileUtil; +import seedu.address.logic.parser.exceptions.ImageException; + +public class ImageDisplayPictureStorageTest { + private static final String TEST_DATA_FOLDER = FileUtil.getPath("./src/test/data/ImageDisplayPicture/"); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Rule + public TemporaryFolder testFolder = new TemporaryFolder(); + + @Test + public void read_notValidPath_exceptionThrown() throws Exception { + + thrown.expect(ImageException.class); + DisplayPictureStorage displayPictureStorage = new ImageDisplayPictureStorage(); + displayPictureStorage.readImageFromDevice("34?/32 2dsd k", 232); + /* IMPORTANT: Any code below an exception-throwing line (like the one above) will be ignored. + * That means you should not have more than one exception test in one method + */ + } + + /** + * To ensure no exception is thrown and command happens successfully + * @throws IOException not expected + */ + @Test + public void read_validPath_success() throws IOException { + DisplayPictureStorage displayPictureStorage = new ImageDisplayPictureStorage(); + displayPictureStorage.readImageFromDevice(TEST_DATA_FOLDER + "1137944384.png", 1137944384); + } + +} +``` +###### \java\seedu\address\storage\StorageManagerTest.java +``` java + + @Test + public void handleDisplayPictureChangedEvent_exceptionThrown_eventRaised() throws IOException { + // Create a StorageManager while injecting a stub that throws an exception when the save method is called + Storage storage = new StorageManager(new XmlAddressBookStorage("dummy"), + new XmlRemindersStorageExceptionThrowingStub("dummy"), + new JsonUserPrefsStorage("dummy"), new ImageDisplayPictureStorage()); + storage.handleDisplayPictureChangedEvent(new DisplayPictureChangedEvent("dummy", 123)); + assertTrue(eventsCollectorRule.eventsCollector.getMostRecent() instanceof DataSavingExceptionEvent); + } +``` +###### \java\seedu\address\testutil\EmailBuilder.java +``` java +package seedu.address.testutil; + +import seedu.address.logic.commands.EmailCommand; +import seedu.address.model.email.Body; +import seedu.address.model.email.Service; +import seedu.address.model.email.Subject; +import seedu.address.model.person.PersonContainsTagPredicate; + +/** + * A utility class to help with building Email content + */ +public class EmailBuilder { + + public static final String DEFAULT_SERVICE = "gmail"; + public static final String DEFAULT_TAG = "friends"; + public static final String DEFAULT_SUBJECT = "hello"; + public static final String DEFAULT_BODY = "how are you?"; + + private EmailCommand emailCommand; + + public EmailBuilder() { + this.emailCommand = new EmailCommand(new PersonContainsTagPredicate(DEFAULT_TAG), + new Subject(DEFAULT_SUBJECT), new Body(DEFAULT_BODY), new Service(DEFAULT_SERVICE)); + } + + public EmailBuilder(EmailCommand toCopy) { + emailCommand = toCopy; + } + + /** Assigns a service to email command */ + public EmailBuilder withService(Service service) { + emailCommand.setService(service); + return this; + } + + /** Assigns a subject to email command */ + public EmailBuilder withSubject(Subject subject) { + emailCommand.setSubject(subject); + return this; + } + + /** Assigns a body to email command */ + public EmailBuilder withBody(Body body) { + emailCommand.setBody(body); + return this; + } + + /** Assigns a predicate to email command to represent recipients */ + public EmailBuilder withPredicate(PersonContainsTagPredicate personContainsTagPredicate) { + emailCommand.setPredicate(personContainsTagPredicate); + return this; + } + public EmailCommand build() { + return this.emailCommand; + } +} +``` +###### \java\seedu\address\ui\PersonCardTest.java +``` java + + @Test + public void displayImage() { + Person personWithDisplayPicture = new PersonBuilder().withDisplayPicture("1137944384").build(); + PersonCard personCard = new PersonCard(personWithDisplayPicture, 1); + uiPartRule.setUiPart(personCard); + assertCardDisplay(personCard, personWithDisplayPicture, 1); + + // changes made to Person reflects on card + guiRobot.interact(() -> { + personWithDisplayPicture.setName(ALICE.getName()); + personWithDisplayPicture.setAddress(ALICE.getAddress()); + personWithDisplayPicture.setEmail(ALICE.getEmail()); + personWithDisplayPicture.setPhone(ALICE.getPhone()); + personWithDisplayPicture.setNickname(ALICE.getNickname()); + personWithDisplayPicture.setDisplayPicture(new DisplayPicture("1137944384")); + personWithDisplayPicture.setTags(ALICE.getTags()); + }); + } +``` +###### \java\seedu\address\ui\PopularContactCardTest.java +``` java +package seedu.address.ui; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static seedu.address.testutil.TypicalPersons.ALICE; +import static seedu.address.ui.testutil.GuiTestAssert.assertCardDisplaysPopularPerson; + +import org.junit.Test; + +import guitests.guihandles.PopularContactCardHandle; +import seedu.address.model.person.DisplayPicture; +import seedu.address.model.person.Person; +import seedu.address.model.person.ReadOnlyPerson; +import seedu.address.testutil.PersonBuilder; + +public class PopularContactCardTest extends GuiUnitTest { + + @Test + public void displayImage() { + Person personWithDisplayPicture = new PersonBuilder().withDisplayPicture("1137944384").build(); + PopularContactCard popularContactCard = new PopularContactCard(personWithDisplayPicture, 1); + uiPartRule.setUiPart(popularContactCard); + assertCardDisplay(popularContactCard, personWithDisplayPicture, 1); + + // changes made to Person reflects on card + guiRobot.interact(() -> { + personWithDisplayPicture.setName(ALICE.getName()); + personWithDisplayPicture.setAddress(ALICE.getAddress()); + personWithDisplayPicture.setEmail(ALICE.getEmail()); + personWithDisplayPicture.setPhone(ALICE.getPhone()); + personWithDisplayPicture.setNickname(ALICE.getNickname()); + personWithDisplayPicture.setDisplayPicture(new DisplayPicture("1137944384")); + personWithDisplayPicture.setTags(ALICE.getTags()); + }); + } + + @Test + public void equals() { + Person person = new PersonBuilder().build(); + PopularContactCard popularContactCard = new PopularContactCard(person, 0); + + // same object -> returns true + assertTrue(popularContactCard.equals(popularContactCard)); + + // null -> returns false + assertFalse(popularContactCard.equals(null)); + + // different types -> returns false + assertFalse(popularContactCard.equals(0)); + + // different person, same index -> returns false + Person differentPerson = new PersonBuilder().withName("differentName").build(); + assertFalse(popularContactCard.equals(new PopularContactCard(differentPerson, 0))); + + // same person, different index -> returns false + assertFalse(popularContactCard.equals(new PopularContactCard(person, 1))); + } + + /** + * Asserts that {@code popularContactCard} displays the details of {@code expectedPerson} correctly and matches + * {@code expectedRank}. + */ + private void assertCardDisplay(PopularContactCard popularContactCard, ReadOnlyPerson expectedPerson, + int expectedRank) { + guiRobot.pauseForHuman(); + + PopularContactCardHandle popularContactCardHandle = new PopularContactCardHandle(popularContactCard.getRoot()); + + // verify id is displayed correctly + assertEquals("#" + Integer.toString(expectedRank) + " ", popularContactCardHandle.getRank()); + + // verify person details are displayed correctly + assertCardDisplaysPopularPerson(expectedPerson, popularContactCardHandle); + } +} +``` +###### \java\seedu\address\ui\PopularContactListPanelTest.java +``` java +package seedu.address.ui; + +import static org.junit.Assert.assertEquals; +import static seedu.address.testutil.TypicalPersons.getPopularPersons; +import static seedu.address.ui.testutil.GuiTestAssert.assertCardDisplaysPopularPerson; + +import org.junit.Before; +import org.junit.Test; + +import guitests.guihandles.PopularContactCardHandle; +import guitests.guihandles.PopularContactsPanelHandle; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import seedu.address.model.person.ReadOnlyPerson; + +public class PopularContactListPanelTest extends GuiUnitTest { + private static final ObservableList TYPICAL_PERSONS = + FXCollections.observableList(getPopularPersons()); + + private PopularContactsPanelHandle popularContactsPanelHandle; + + @Before + public void setUp() { + PopularContactPanel popularContactPanel = new PopularContactPanel(TYPICAL_PERSONS); + uiPartRule.setUiPart(popularContactPanel); + + popularContactsPanelHandle = new PopularContactsPanelHandle(getChildNode(popularContactPanel.getRoot(), + popularContactsPanelHandle.PERSON_LIST_VIEW_ID)); + } + + @Test + public void display() { + for (int i = 0; i < TYPICAL_PERSONS.size(); i++) { + popularContactsPanelHandle.navigateToCard(TYPICAL_PERSONS.get(i)); + ReadOnlyPerson expectedPerson = TYPICAL_PERSONS.get(i); + PopularContactCardHandle actualCard = popularContactsPanelHandle.getPopularContactCardHandle(i); + + assertCardDisplaysPopularPerson(expectedPerson, actualCard); + assertEquals("#" + Integer.toString(i + 1) + " ", actualCard.getRank()); + } + } + +} +``` +###### \java\seedu\address\ui\testutil\GuiTestAssert.java +``` java + + /** + * Asserts that {@code actualCard} displays the same values as {@code expectedCard}. + */ + public static void assertPopularCardEquals(PopularContactCardHandle expectedCard, + PopularContactCardHandle actualCard) { + assertEquals(expectedCard.getRank(), actualCard.getRank()); + assertEquals(expectedCard.getName(), actualCard.getName()); + } +``` +###### \java\seedu\address\ui\testutil\GuiTestAssert.java +``` java + + /** + * Asserts that {@code actualCard} displays the details of {@code expectedPerson}. + */ + public static void assertCardDisplaysPopularPerson(ReadOnlyPerson expectedPerson, + PopularContactCardHandle actualCard) { + assertEquals(expectedPerson.getName().fullName, actualCard.getName()); + + } +``` +###### \java\systemtests\EmailCommandSystemTest.java +``` java +package systemtests; + +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; +import static seedu.address.testutil.EmailBuilder.DEFAULT_BODY; +import static seedu.address.testutil.EmailBuilder.DEFAULT_SERVICE; +import static seedu.address.testutil.EmailBuilder.DEFAULT_SUBJECT; +import static seedu.address.testutil.EmailBuilder.DEFAULT_TAG; + +import org.junit.Test; + +import seedu.address.logic.commands.EmailCommand; +import seedu.address.model.Model; + +public class EmailCommandSystemTest extends AddressBookSystemTest { + + + @Test + public void sendingEmail() throws Exception { + /** With all prefixes */ + String command = EmailCommand.COMMAND_WORD + " s/" + DEFAULT_SERVICE + " to/" + DEFAULT_TAG + " sub/" + + DEFAULT_SUBJECT + " body/" + DEFAULT_BODY; + Model model = getModel(); + assertCommandSuccess(command, model, ""); + + /** With optional prefixes missing*/ + command = EmailCommand.COMMAND_WORD + " s/" + DEFAULT_SERVICE + " to/" + DEFAULT_TAG + " sub/" + + DEFAULT_SUBJECT; + model = getModel(); + assertCommandSuccess(command, model, ""); + + /** With compulsory prefix missing*/ + command = EmailCommand.COMMAND_WORD + " to/" + DEFAULT_TAG + " sub/" + + DEFAULT_SUBJECT; + assertCommandFailure(command, String.format(MESSAGE_INVALID_COMMAND_FORMAT, EmailCommand.MESSAGE_USAGE)); + } + + /** + * To assert successful command + */ + private void assertCommandSuccess(String command, Model expectedModel, String expectedResultMessage) { + executeCommand(command); + expectedModel.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); + assertCommandBoxShowsDefaultStyle(); + assertSelectedCardUnchanged(); + } + + /** + * To assert failed command + */ + private void assertCommandFailure(String command, String expectedResultMessage) { + Model expectedModel = getModel(); + + executeCommand(command); + assertApplicationDisplaysExpected(command, expectedResultMessage, expectedModel); + assertSelectedCardUnchanged(); + assertCommandBoxShowsErrorStyle(); + assertStatusBarUnchanged(); + } +} + +``` +###### \java\systemtests\PopularContactsSystemTest.java +``` java +package systemtests; + +import static seedu.address.commons.core.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW; +import static seedu.address.logic.commands.LocationCommand.MESSAGE_FIND_LOCATION_SUCCESS; +import static seedu.address.logic.commands.SelectCommand.MESSAGE_SELECT_PERSON_SUCCESS; +import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON; +import static seedu.address.testutil.TypicalPersons.ALICE; +import static seedu.address.testutil.TypicalPersons.BENSON; +import static seedu.address.testutil.TypicalPersons.CARL; +import static seedu.address.testutil.TypicalPersons.DANIEL; +import static seedu.address.testutil.TypicalPersons.ELLE; +import static seedu.address.testutil.TypicalPersons.KEYWORD_TAG_ENEMY; + +import org.junit.Test; + +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.ListCommand; +import seedu.address.logic.commands.LocationCommand; +import seedu.address.logic.commands.SelectCommand; +import seedu.address.logic.commands.ViewTagCommand; +import seedu.address.model.Model; + +public class PopularContactsSystemTest extends AddressBookSystemTest { + + @Test + public void favouriteContactsTest() { + + /* Selecting first one to increase popularity counter by one */ + String command = " " + SelectCommand.COMMAND_WORD + " " + INDEX_FIRST_PERSON.getOneBased() + " "; + Model expectedModel = getModel(); + ModelHelper.setFilteredListPopularContacts(expectedModel, ALICE, BENSON, CARL, DANIEL, ELLE); + assertCommandSuccessForSelect(command, INDEX_FIRST_PERSON); + assertSelectedCardChanged(INDEX_FIRST_PERSON); + + + /* Executing viewtag to increase popularity counter by one for everyone in the tag */ + command = " " + ViewTagCommand.COMMAND_WORD + " " + KEYWORD_TAG_ENEMY + " "; + expectedModel = getModel(); + ModelHelper.setFilteredList(expectedModel, ELLE); + ModelHelper.setFilteredListPopularContacts(expectedModel, ALICE, ELLE, BENSON, CARL, DANIEL); + assertCommandSuccessForViewTag(command, expectedModel); + + /* Executing location to increase popularity counter by one for everyone in the tag */ + command = " " + LocationCommand.COMMAND_WORD + " " + INDEX_FIRST_PERSON.getOneBased() + " "; + expectedModel = getModel(); + ModelHelper.setFilteredListPopularContacts(expectedModel, ELLE, ALICE, BENSON, CARL, DANIEL); + assertCommandSuccessForLocation(command, INDEX_FIRST_PERSON, expectedModel); + + /* Listing all contacts */ + command = " " + ListCommand.COMMAND_WORD; + executeCommand(command); + + /* Executing viewtag to increase popularity counter by one for everyone in the tag */ + command = " " + ViewTagCommand.COMMAND_WORD + " " + "owesmoney"; + expectedModel = getModel(); + ModelHelper.setFilteredList(expectedModel, BENSON); + ModelHelper.setFilteredListPopularContacts(expectedModel, ELLE, ALICE, BENSON, CARL, DANIEL); + assertCommandSuccessForViewTag(command, expectedModel); + + } + + /** + * Command success for Select + * @param command + * @param expectedSelectedCardIndex + */ + private void assertCommandSuccessForSelect(String command, Index expectedSelectedCardIndex) { + Model expectedModel = getModel(); + String expectedResultMessage = String.format( + MESSAGE_SELECT_PERSON_SUCCESS, expectedSelectedCardIndex.getOneBased()); + int preExecutionSelectedCardIndex = getPersonListPanel().getSelectedCardIndex(); + + executeCommand(command); + assertApplicationDisplaysExpected("", expectedResultMessage, expectedModel); + + if (preExecutionSelectedCardIndex == expectedSelectedCardIndex.getZeroBased()) { + assertSelectedCardUnchanged(); + } else { + assertSelectedCardChanged(expectedSelectedCardIndex); + } + + assertCommandBoxShowsDefaultStyle(); + assertStatusBarUnchangedExceptSyncStatus(); + } + + /** + * Executes {@code command} and verifies that the command box displays an empty string, the result display + * box displays {@code Messages#MESSAGE_PERSONS_LISTED_OVERVIEW} with the number of people in the filtered list, + * and the model related components equal to {@code expectedModel}. + * These verifications are done by + * {@code AddressBookSystemTest#assertApplicationDisplaysExpected(String, String, Model)}.
+ * Also verifies that the status bar remains unchanged, and the command box has the default style class, and the + * selected card updated accordingly, depending on {@code cardStatus}. + * @see AddressBookSystemTest#assertApplicationDisplaysExpected(String, String, Model) + */ + private void assertCommandSuccessForViewTag(String command, Model expectedModel) { + String expectedResultMessage = String.format( + MESSAGE_PERSONS_LISTED_OVERVIEW, expectedModel.getFilteredPersonList().size()); + + executeCommand(command); + assertApplicationDisplaysExpected("", expectedResultMessage, expectedModel); + assertCommandBoxShowsDefaultStyle(); + if (expectedModel.getFilteredPersonList().size() != 0) { + assertStatusBarUnchangedExceptSyncStatus(); + } else { + assertStatusBarUnchanged(); + } + + } + + /** + * Executes command and checks the state and equality of model + * @param command + * @param expectedSelectedCardIndex + * @param expectedModel + */ + private void assertCommandSuccessForLocation(String command, Index expectedSelectedCardIndex, Model expectedModel) { + String expectedResultMessage = String.format( + MESSAGE_FIND_LOCATION_SUCCESS, + expectedModel.getFilteredPersonList().get(expectedSelectedCardIndex.getZeroBased()).getName(), + expectedModel.getFilteredPersonList().get(expectedSelectedCardIndex.getZeroBased()).getAddress()); + + executeCommand(command); + assertApplicationDisplaysExpected("", expectedResultMessage, expectedModel); + + assertCommandBoxShowsDefaultStyle(); + assertStatusBarUnchangedExceptSyncStatus(); + } + +} + + +``` +###### \java\systemtests\ViewTagCommandSystemTest.java +``` java +package systemtests; + +import static seedu.address.commons.core.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW; +import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND; +import static seedu.address.testutil.TypicalPersons.ALICE; +import static seedu.address.testutil.TypicalPersons.BENSON; +import static seedu.address.testutil.TypicalPersons.CARL; +import static seedu.address.testutil.TypicalPersons.DANIEL; +import static seedu.address.testutil.TypicalPersons.ELLE; +import static seedu.address.testutil.TypicalPersons.KEYWORD_TAG_FRIEND; + +import org.junit.Test; + +import seedu.address.logic.commands.ClearCommand; +import seedu.address.logic.commands.DeleteCommand; +import seedu.address.logic.commands.RedoCommand; +import seedu.address.logic.commands.UndoCommand; +import seedu.address.logic.commands.ViewTagCommand; +import seedu.address.model.Model; + +public class ViewTagCommandSystemTest extends AddressBookSystemTest { + + @Test + public void viewtag() { + + /* Case: Multiple people having one Tag, command with leading spaces and trailing spaces + * -> 2 persons found + */ + String command = " " + ViewTagCommand.COMMAND_WORD + " " + KEYWORD_TAG_FRIEND + " "; + Model expectedModel = getModel(); + ModelHelper.setFilteredList(expectedModel, ALICE, BENSON); // Alice and Benson have tags as "friend" + assertCommandSuccess(command, expectedModel); + assertSelectedCardUnchanged(); + + + /* Case: Repeat previous command with no extra spaces -> 2 persons found */ + command = ViewTagCommand.COMMAND_WORD + " " + KEYWORD_TAG_FRIEND; + assertCommandSuccess(command, expectedModel); + assertSelectedCardUnchanged(); + + /* Case: Only person having the given tag -> 1 person found */ + command = ViewTagCommand.COMMAND_WORD + " enemy"; + ModelHelper.setFilteredList(expectedModel, ELLE); + assertCommandSuccess(command, expectedModel); + assertSelectedCardUnchanged(); + + /* Case: When multiple people have a tag with other tags too -> 2 persons found */ + command = ViewTagCommand.COMMAND_WORD + " relative"; + ModelHelper.setFilteredList(expectedModel, CARL, DANIEL); // Carl and Daniel have 2 tags and one is "family" + assertCommandSuccess(command, expectedModel); + assertSelectedCardUnchanged(); + + /* Case: undo previous find command -> rejected */ + command = UndoCommand.COMMAND_WORD; + String expectedResultMessage = UndoCommand.MESSAGE_FAILURE; + assertCommandFailure(command, expectedResultMessage); + + /* Case: redo previous find command -> rejected */ + command = RedoCommand.COMMAND_WORD; + expectedResultMessage = RedoCommand.MESSAGE_FAILURE; + assertCommandFailure(command, expectedResultMessage); + + /* Case: find same persons in address book with tag after deleting 1 of them -> 1 person found */ + executeCommand(DeleteCommand.COMMAND_WORD + " 1"); + assert !getModel().getAddressBook().getPersonList().contains(CARL); + command = ViewTagCommand.COMMAND_WORD + " relative"; + expectedModel = getModel(); + + assertCommandSuccess(command, expectedModel); + assertSelectedCardUnchanged(); + + /* Case: find person in address book, keyword is same as name but of different case -> 1 person found */ + command = ViewTagCommand.COMMAND_WORD + " rElATivE"; + assertCommandSuccess(command, expectedModel); + assertSelectedCardUnchanged(); + + /* Case: find person in address book, keyword is substring of name -> 0 persons found */ + command = ViewTagCommand.COMMAND_WORD + " relat"; + ModelHelper.setFilteredList(expectedModel); + assertCommandSuccess(command, expectedModel); + assertSelectedCardUnchanged(); + + /* Case: find person in address book, name is substring of keyword -> 0 persons found */ + command = ViewTagCommand.COMMAND_WORD + " myrelative"; + ModelHelper.setFilteredList(expectedModel); + assertCommandSuccess(command, expectedModel); + assertSelectedCardUnchanged(); + + /* Case: find persons for a tag which doesn't exist-> 0 persons found */ + command = ViewTagCommand.COMMAND_WORD + " school"; + assertCommandSuccess(command, expectedModel); + assertSelectedCardUnchanged(); + + /* Case: find person in empty address book -> 0 persons found */ + executeCommand(ClearCommand.COMMAND_WORD); + assert getModel().getAddressBook().getPersonList().size() == 0; + command = ViewTagCommand.COMMAND_WORD + " " + KEYWORD_TAG_FRIEND; + expectedModel = getModel(); + ModelHelper.setFilteredList(expectedModel, DANIEL); + assertCommandSuccess(command, expectedModel); + assertSelectedCardUnchanged(); + + /* Case: mixed case command word -> rejected */ + command = "viEwTaG owesMONey"; + assertCommandFailure(command, MESSAGE_UNKNOWN_COMMAND); + + + } + + + + /** + * Executes {@code command} and verifies that the command box displays an empty string, the result display + * box displays {@code Messages#MESSAGE_PERSONS_LISTED_OVERVIEW} with the number of people in the filtered list, + * and the model related components equal to {@code expectedModel}. + * These verifications are done by + * {@code AddressBookSystemTest#assertApplicationDisplaysExpected(String, String, Model)}.
+ * Also verifies that the status bar remains unchanged, and the command box has the default style class, and the + * selected card updated accordingly, depending on {@code cardStatus}. + * @see AddressBookSystemTest#assertApplicationDisplaysExpected(String, String, Model) + */ + private void assertCommandSuccess(String command, Model expectedModel) { + String expectedResultMessage = String.format( + MESSAGE_PERSONS_LISTED_OVERVIEW, expectedModel.getFilteredPersonList().size()); + + executeCommand(command); + assertApplicationDisplaysExpected("", expectedResultMessage, expectedModel); + assertCommandBoxShowsDefaultStyle(); + if (expectedModel.getFilteredPersonList().size() != 0) { + assertStatusBarUnchangedExceptSyncStatus(); + } else { + assertStatusBarUnchanged(); + } + + } + + /** + * Executes {@code command} and verifies that the command box displays {@code command}, the result display + * box displays {@code expectedResultMessage} and the model related components equal to the current model. + * These verifications are done by + * {@code AddressBookSystemTest#assertApplicationDisplaysExpected(String, String, Model)}.
+ * Also verifies that the browser url, selected card and status bar remain unchanged, and the command box has the + * error style. + * @see AddressBookSystemTest#assertApplicationDisplaysExpected(String, String, Model) + */ + private void assertCommandFailure(String command, String expectedResultMessage) { + Model expectedModel = getModel(); + + executeCommand(command); + assertApplicationDisplaysExpected(command, expectedResultMessage, expectedModel); + assertSelectedCardUnchanged(); + assertCommandBoxShowsErrorStyle(); + assertStatusBarUnchanged(); + } +} +``` From 460aa5b90ee330b669e159df922ef5534ad1c940 Mon Sep 17 00:00:00 2001 From: Shradheya Thakre Date: Tue, 31 Oct 2017 23:11:21 +0800 Subject: [PATCH 2/2] Tags retained --- collated/test/tshradheya.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/collated/test/tshradheya.md b/collated/test/tshradheya.md index 828d4ec24bdb..eaa45234a3f9 100644 --- a/collated/test/tshradheya.md +++ b/collated/test/tshradheya.md @@ -469,6 +469,32 @@ public class EmailCommandTest { } ``` +###### \java\seedu\address\logic\commands\ExportCommandTest.java +``` java + + public static final String VALID_PATH = "/storage/classmates"; + private Model model = new ModelManager(getTypicalAddressBook(), getUniqueTypicalReminders(), new UserPrefs()); + + @Test + public void execute_invalidPersonIndexUnfilteredList_failure() throws Exception { + Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1); + ExportCommand exportCommand = prepareCommand(Integer.toString(outOfBoundIndex.getOneBased()), VALID_PATH); + + assertCommandFailure(exportCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + + @Test + public void execute_invalidPersonIndexFilteredList_failure() throws Exception { + showFirstPersonOnly(model); + Index outOfBoundIndex = INDEX_SECOND_PERSON; + // ensures that outOfBoundIndex is still within bounds of address book list + assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size()); + + ExportCommand exportCommand = prepareCommand(Integer.toString(outOfBoundIndex.getOneBased()), VALID_PATH); + + assertCommandFailure(exportCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } +``` ###### \java\seedu\address\logic\commands\LocationCommandTest.java ``` java package seedu.address.logic.commands;