001package edu.pdx.cs.joy.grader;
002
003import com.google.common.io.CharStreams;
004import edu.pdx.cs.joy.grader.gradebook.*;
005import org.junit.jupiter.api.Test;
006import org.junit.jupiter.api.io.TempDir;
007
008import java.io.*;
009import java.time.LocalDateTime;
010import java.util.Arrays;
011import java.util.stream.Collectors;
012
013import static org.hamcrest.MatcherAssert.assertThat;
014import static org.hamcrest.Matchers.*;
015
016public class SummaryReportTest {
017
018  @Test
019  public void ungradedAssignmentsDoNotCountTowardsGraded() {
020    GradeBook gradeBook = new GradeBook("test");
021    Student student = new Student("student");
022    gradeBook.addStudent(student);
023    Assignment assignment = new Assignment("assignment", 4.0);
024    gradeBook.addAssignment(assignment);
025
026    Grade grade = new Grade(assignment, Grade.NO_GRADE);
027    student.setGrade(assignment.getName(), grade);
028
029    assertThat(SummaryReport.noStudentHasGradeFor(assignment, gradeBook), equalTo(true));
030
031  }
032
033  @Test
034  public void reportsAreGeneratedInCorrectDirectories(@TempDir File tempDirectory) throws IOException {
035    GradeBook gradeBook = new GradeBook("test");
036    Assignment assignment = new Assignment("assignment", 4.0);
037    gradeBook.addAssignment(assignment);
038
039    double undergradScore = 3.0;
040    Student undergrad = addStudentInSectionWithScore(gradeBook, assignment, "undergrad", Student.Section.UNDERGRADUATE, undergradScore);
041
042    double gradScore = 3.5;
043    Student grad = addStudentInSectionWithScore(gradeBook, assignment, "grad", Student.Section.GRADUATE, gradScore);
044
045    SummaryReport.dumpReports(gradeBook.getStudentIds(), gradeBook, tempDirectory, false);
046
047    assertThatStudentHasReportInDirectoryWithScore(undergrad, tempDirectory, SummaryReport.UNDERGRADUATE_DIRECTORY_NAME, undergradScore);
048    assertThatStudentHasReportInDirectoryWithScore(grad, tempDirectory, SummaryReport.GRADUATE_DIRECTORY_NAME, gradScore);
049  }
050
051  private Student addStudentInSectionWithScore(GradeBook gradeBook, Assignment assignment, String studentId, Student.Section enrolledSection, double undergradScore) {
052    Student undergrad = new Student(studentId);
053    undergrad.setEnrolledSection(enrolledSection);
054    gradeBook.addStudent(undergrad);
055    undergrad.setGrade(assignment, undergradScore);
056    return undergrad;
057  }
058
059  private void assertThatStudentHasReportInDirectoryWithScore(Student student, File tempDirectory, String dirFileName, double studentScore) throws IOException {
060    File directory = new File(tempDirectory, dirFileName);
061    assertThat(directory.exists(), equalTo(true));
062
063    File reportFile = new File(directory, SummaryReport.getReportFileName(student.getId()));
064    assertThat(reportFile.exists(), equalTo(true));
065
066    String reportContents = readTextFromFile(reportFile);
067    assertThat(reportContents, containsString(String.valueOf(studentScore)));
068  }
069
070  private String readTextFromFile(File file) throws IOException {
071    StringWriter writer = new StringWriter();
072    CharStreams.copy(new FileReader(file), writer);
073    return writer.getBuffer().toString();
074  }
075
076  @Test
077  public void totalsArePrintedForAllStudents() {
078    GradeBook gradeBook = new GradeBook("test");
079    Assignment assignment = new Assignment("assignment", 4.0);
080    gradeBook.addAssignment(assignment);
081
082    String worseUndergradStudentName = "worseUndergrad";
083    addStudentInSectionWithScore(gradeBook, assignment, worseUndergradStudentName, Student.Section.UNDERGRADUATE, 3.0);
084
085    String betterUndergradStudentName = "betterUndergrad";
086    addStudentInSectionWithScore(gradeBook, assignment, betterUndergradStudentName, Student.Section.UNDERGRADUATE, 3.5);
087
088    String worseGradStudentName = "worseGrad";
089    addStudentInSectionWithScore(gradeBook, assignment, worseGradStudentName, Student.Section.GRADUATE, 3.0);
090
091    String betterGradStudentName = "betterGrad";
092    addStudentInSectionWithScore(gradeBook, assignment, betterGradStudentName, Student.Section.GRADUATE, 3.5);
093
094    calculateTotalGradesForStudents(gradeBook, false);
095
096    CapturingPrintWriter out = new CapturingPrintWriter();
097    SummaryReport.printOutStudentTotals(gradeBook.studentsStream().collect(Collectors.toSet()), out);
098
099    String written = out.getTextWrittenToWriter();
100    String[] strings = { betterUndergradStudentName, worseUndergradStudentName, betterGradStudentName, worseGradStudentName };
101    assertThat(written, stringContainsInOrder(Arrays.asList(strings)));
102  }
103
104  private void calculateTotalGradesForStudents(GradeBook gradeBook, boolean assignLetterGrades) {
105    PrintWriter pw = new PrintWriter(new Writer() {
106      @Override
107      public void write(char[] cbuf, int off, int len) {
108
109      }
110
111      @Override
112      public void flush() {
113
114      }
115
116      @Override
117      public void close() {
118
119      }
120    });
121
122    gradeBook.studentsStream().forEach(student -> SummaryReport.dumpReportTo(gradeBook, student, pw, assignLetterGrades));
123  }
124
125  private static class CapturingPrintWriter extends PrintWriter {
126    public CapturingPrintWriter() {
127      super(new StringWriter());
128    }
129
130    public String getTextWrittenToWriter() {
131      return ((StringWriter) this.out).getBuffer().toString();
132    }
133  }
134
135  @Test
136  public void assignLetterGradesAccordingToGradeBookRangesForSection() {
137    GradeBook gradeBook = new GradeBook("test");
138    Assignment assignment = new Assignment("assignment", 10.0);
139    gradeBook.addAssignment(assignment);
140
141    GradeBook.LetterGradeRanges undergradLetterGradeRanges = gradeBook.getLetterGradeRanges(Student.Section.UNDERGRADUATE);
142    undergradLetterGradeRanges.getRange(LetterGrade.A).setRange(95, 100);
143    undergradLetterGradeRanges.getRange(LetterGrade.A_MINUS).setRange(90, 94);
144    undergradLetterGradeRanges.validate();
145
146    GradeBook.LetterGradeRanges gradLetterGradeRanges = gradeBook.getLetterGradeRanges(Student.Section.GRADUATE);
147    gradLetterGradeRanges.getRange(LetterGrade.A).setRange(92, 100);
148    gradLetterGradeRanges.getRange(LetterGrade.A_MINUS).setRange(90, 91);
149    gradLetterGradeRanges.validate();
150
151    String betterUndergradStudentName = "betterUndergrad";
152    Student betterUndergrad = addStudentInSectionWithScore(gradeBook, assignment, betterUndergradStudentName, Student.Section.UNDERGRADUATE, 9.7);
153    assertThat(betterUndergrad.getLetterGrade(), nullValue());
154
155    String worseUndergradStudentName = "worseUndergrad";
156    Student worseUndergrad = addStudentInSectionWithScore(gradeBook, assignment, worseUndergradStudentName, Student.Section.UNDERGRADUATE, 9.2);
157    assertThat(worseUndergrad.getLetterGrade(), nullValue());
158
159    String gradStudentName = "grad";
160    Student grad = addStudentInSectionWithScore(gradeBook, assignment, gradStudentName, Student.Section.GRADUATE, 9.2);
161    assertThat(grad.getLetterGrade(), nullValue());
162
163    calculateTotalGradesForStudents(gradeBook, true);
164
165    assertThat(betterUndergrad.getLetterGrade(), equalTo(LetterGrade.A));
166    assertThat(worseUndergrad.getLetterGrade(), equalTo(LetterGrade.A_MINUS));
167    assertThat(grad.getLetterGrade(), equalTo(LetterGrade.A));
168  }
169
170  @Test
171  public void assignmentDueInThePastIsLate() {
172    Assignment assignment = new Assignment("Test", 4.0);
173    LocalDateTime dueDate = LocalDateTime.now().minusDays(3);
174    assignment.setDueDate(dueDate);
175
176    assertThat(SummaryReport.dueDateHasPassed(assignment), equalTo(true));
177  }
178
179  @Test
180  public void assignmentDueInTheFutureIsNotLate() {
181    Assignment assignment = new Assignment("Test", 4.0);
182    LocalDateTime dueDate = LocalDateTime.now().plusDays(3);
183    assignment.setDueDate(dueDate);
184
185    assertThat(SummaryReport.dueDateHasPassed(assignment), equalTo(false));
186  }
187
188  @Test
189  void assignmentWithAllZeroGradesDoesNotAppearInReport(@TempDir File tempDirectory) throws IOException {
190    GradeBook gradeBook = new GradeBook("test");
191    String someNonZeroGradesName = "someNonZeroGrades";
192    String allZeroGradesName = "allZeroGrades";
193
194    Assignment someNonZeroGrades = gradeBook.addAssignment(new Assignment(someNonZeroGradesName, 10.0));
195    Assignment allZeroGrades = gradeBook.addAssignment(new Assignment(allZeroGradesName, 10.0));
196
197    Student studentWithSomeNonZeroGrades =
198      gradeBook.addStudent(new Student("studentWithSomeNonZeroGrades"))
199        .setLastName("studentWithSomeNonZeroGrades")
200        .setEnrolledSection(Student.Section.UNDERGRADUATE)
201        .setGrade(someNonZeroGrades, 5.0)
202        .setGrade(allZeroGrades, 0.0);
203
204    Student studentWithAllZeroGrades =
205      gradeBook.addStudent(new Student("studentWithAllZeroGrades"))
206        .setLastName("studentWithAllZeroGrades")
207        .setEnrolledSection(Student.Section.UNDERGRADUATE)
208        .setGrade(someNonZeroGrades, 0.0)
209        .setGrade(allZeroGrades, 0.0);
210
211    assertThat(SummaryReport.noStudentHasGradeFor(allZeroGrades, gradeBook), equalTo(true));
212
213    SummaryReport.dumpReports(gradeBook.getStudentIds(), gradeBook, tempDirectory, false);
214
215    File studentWithSomeNonZeroGradesReportFile = getStudentReportFile(tempDirectory, studentWithSomeNonZeroGrades);
216    assertThat(studentWithSomeNonZeroGradesReportFile.exists(), equalTo(true));
217
218    String studentWithSomeNonZeroGradesReport = readTextFromFile(studentWithSomeNonZeroGradesReportFile);
219    assertThat(studentWithSomeNonZeroGradesReport, containsString(someNonZeroGradesName));
220    assertThat(studentWithSomeNonZeroGradesReport, not(containsString(allZeroGradesName)));
221
222    File studentWithAllZeroGradesReportFile = getStudentReportFile(tempDirectory, studentWithAllZeroGrades);
223    assertThat(studentWithAllZeroGradesReportFile.exists(), equalTo(true));
224
225    String studentWithAllZeroGradesReport = readTextFromFile(studentWithAllZeroGradesReportFile);
226    assertThat(studentWithAllZeroGradesReport, containsString(someNonZeroGradesName));
227    assertThat(studentWithAllZeroGradesReport, not(containsString(allZeroGradesName)));
228
229  }
230
231  private static File getStudentReportFile(File directory, Student student) {
232    String sectionDirName;
233    switch (student.getEnrolledSection()) {
234      case GRADUATE:
235        sectionDirName = SummaryReport.GRADUATE_DIRECTORY_NAME;
236        break;
237      case UNDERGRADUATE:
238        sectionDirName = SummaryReport.UNDERGRADUATE_DIRECTORY_NAME;
239        break;
240      default:
241        throw new UnsupportedOperationException("Don't know how to handle section: " + student.getEnrolledSection());
242    }
243
244    File sectionDirectory = new File(directory, sectionDirName);
245    return new File(sectionDirectory, SummaryReport.getReportFileName(student.getId()));
246  }
247
248  @Test
249  void missingGradeIsClearInReport(@TempDir File tempDirectory) throws IOException {
250    GradeBook gradeBook = new GradeBook("test");
251
252    String assignmentName = "Assignment";
253    Assignment assignment = gradeBook.addAssignment(new Assignment(assignmentName, 10.0));
254    Assignment assignment2 = gradeBook.addAssignment(new Assignment("Assignment 2", 10.0));
255
256    Student studentWithMissingGrade =
257      gradeBook.addStudent(new Student("studentWithMissingGrade"))
258        .setLastName("studentWithMissingGrade")
259        .setEnrolledSection(Student.Section.UNDERGRADUATE)
260        .setGrade(assignment, Grade.NO_GRADE)
261        .setGrade(assignment2, 10.0);
262
263    Student studentWithGrade =
264      gradeBook.addStudent(new Student("studentWithGrade"))
265        .setLastName("studentWithGrade")
266        .setEnrolledSection(Student.Section.UNDERGRADUATE)
267        .setGrade(assignment, 10.0)
268        .setGrade(assignment2, 10.0);
269
270    SummaryReport.dumpReports(gradeBook.getStudentIds(), gradeBook, tempDirectory, false);
271
272    File studentWithMissingGradeReportFile = getStudentReportFile(tempDirectory, studentWithMissingGrade);
273    assertThat(studentWithMissingGradeReportFile.exists(), equalTo(true));
274
275    String studentWithSomeNonZeroGradesReport = readTextFromFile(studentWithMissingGradeReportFile);
276    assertThat(studentWithSomeNonZeroGradesReport, not(containsString(String.valueOf(Grade.NO_GRADE))));
277    assertThat(studentWithSomeNonZeroGradesReport, containsString("NOT GRADED"));
278  }
279
280}