Skip to content

Commit

Permalink
Merge pull request #67 from joelgoh1/EditSortCommand
Browse files Browse the repository at this point in the history
Edit sort command
  • Loading branch information
amanzainal authored Apr 4, 2024
2 parents 90d654d + 7f3c1bb commit 9333985
Show file tree
Hide file tree
Showing 10 changed files with 232 additions and 14 deletions.
38 changes: 31 additions & 7 deletions src/main/java/seedu/address/logic/commands/SortCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
import java.util.Comparator;
import java.util.Optional;

import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.model.Model;
import seedu.address.model.student.Student;
import seedu.address.model.student.TestNameEqualsKeywordPredicate;


/**
Expand All @@ -24,7 +26,7 @@ public class SortCommand extends Command {
+ "/r means reverse so it will sort in decreasing order, highest grade first.\n"
+ "Example: " + COMMAND_WORD + " ca1 /r";

private final String testName;
private final TestNameEqualsKeywordPredicate predicate;
private final boolean isReverse;

/**
Expand All @@ -41,27 +43,49 @@ public class SortCommand extends Command {
* Example:
* - sort Math /r: Sorts students based on their Math test grades in decreasing order.
*/
public SortCommand(String testName, boolean isReverse) {
this.testName = testName;
public SortCommand(TestNameEqualsKeywordPredicate predicate, boolean isReverse) {
this.predicate = predicate;
this.isReverse = isReverse;
}

@Override
public CommandResult execute(Model model) {
requireNonNull(model);
Comparator<Student> gradeComparator = (student1, student2) -> {
String grade1 = Optional.ofNullable(student1.getGradeForTest(testName)).orElse("0");
String grade2 = Optional.ofNullable(student2.getGradeForTest(testName)).orElse("0");
String grade1 = Optional.ofNullable(student1.getGradeForTest(predicate.keyword)).orElse("0");
String grade2 = Optional.ofNullable(student2.getGradeForTest(predicate.keyword)).orElse("0");
return grade1.compareTo(grade2);
};

if (isReverse) {
gradeComparator = gradeComparator.reversed();
}

model.sortFilteredStudentList(gradeComparator);
model.sortFilteredStudentList(gradeComparator, predicate);
return new CommandResult(String.format(Messages.MESSAGE_STUDENTS_LISTED_OVERVIEW,
model.getFilteredStudentList().size()));
model.getFilteredStudentList().size()));
}

@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}

// instanceof handles nulls
if (!(other instanceof SortCommand)) {
return false;
}

SortCommand otherSortCommand = (SortCommand) other;
return predicate.equals(otherSortCommand.predicate) && isReverse == otherSortCommand.isReverse;
}

