001package edu.pdx.cs.joy.grader; 002 003import edu.pdx.cs.joy.grader.gradebook.Assignment; 004import edu.pdx.cs.joy.grader.gradebook.Grade; 005import edu.pdx.cs.joy.grader.gradebook.GradeBook; 006import edu.pdx.cs.joy.grader.gradebook.Student; 007import org.hamcrest.MatcherAssert; 008import org.junit.jupiter.api.Test; 009 010import java.io.StringWriter; 011import java.util.Arrays; 012import java.util.Collection; 013import java.util.List; 014import java.util.stream.Collectors; 015 016import static org.hamcrest.MatcherAssert.assertThat; 017import static org.hamcrest.Matchers.*; 018 019public class ProjectTimeEstimatesSummaryTest { 020 021 private void noteSubmission(Student student, Assignment project, Double... estimates) { 022 Grade grade = new Grade(project, Grade.NO_GRADE); 023 for (Double estimate : estimates) { 024 Grade.SubmissionInfo submission = new Grade.SubmissionInfo(); 025 if (estimate != null) { 026 submission.setEstimatedHours(estimate); 027 } 028 grade.noteSubmission(submission); 029 } 030 student.setGrade(project, grade); 031 } 032 033 private Student addStudent(GradeBook book, String studentName) { 034 Student student = new Student(studentName); 035 book.addStudent(student); 036 return student; 037 } 038 039 private Assignment addProject(GradeBook book, Assignment.ProjectType projectType) { 040 return addProject(book, "project", projectType); 041 } 042 043 private Assignment addProject(GradeBook book, String projectName, Assignment.ProjectType projectType) { 044 Assignment project = new Assignment(projectName, 1.0) 045 .setProjectType(projectType); 046 book.addAssignment(project); 047 return project; 048 } 049 050 @Test 051 void oneSubmittedProjectHasSummaryWithOneSubmission() { 052 GradeBook book = new GradeBook("test"); 053 054 Assignment.ProjectType projectType = Assignment.ProjectType.APP_CLASSES; 055 056 noteSubmission(addStudent(book, "student"), addProject(book, projectType), 10.0); 057 058 ProjectTimeEstimatesSummary summary = new ProjectTimeEstimatesSummary(); 059 ProjectTimeEstimatesSummary.TimeEstimatesSummaries summaries = summary.getTimeEstimateSummaries(book); 060 ProjectTimeEstimatesSummary.TimeEstimatesSummary estimates = summaries.getTimeEstimateSummary(projectType); 061 assertThat(estimates.getCount(), equalTo(1)); 062 } 063 064 @Test 065 void maximumEstimateByStudentIsConsidered() { 066 GradeBook book = new GradeBook("test"); 067 068 Assignment.ProjectType projectType = Assignment.ProjectType.APP_CLASSES; 069 070 double maximumEstimate = 11.0; 071 noteSubmission(addStudent(book, "student"), addProject(book, projectType), 10.0, maximumEstimate); 072 073 ProjectTimeEstimatesSummary summary = new ProjectTimeEstimatesSummary(); 074 ProjectTimeEstimatesSummary.TimeEstimatesSummaries summaries = summary.getTimeEstimateSummaries(book); 075 ProjectTimeEstimatesSummary.TimeEstimatesSummary estimates = summaries.getTimeEstimateSummary(projectType); 076 assertThat(estimates.getCount(), equalTo(1)); 077 assertThat(estimates.getMaximum(), equalTo(maximumEstimate)); 078 079 } 080 081 @Test 082 void maximumFromMultipleStudents() { 083 GradeBook book = new GradeBook("test"); 084 085 Assignment.ProjectType projectType = Assignment.ProjectType.APP_CLASSES; 086 087 double maximumEstimate = 11.0; 088 Assignment project = addProject(book, projectType); 089 noteSubmission(addStudent(book, "student1"), project, 10.0, maximumEstimate); 090 noteSubmission(addStudent(book, "student2"), project, 9.0); 091 092 ProjectTimeEstimatesSummary summary = new ProjectTimeEstimatesSummary(); 093 ProjectTimeEstimatesSummary.TimeEstimatesSummaries summaries = summary.getTimeEstimateSummaries(book); 094 ProjectTimeEstimatesSummary.TimeEstimatesSummary estimates = summaries.getTimeEstimateSummary(projectType); 095 assertThat(estimates.getCount(), equalTo(2)); 096 assertThat(estimates.getMaximum(), equalTo(maximumEstimate)); 097 } 098 099 @Test 100 void minimumFromMultipleStudents() { 101 GradeBook book = new GradeBook("test"); 102 103 Assignment.ProjectType projectType = Assignment.ProjectType.APP_CLASSES; 104 105 double minimumEstimate = 9.0; 106 Assignment project = addProject(book, projectType); 107 noteSubmission(addStudent(book, "student1"), project, 10.0, 11.0); 108 noteSubmission(addStudent(book, "student2"), project, minimumEstimate); 109 110 ProjectTimeEstimatesSummary summary = new ProjectTimeEstimatesSummary(); 111 ProjectTimeEstimatesSummary.TimeEstimatesSummaries summaries = summary.getTimeEstimateSummaries(book); 112 ProjectTimeEstimatesSummary.TimeEstimatesSummary estimates = summaries.getTimeEstimateSummary(projectType); 113 assertThat(estimates.getCount(), equalTo(2)); 114 assertThat(estimates.getMinimum(), equalTo(minimumEstimate)); 115 } 116 117 @Test 118 void medianFromMultipleStudents() { 119 GradeBook book = new GradeBook("test"); 120 121 Assignment.ProjectType projectType = Assignment.ProjectType.APP_CLASSES; 122 123 Assignment project = addProject(book, projectType); 124 double medianEstimate = 10.0; 125 noteSubmission(addStudent(book, "student1"), project, medianEstimate); 126 noteSubmission(addStudent(book, "student2"), project, 9.0); 127 noteSubmission(addStudent(book, "student3"), project, 11.0); 128 129 ProjectTimeEstimatesSummary summary = new ProjectTimeEstimatesSummary(); 130 ProjectTimeEstimatesSummary.TimeEstimatesSummaries summaries = summary.getTimeEstimateSummaries(book); 131 ProjectTimeEstimatesSummary.TimeEstimatesSummary estimates = summaries.getTimeEstimateSummary(projectType); 132 assertThat(estimates.getCount(), equalTo(3)); 133 assertThat(estimates.getMedian(), equalTo(medianEstimate)); 134 } 135 136 @Test 137 void medianOfOddNumberOfValuesIsMiddleValue() { 138 double median = 2.0; 139 Collection<Double> doubles = List.of(1.0, median, 3.0); 140 MatcherAssert.assertThat(ProjectTimeEstimatesSummary.TimeEstimatesSummary.median(doubles), equalTo(median)); 141 } 142 143 @Test 144 void medianOfEvenNumberOfValuesIsAverageOfMiddleValues() { 145 Collection<Double> doubles = List.of(1.0, 2.0, 3.0, 4.0); 146 MatcherAssert.assertThat(ProjectTimeEstimatesSummary.TimeEstimatesSummary.median(doubles), equalTo(2.5)); 147 } 148 149 @Test 150 void medianSortsValues() { 151 double median = 2.0; 152 Collection<Double> doubles = List.of(median, 1.0, 3.0); 153 MatcherAssert.assertThat(ProjectTimeEstimatesSummary.TimeEstimatesSummary.median(doubles), equalTo(median)); 154 } 155 156 @Test 157 void upperQuartileFromMultipleStudents() { 158 GradeBook book = new GradeBook("test"); 159 160 Assignment.ProjectType projectType = Assignment.ProjectType.APP_CLASSES; 161 162 double upperQuartile = 4.0; 163 Assignment project = addProject(book, projectType); 164 noteSubmission(addStudent(book, "student1"), project, 1.0); 165 noteSubmission(addStudent(book, "student2"), project, 2.0); 166 noteSubmission(addStudent(book, "student3"), project, 3.0); 167 noteSubmission(addStudent(book, "student4"), project, upperQuartile); 168 noteSubmission(addStudent(book, "student5"), project, 5.0); 169 170 ProjectTimeEstimatesSummary summary = new ProjectTimeEstimatesSummary(); 171 ProjectTimeEstimatesSummary.TimeEstimatesSummaries summaries = summary.getTimeEstimateSummaries(book); 172 ProjectTimeEstimatesSummary.TimeEstimatesSummary estimates = summaries.getTimeEstimateSummary(projectType); 173 assertThat(estimates.getUpperQuartile(), equalTo(upperQuartile)); 174 } 175 176 @Test 177 void lowerQuartileFromMultipleStudents() { 178 GradeBook book = new GradeBook("test"); 179 180 Assignment.ProjectType projectType = Assignment.ProjectType.APP_CLASSES; 181 182 double lowerQuartile = 2.0; 183 Assignment project = addProject(book, projectType); 184 noteSubmission(addStudent(book, "student1"), project, 1.0); 185 noteSubmission(addStudent(book, "student2"), project, lowerQuartile); 186 noteSubmission(addStudent(book, "student3"), project, 3.0); 187 noteSubmission(addStudent(book, "student4"), project, 4.0); 188 noteSubmission(addStudent(book, "student5"), project, 5.0); 189 190 ProjectTimeEstimatesSummary summary = new ProjectTimeEstimatesSummary(); 191 ProjectTimeEstimatesSummary.TimeEstimatesSummaries summaries = summary.getTimeEstimateSummaries(book); 192 ProjectTimeEstimatesSummary.TimeEstimatesSummary estimates = summaries.getTimeEstimateSummary(projectType); 193 assertThat(estimates.getLowerQuartile(), equalTo(lowerQuartile)); 194 } 195 196 @Test 197 void upperQuartileOfEvenNumberOfValues() { 198 double upperQuartile = 5.0; 199 List<Double> doubles = List.of(1.0, 2.0, 3.0, 4.0, upperQuartile, 6.0); 200 MatcherAssert.assertThat(ProjectTimeEstimatesSummary.TimeEstimatesSummary.upperQuartile(doubles), equalTo(upperQuartile)); 201 } 202 203 @Test 204 void lowerQuartileOfEvenNumberOfValues() { 205 double lowerQuartile = 2.0; 206 List<Double> doubles = List.of(1.0, lowerQuartile, 3.0, 4.0, 5.0, 6.0); 207 MatcherAssert.assertThat(ProjectTimeEstimatesSummary.TimeEstimatesSummary.lowerQuartile(doubles), equalTo(lowerQuartile)); 208 } 209 210 @Test 211 void lowerQuartileOfOddNumberOfValues() { 212 double lowerQuartile = 2.0; 213 List<Double> doubles = List.of(1.0, lowerQuartile, 3.0, 4.0, 5.0); 214 MatcherAssert.assertThat(ProjectTimeEstimatesSummary.TimeEstimatesSummary.lowerQuartile(doubles), equalTo(lowerQuartile)); 215 } 216 217 @Test 218 void upperQuartileOfOneValueIsThatValue() { 219 double value = 1.0; 220 MatcherAssert.assertThat(ProjectTimeEstimatesSummary.TimeEstimatesSummary.upperQuartile(List.of(value)), equalTo(value)); 221 } 222 223 @Test 224 void upperQuartileOfTwoValuesIsSecondValue() { 225 double value = 2.0; 226 MatcherAssert.assertThat(ProjectTimeEstimatesSummary.TimeEstimatesSummary.upperQuartile(List.of(1.0, value)), equalTo(value)); 227 } 228 229 @Test 230 void upperQuartileOfThreeValuesIsAverageOfSecondAndThirdValue() { 231 MatcherAssert.assertThat(ProjectTimeEstimatesSummary.TimeEstimatesSummary.upperQuartile(List.of(1.0, 2.0, 3.0)), equalTo(2.5)); 232 } 233 234 @Test 235 void upperQuartileOfFourValuesIsAverageOfThirdAndFourthValues() { 236 MatcherAssert.assertThat(ProjectTimeEstimatesSummary.TimeEstimatesSummary.upperQuartile(List.of(1.0, 2.0, 3.0, 4.0)), equalTo(3.5)); 237 } 238 239 @Test 240 void averageFromMultipleStudents() { 241 GradeBook book = new GradeBook("test"); 242 243 Assignment.ProjectType projectType = Assignment.ProjectType.APP_CLASSES; 244 245 Assignment project = addProject(book, projectType); 246 noteSubmission(addStudent(book, "student1"), project, 1.0); 247 noteSubmission(addStudent(book, "student2"), project, 2.0); 248 noteSubmission(addStudent(book, "student4"), project, 4.0); 249 noteSubmission(addStudent(book, "student5"), project, 5.0); 250 251 ProjectTimeEstimatesSummary summary = new ProjectTimeEstimatesSummary(); 252 ProjectTimeEstimatesSummary.TimeEstimatesSummaries summaries = summary.getTimeEstimateSummaries(book); 253 ProjectTimeEstimatesSummary.TimeEstimatesSummary estimates = summaries.getTimeEstimateSummary(projectType); 254 assertThat(estimates.getAverage(), equalTo(3.0)); 255 } 256 257 @Test 258 void generateMarkdown() { 259 GradeBook book = new GradeBook("test"); 260 261 Assignment appClasses = addProject(book, "AppClasses", Assignment.ProjectType.APP_CLASSES); 262 Assignment textFile = addProject(book, "TextFile", Assignment.ProjectType.TEXT_FILE); 263 264 Student student1 = addStudent(book, "student1"); 265 Student student2 = addStudent(book, "student2"); 266 Student student3 = addStudent(book, "student3"); 267 Student student4 = addStudent(book, "student4"); 268 Student student5 = addStudent(book, "student5"); 269 270 noteSubmission(student1, appClasses, 4.0); 271 noteSubmission(student2, appClasses, 5.0); 272 noteSubmission(student3, appClasses, 3.0); 273 noteSubmission(student4, appClasses, 6.0); 274 noteSubmission(student5, appClasses, 2.0); 275 noteSubmission(student1, textFile, 7.0); 276 noteSubmission(student2, textFile, 6.0); 277 noteSubmission(student3, textFile, 8.0); 278 noteSubmission(student4, textFile, 6.0); 279 noteSubmission(student5, textFile, 7.0); 280 281 ProjectTimeEstimatesSummary summary = new ProjectTimeEstimatesSummary(); 282 ProjectTimeEstimatesSummary.TimeEstimatesSummaries summaries = summary.getTimeEstimateSummaries(book); 283 ProjectTimeEstimatesSummary.TimeEstimatesSummary appClassesEstimates = summaries.getTimeEstimateSummary(appClasses.getProjectType()); 284 assertThat(appClassesEstimates.getCount(), equalTo(5)); 285 286 StringWriter sw = new StringWriter(); 287 summaries.generateMarkdown(sw, List.of(appClasses.getProjectType(), textFile.getProjectType())); 288 String markdown = sw.toString(); 289 290// System.out.println(markdown); 291 292 List<String> lines = markdown.lines().collect(Collectors.toList()); 293 294 assertThat(lines.get(0), equalTo("| | App Classes | Text File |")); 295 assertThat(lines.get(1), equalTo("| :--- | ---: | ---: |")); 296 assertThat(lines.get(2), equalTo("| Count | 5 | 5 |")); 297 assertThat(lines.get(3), matchesRegex("\\| Average \\| \\d hours \\| \\d hours \\|")); 298 assertThat(lines.get(4), matchesRegex("\\| Maximum \\| \\d hours \\| \\d hours \\|")); 299 assertThat(lines.get(5), matchesRegex("\\| Top 25% \\| \\d hours \\| \\d hours \\|")); 300 assertThat(lines.get(6), matchesRegex("\\| Median \\| \\d hours \\| \\d hours \\|")); 301 assertThat(lines.get(7), matchesRegex("\\| Bottom 25% \\| \\d hours \\| \\d hours \\|")); 302 assertThat(lines.get(8), matchesRegex("\\| Minimum \\| \\d hours \\| \\d hours \\|")); 303 } 304 305 @Test 306 void okayToGenerateMarkdownWhenProjectsWithoutType() { 307 GradeBook book = new GradeBook("test"); 308 book.addAssignment(new Assignment("project1", 1.0)); 309 book.addAssignment(new Assignment("project2", 1.0)); 310 book.addAssignment(new Assignment("project3", 1.0)); 311 312 ProjectTimeEstimatesSummary summary = new ProjectTimeEstimatesSummary(); 313 ProjectTimeEstimatesSummary.TimeEstimatesSummaries summaries = summary.getTimeEstimateSummaries(book); 314 315 StringWriter sw = new StringWriter(); 316 summaries.generateMarkdown(sw, List.of(Assignment.ProjectType.APP_CLASSES, Assignment.ProjectType.TEXT_FILE)); 317 String markdown = sw.toString(); 318 319 List<String> lines = markdown.lines().collect(Collectors.toList()); 320 321 assertThat(lines.get(0), equalTo("| | App Classes | Text File |")); 322 assertThat(lines.get(1), equalTo("| :--- | ---: | ---: |")); 323 assertThat(lines.get(2), equalTo("| Count | 0 | 0 |")); 324 assertThat(lines.get(3), equalTo("| Average | n/a | n/a |")); 325 } 326 327 @Test 328 void allProjectTypesAreFormatted() { 329 Arrays.stream(Assignment.ProjectType.values()).forEach(projectType -> MatcherAssert.assertThat(ProjectTimeEstimatesSummary.TimeEstimatesSummaries.formatProjectType(projectType), notNullValue())); 330 } 331 332 @Test 333 void submissionsWithoutEstimatesDoNotCount() { 334 GradeBook book = new GradeBook("test"); 335 336 Assignment appClasses = addProject(book, "AppClasses", Assignment.ProjectType.APP_CLASSES); 337 Student student1 = addStudent(book, "student1"); 338 noteSubmission(student1, appClasses, (Double) null); 339 340 ProjectTimeEstimatesSummary summary = new ProjectTimeEstimatesSummary(); 341 ProjectTimeEstimatesSummary.TimeEstimatesSummaries summaries = summary.getTimeEstimateSummaries(book); 342 assertThat(summaries.getTimeEstimateSummary(Assignment.ProjectType.APP_CLASSES), nullValue()); 343 } 344 345 @Test 346 void calculationsUsingMultipleGradeBooks() { 347 GradeBook book1 = new GradeBook("Book 1"); 348 GradeBook book2 = new GradeBook("Book 2"); 349 350 Assignment.ProjectType projectType = Assignment.ProjectType.APP_CLASSES; 351 352 Assignment project1 = addProject(book1, projectType); 353 noteSubmission(addStudent(book1, "student1"), project1, 1.0); 354 noteSubmission(addStudent(book1, "student2"), project1, 2.0); 355 Assignment project2 = addProject(book2, projectType); 356 noteSubmission(addStudent(book2, "student4"), project2, 4.0); 357 noteSubmission(addStudent(book2, "student5"), project2, 5.0); 358 359 ProjectTimeEstimatesSummary summary = new ProjectTimeEstimatesSummary(); 360 ProjectTimeEstimatesSummary.TimeEstimatesSummaries summaries = summary.getTimeEstimateSummaries(List.of(book1, book2)); 361 ProjectTimeEstimatesSummary.TimeEstimatesSummary estimates = summaries.getTimeEstimateSummary(projectType); 362 assertThat(estimates.getCount(), equalTo(4)); 363 assertThat(estimates.getAverage(), equalTo(3.0)); 364 } 365}