@Override
public String toString() {
return new ToStringBuilder(this)
.add("predicate", predicate)
.add("isReverse", isReverse)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ private Optional<Set<Timeslots>> parseTimeslotsForEdit(Collection<String> timesl
Set<Timeslots> timeslotSet = new HashSet<>();
for (String timeslotString : timeslots) {
String trimmedTimeslotString = timeslotString.trim();
if (!Timeslots.isValidTimeslot(trimmedTimeslotString)) {
throw new ParseException(Timeslots.MESSAGE_CONSTRAINTS);
}
// Remove leading and trailing curly braces if present
if (trimmedTimeslotString.startsWith("[[") && trimmedTimeslotString.endsWith("]]")) {
trimmedTimeslotString = trimmedTimeslotString.substring(2, trimmedTimeslotString.length() - 2);
Expand Down Expand Up @@ -177,6 +180,9 @@ private Optional<Set<Grade>> parseGradesForEdit(Collection<String> grades) throw
Set<Grade> gradeSet = new HashSet<>();
for (String gradeString : grades) {
String trimmedGradeString = gradeString.trim();
if (!Grade.isValidGrade(trimmedGradeString)) {
throw new ParseException(Timeslots.MESSAGE_CONSTRAINTS);
}
// Remove leading and trailing curly braces if present
if (trimmedGradeString.startsWith("[[") && trimmedGradeString.endsWith("]]")) {
trimmedGradeString = trimmedGradeString.substring(2, trimmedGradeString.length() - 2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import seedu.address.logic.commands.SortCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.student.TestNameEqualsKeywordPredicate;

/**
* Parses input arguments and creates a new SortCommand object.
Expand Down Expand Up @@ -31,7 +32,6 @@ public SortCommand parse(String args) throws ParseException {
throw new ParseException(
String.format(MESSAGE_INVALID_COMMAND_FORMAT, SortCommand.MESSAGE_USAGE));
}

return new SortCommand(testName, isReverse);
return new SortCommand(new TestNameEqualsKeywordPredicate(testName), isReverse);
}
}
2 changes: 1 addition & 1 deletion src/main/java/seedu/address/model/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,5 @@ public interface Model {
*
* @param comparator The comparator to determine the order of the list.
*/
void sortFilteredStudentList(Comparator<Student> comparator);
void sortFilteredStudentList(Comparator<Student> comparator, Predicate<Student> predicate);
}
7 changes: 5 additions & 2 deletions src/main/java/seedu/address/model/ModelManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,11 @@ public void updateFilteredStudentList(Predicate<Student> predicate) {
}

@Override
public void sortFilteredStudentList(Comparator<Student> comparator) {
this.sortedStudents.setComparator(comparator);
public void sortFilteredStudentList(Comparator<Student> comparator, Predicate<Student> predicate) {
requireNonNull(comparator);
requireNonNull(predicate);
filteredStudents.setPredicate(predicate);
sortedStudents.setComparator(comparator);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package seedu.address.model.student;

import java.util.function.Predicate;

import seedu.address.commons.util.ToStringBuilder;

/**
* Tests that any of {@code student}'s {@code Grades} matches any of the keywords given.
*/
public class TestNameEqualsKeywordPredicate implements Predicate<Student> {
public final String keyword;

public TestNameEqualsKeywordPredicate(String keyword) {
this.keyword = keyword;
}

@Override
public boolean test(Student student) {
return student.getGrades().stream()
.anyMatch(grades -> grades.testName.equalsIgnoreCase(keyword));
}

@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}

// instanceof handles nulls
if (!(other instanceof TestNameEqualsKeywordPredicate)) {
return false;
}

TestNameEqualsKeywordPredicate gradesContainsKeywordsPredicate =
(TestNameEqualsKeywordPredicate) other;
return keyword.equals(gradesContainsKeywordsPredicate.keyword);
}

@Override
public String toString() {
return new ToStringBuilder(this).add("keywords", keyword).toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public void updateFilteredStudentList(Predicate<Student> predicate) {
}

@Override
public void sortFilteredStudentList(Comparator<Student> comparator) {
public void sortFilteredStudentList(Comparator<Student> comparator, Predicate<Student> predicate) {
throw new AssertionError("This method should not be called.");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public void toStringMethod() {
}

/**
* Parses {@code userInput} into a {@code NameContainsKeywordsPredicate}.
* Parses {@code userInput} into a {@code TimeslotContainsKeywordsPredicate}.
*/
private TimeslotsContainsKeywordsPredicate preparePredicate(String userInput) {
return new TimeslotsContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+")));
Expand Down
109 changes: 109 additions & 0 deletions src/test/java/seedu/address/logic/commands/SortCommandTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package seedu.address.logic.commands;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.Messages.MESSAGE_STUDENTS_LISTED_OVERVIEW;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
import static seedu.address.testutil.TypicalStudents.ALICE;
import static seedu.address.testutil.TypicalStudents.BENSON;
import static seedu.address.testutil.TypicalStudents.getTypicalAddressBook;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Optional;

import org.junit.jupiter.api.Test;

import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
import seedu.address.model.student.Student;
import seedu.address.model.student.TestNameEqualsKeywordPredicate;

/**
* Contains integration tests (interaction with the Model) for {@code FilterCommand}.
*/
public class SortCommandTest {
private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());

@Test
public void equals() {
TestNameEqualsKeywordPredicate firstPredicate =
new TestNameEqualsKeywordPredicate("first");
TestNameEqualsKeywordPredicate secondPredicate =
new TestNameEqualsKeywordPredicate("second");

SortCommand sortFirstCommand = new SortCommand(firstPredicate, false);
SortCommand sortSecondCommand = new SortCommand(secondPredicate, false);

// same object -> returns true
assertTrue(sortFirstCommand.equals(sortFirstCommand));

// same values -> returns true
SortCommand sortFirstCommandCopy = new SortCommand(firstPredicate, false);
assertTrue(sortFirstCommand.equals(sortFirstCommandCopy));

// different types -> returns false
assertFalse(sortFirstCommand.equals(1));

// null -> returns false
assertFalse(sortFirstCommand.equals(null));

// different student -> returns false
assertFalse(sortFirstCommand.equals(sortSecondCommand));
}

@Test
public void execute_zeroKeywords_nostudentFound() {
String expectedMessage = String.format(MESSAGE_STUDENTS_LISTED_OVERVIEW, 0);
TestNameEqualsKeywordPredicate predicate = preparePredicate(" ");
Comparator<Student> gradeComparator = (student1, student2) -> {
String grade1 = Optional.ofNullable(student1.getGradeForTest(predicate.keyword)).orElse("0");
String grade2 = Optional.ofNullable(student2.getGradeForTest(predicate.keyword)).orElse("0");
return grade1.compareTo(grade2);
};
SortCommand command = new SortCommand(predicate, false);
expectedModel.sortFilteredStudentList(gradeComparator, predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
assertEquals(Collections.emptyList(), model.getFilteredStudentList());
}

@Test
public void execute_multipleKeywords_multiplestudentsFound() {
String expectedMessage = String.format(MESSAGE_STUDENTS_LISTED_OVERVIEW, 2);
TestNameEqualsKeywordPredicate predicate = preparePredicate("Ca1");
Comparator<Student> gradeComparator = (student1, student2) -> {
String grade1 = Optional.ofNullable(student1.getGradeForTest(predicate.keyword)).orElse("0");
String grade2 = Optional.ofNullable(student2.getGradeForTest(predicate.keyword)).orElse("0");
return grade1.compareTo(grade2);
};
SortCommand command = new SortCommand(predicate, false);
expectedModel.sortFilteredStudentList(gradeComparator, predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
assertEquals(Arrays.asList(ALICE, BENSON), model.getFilteredStudentList());
}

@Test
public void toStringMethod() {
TestNameEqualsKeywordPredicate predicate = new TestNameEqualsKeywordPredicate("keyword");
Comparator<Student> gradeComparator = (student1, student2) -> {
String grade1 = Optional.ofNullable(student1.getGradeForTest(predicate.keyword)).orElse("0");
String grade2 = Optional.ofNullable(student2.getGradeForTest(predicate.keyword)).orElse("0");
return grade1.compareTo(grade2);
};
SortCommand sortCommand = new SortCommand(predicate, false);
String expected = SortCommand.class.getCanonicalName() + "{predicate=" + predicate + ", "
+ "isReverse=" + false + "}";
assertEquals(expected, sortCommand.toString());
}

/**
* Parses {@code userInput} into a {@code TestNameEqualsKeywordPredicate}.
*/
private TestNameEqualsKeywordPredicate preparePredicate(String userInput) {
return new TestNameEqualsKeywordPredicate(userInput);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package seedu.address.logic.parser;

import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;

import org.junit.jupiter.api.Test;

import seedu.address.logic.commands.SortCommand;
import seedu.address.model.student.TestNameEqualsKeywordPredicate;

public class SortCommandParserTest {

private SortCommandParser parser = new SortCommandParser();

@Test
public void parse_emptyArg_throwsParseException() {
assertParseFailure(parser, " ",
String.format(MESSAGE_INVALID_COMMAND_FORMAT, SortCommand.MESSAGE_USAGE));
}

@Test
public void parse_validArgs_returnsSortCommand() {
// no leading and trailing whitespaces
SortCommand expectedSortCommand =
new SortCommand(new TestNameEqualsKeywordPredicate("ca1"), false);
assertParseSuccess(parser, "ca1", expectedSortCommand);

// multiple whitespaces between keywords
assertParseSuccess(parser, " \n ca1 \t", expectedSortCommand);
}

}

0 comments on commit 9333985

Please sign in to comment.