RosterStudentsCSVController.java

1
package edu.ucsb.cs.scaffold.controller;
2
3
import com.fasterxml.jackson.core.JsonProcessingException;
4
import com.opencsv.CSVReader;
5
import com.opencsv.exceptions.CsvException;
6
import edu.ucsb.cs.scaffold.entity.Course;
7
import edu.ucsb.cs.scaffold.entity.RosterStudent;
8
import edu.ucsb.cs.scaffold.enums.InsertStatus;
9
import edu.ucsb.cs.scaffold.enums.RosterStatus;
10
import edu.ucsb.cs.scaffold.errors.EntityNotFoundException;
11
import edu.ucsb.cs.scaffold.model.LoadResult;
12
import edu.ucsb.cs.scaffold.model.UpsertResponse;
13
import edu.ucsb.cs.scaffold.repository.CourseRepository;
14
import edu.ucsb.cs.scaffold.repository.RosterStudentRepository;
15
import edu.ucsb.cs.scaffold.services.UpdateUserService;
16
import edu.ucsb.cs156.jobs.services.JobService;
17
import io.swagger.v3.oas.annotations.Operation;
18
import io.swagger.v3.oas.annotations.Parameter;
19
import io.swagger.v3.oas.annotations.tags.Tag;
20
import java.io.BufferedInputStream;
21
import java.io.IOException;
22
import java.io.InputStream;
23
import java.io.InputStreamReader;
24
import java.util.ArrayList;
25
import java.util.Arrays;
26
import java.util.HashMap;
27
import java.util.List;
28
import java.util.Map;
29
import lombok.extern.slf4j.Slf4j;
30
import org.springframework.beans.factory.annotation.Autowired;
31
import org.springframework.http.HttpStatus;
32
import org.springframework.http.ResponseEntity;
33
import org.springframework.security.access.prepost.PreAuthorize;
34
import org.springframework.web.bind.annotation.PostMapping;
35
import org.springframework.web.bind.annotation.RequestMapping;
36
import org.springframework.web.bind.annotation.RequestParam;
37
import org.springframework.web.bind.annotation.RestController;
38
import org.springframework.web.multipart.MultipartFile;
39
import org.springframework.web.server.ResponseStatusException;
40
41
@Tag(name = "RosterStudents")
42
@RequestMapping("/api/rosterstudents")
43
@RestController
44
@Slf4j
45
public class RosterStudentsCSVController extends ApiController {
46
47
  @Autowired private RosterStudentRepository rosterStudentRepository;
48
49
  @Autowired private CourseRepository courseRepository;
50
51
  @Autowired private UpdateUserService updateUserService;
52
  @Autowired private JobService jobService;
53
54
  public enum RosterSourceType {
55
    UCSB_EGRADES,
56
    CHICO_CANVAS,
57
    OREGON_STATE,
58
    ROSTER_DOWNLOAD,
59
    UNKNOWN
60
  }
61
62
  public static final String UCSB_EGRADES_HEADERS =
63
      "Enrl Cd,Perm #,Grade,Final Units,Student Last,Student First Middle,Quarter,Course ID,Section,Meeting Time(s) / Location(s),Email,ClassLevel,Major1,Major2,Date/Time,Pronoun";
64
  public static final String CHICO_CANVAS_HEADERS =
65
      "Student Name,Student ID,Student SIS ID,Email,Section Name";
66
  public static final String OREGON_STATE_HEADERS =
67
      "Full name,Sortable name,Canvas user id,Overall course grade,Assignment on time percent,Last page view time,Last participation time,Last logged out,Email,SIS Id";
68
  public static final String ROSTER_DOWNLOAD_HEADERS =
69
      "COURSEID,EMAIL,FIRSTNAME,GITHUBID,GITHUBLOGIN,ID,LASTNAME,ORGSTATUS,ROSTERSTATUS,SECTION,STUDENTID,TEAMS,USERID";
70
71
  public static RosterSourceType getRosterSourceType(String[] headers) {
72
73
    Map<RosterSourceType, String[]> sourceTypeToHeaders = new HashMap<>();
74
75
    sourceTypeToHeaders.put(RosterSourceType.UCSB_EGRADES, UCSB_EGRADES_HEADERS.split(","));
76
    sourceTypeToHeaders.put(RosterSourceType.CHICO_CANVAS, CHICO_CANVAS_HEADERS.split(","));
77
    sourceTypeToHeaders.put(RosterSourceType.OREGON_STATE, OREGON_STATE_HEADERS.split(","));
78
    sourceTypeToHeaders.put(RosterSourceType.ROSTER_DOWNLOAD, ROSTER_DOWNLOAD_HEADERS.split(","));
79
80
    for (Map.Entry<RosterSourceType, String[]> entry : sourceTypeToHeaders.entrySet()) {
81
      RosterSourceType type = entry.getKey();
82
      String[] expectedHeaders = entry.getValue();
83 2 1. getRosterSourceType : changed conditional boundary → KILLED
2. getRosterSourceType : negated conditional → KILLED
      if (headers.length >= expectedHeaders.length) {
84
        boolean matches = true;
85 2 1. getRosterSourceType : negated conditional → KILLED
2. getRosterSourceType : changed conditional boundary → KILLED
        for (int i = 0; i < expectedHeaders.length; i++) {
86 1 1. getRosterSourceType : negated conditional → KILLED
          if (!expectedHeaders[i].trim().equalsIgnoreCase(headers[i].trim())) {
87
            matches = false;
88
            break;
89
          }
90
        }
91 1 1. getRosterSourceType : negated conditional → KILLED
        if (matches) {
92 1 1. getRosterSourceType : replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::getRosterSourceType → KILLED
          return type;
93
        }
94
      }
95
    }
96
    // If no known type matches, return UNKNOWN
97 1 1. getRosterSourceType : replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::getRosterSourceType → KILLED
    return RosterSourceType.UNKNOWN;
98
  }
99
100
  /**
101
   * Upload Roster students for Course in any supported format. It is important to keep the code in
102
   * this method consistent with the code for adding a single roster student
103
   *
104
   * @param courseId
105
   * @param file
106
   * @return
107
   * @throws JsonProcessingException
108
   * @throws IOException
109
   * @throws CsvException
110
   */
111
  @Operation(summary = "Upload Roster students for Course in any supported Format")
112
  @PreAuthorize("@CourseSecurity.hasManagePermissions(#root, #courseId)")
113
  @PostMapping(
114
      value = "/upload/csv",
115
      consumes = {"multipart/form-data"})
116
  public ResponseEntity<LoadResult> uploadRosterStudentsCSV(
117
      @Parameter(name = "courseId") @RequestParam Long courseId,
118
      @Parameter(name = "file") @RequestParam("file") MultipartFile file)
119
      throws JsonProcessingException, IOException, CsvException {
120
121
    Course course =
122
        courseRepository
123
            .findById(courseId)
124 1 1. lambda$uploadRosterStudentsCSV$0 : replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::lambda$uploadRosterStudentsCSV$0 → KILLED
            .orElseThrow(() -> new EntityNotFoundException(Course.class, courseId.toString()));
125
126
    course.getRosterStudents().stream()
127 2 1. lambda$uploadRosterStudentsCSV$1 : replaced boolean return with true for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::lambda$uploadRosterStudentsCSV$1 → KILLED
2. lambda$uploadRosterStudentsCSV$1 : negated conditional → KILLED
        .filter(filteredStudent -> filteredStudent.getRosterStatus() == RosterStatus.ROSTER)
128 2 1. lambda$uploadRosterStudentsCSV$2 : removed call to edu/ucsb/cs/scaffold/entity/RosterStudent::setRosterStatus → KILLED
2. uploadRosterStudentsCSV : removed call to java/util/stream/Stream::forEach → KILLED
        .forEach(student -> student.setRosterStatus(RosterStatus.DROPPED));
129
130
    int counts[] = {0, 0};
131
    List<RosterStudent> rejectedStudents = new ArrayList<>();
132
133
    try (InputStream inputStream = new BufferedInputStream(file.getInputStream());
134
        InputStreamReader reader = new InputStreamReader(inputStream);
135
        CSVReader csvReader = new CSVReader(reader); ) {
136
137
      String[] headers = csvReader.readNext();
138
      RosterSourceType sourceType = getRosterSourceType(headers);
139 1 1. uploadRosterStudentsCSV : negated conditional → KILLED
      if (sourceType == RosterSourceType.UNKNOWN) {
140
        throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Unknown Roster Source Type");
141
      }
142 1 1. uploadRosterStudentsCSV : negated conditional → KILLED
      if (sourceType == RosterSourceType.UCSB_EGRADES) {
143 1 1. uploadRosterStudentsCSV : removed call to com/opencsv/CSVReader::skip → KILLED
        csvReader.skip(1);
144
      }
145
      List<String[]> myEntries = csvReader.readAll();
146
      for (String[] row : myEntries) {
147
        RosterStudent rosterStudent = fromCSVRow(row, sourceType);
148
        UpsertResponse upsertResponse =
149
            RosterStudentsController.upsertStudent(rosterStudent, course, RosterStatus.ROSTER);
150 1 1. uploadRosterStudentsCSV : negated conditional → KILLED
        if (upsertResponse.getInsertStatus() == InsertStatus.REJECTED) {
151
          rejectedStudents.add(upsertResponse.rosterStudent());
152
        } else {
153
          InsertStatus s = upsertResponse.getInsertStatus();
154 1 1. uploadRosterStudentsCSV : negated conditional → KILLED
          if (s == InsertStatus.INSERTED) {
155
            course.getRosterStudents().add(upsertResponse.rosterStudent());
156
          }
157 1 1. uploadRosterStudentsCSV : Replaced integer addition with subtraction → KILLED
          counts[s.ordinal()]++;
158
        }
159
      }
160
    }
161 1 1. uploadRosterStudentsCSV : negated conditional → KILLED
    if (rejectedStudents.isEmpty()) {
162
      List<RosterStudent> droppedStudents =
163
          course.getRosterStudents().stream()
164 2 1. lambda$uploadRosterStudentsCSV$3 : replaced boolean return with true for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::lambda$uploadRosterStudentsCSV$3 → KILLED
2. lambda$uploadRosterStudentsCSV$3 : negated conditional → KILLED
              .filter(student -> student.getRosterStatus() == RosterStatus.DROPPED)
165
              .toList();
166
      LoadResult successfulResult =
167
          new LoadResult(
168
              counts[InsertStatus.INSERTED.ordinal()],
169
              counts[InsertStatus.UPDATED.ordinal()],
170
              droppedStudents.size(),
171
              List.of());
172
      rosterStudentRepository.saveAll(course.getRosterStudents());
173 1 1. uploadRosterStudentsCSV : removed call to edu/ucsb/cs/scaffold/services/UpdateUserService::attachUsersToRosterStudents → KILLED
      updateUserService.attachUsersToRosterStudents(course.getRosterStudents());
174 1 1. uploadRosterStudentsCSV : replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::uploadRosterStudentsCSV → KILLED
      return ResponseEntity.ok(successfulResult);
175
    } else {
176
      LoadResult conflictResult = new LoadResult(0, 0, 0, rejectedStudents);
177 1 1. uploadRosterStudentsCSV : replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::uploadRosterStudentsCSV → KILLED
      return ResponseEntity.status(HttpStatus.CONFLICT).body(conflictResult);
178
    }
179
  }
180
181
  public static RosterStudent fromCSVRow(String[] row, RosterSourceType sourceType) {
182 1 1. fromCSVRow : negated conditional → KILLED
    if (sourceType == RosterSourceType.UCSB_EGRADES) {
183 1 1. fromCSVRow : replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::fromCSVRow → KILLED
      return fromUCSBEgradesCSVRow(row);
184 1 1. fromCSVRow : negated conditional → KILLED
    } else if (sourceType == RosterSourceType.CHICO_CANVAS) {
185 1 1. fromCSVRow : replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::fromCSVRow → KILLED
      return fromChicoCanvasCSVRow(row);
186 1 1. fromCSVRow : negated conditional → KILLED
    } else if (sourceType == RosterSourceType.OREGON_STATE) {
187 1 1. fromCSVRow : replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::fromCSVRow → KILLED
      return fromOregonStateCSVRow(row);
188 1 1. fromCSVRow : negated conditional → KILLED
    } else if (sourceType == RosterSourceType.ROSTER_DOWNLOAD) {
189 1 1. fromCSVRow : replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::fromCSVRow → KILLED
      return fromRosterDownloadCSVRow(row);
190
    } else {
191
      throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "CSV format not recognized");
192
    }
193
  }
194
195
  public static void checkRowLength(String[] row, int expectedLength, RosterSourceType sourceType) {
196 2 1. checkRowLength : negated conditional → KILLED
2. checkRowLength : changed conditional boundary → KILLED
    if (row.length < expectedLength) {
197
      throw new ResponseStatusException(
198
          HttpStatus.BAD_REQUEST,
199
          String.format(
200
              "%s CSV row does not have enough columns. Length = %d Row content = [%s]",
201
              sourceType.toString(), row.length, Arrays.toString(row)));
202
    }
203
  }
204
205
  public static RosterStudent fromUCSBEgradesCSVRow(String[] row) {
206 1 1. fromUCSBEgradesCSVRow : removed call to edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::checkRowLength → KILLED
    checkRowLength(row, 11, RosterSourceType.UCSB_EGRADES);
207 1 1. fromUCSBEgradesCSVRow : replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::fromUCSBEgradesCSVRow → KILLED
    return RosterStudent.builder()
208
        .firstName(row[5])
209
        .lastName(row[4])
210
        .studentId(row[1])
211
        .email(row[10].strip())
212
        .section(row[0])
213
        .build();
214
  }
215
216
  public static RosterStudent fromChicoCanvasCSVRow(String[] row) {
217 1 1. fromChicoCanvasCSVRow : removed call to edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::checkRowLength → KILLED
    checkRowLength(row, 4, RosterSourceType.CHICO_CANVAS);
218 1 1. fromChicoCanvasCSVRow : replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::fromChicoCanvasCSVRow → KILLED
    return RosterStudent.builder()
219
        .firstName(getFirstName(row[0]))
220
        .lastName(getLastName(row[0]))
221
        .studentId(row[2])
222
        .email(row[3].strip())
223
        .section("")
224
        .build();
225
  }
226
227
  public static RosterStudent fromOregonStateCSVRow(String[] row) {
228
229 1 1. fromOregonStateCSVRow : removed call to edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::checkRowLength → KILLED
    checkRowLength(row, 10, RosterSourceType.OREGON_STATE);
230
    String sortableName = row[1];
231
    String sortableNameParts[] = sortableName.split(",");
232
    String lastName = sortableNameParts[0].trim();
233 2 1. fromOregonStateCSVRow : negated conditional → KILLED
2. fromOregonStateCSVRow : changed conditional boundary → KILLED
    String firstName = sortableNameParts.length > 1 ? sortableNameParts[1].trim() : "";
234 1 1. fromOregonStateCSVRow : replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::fromOregonStateCSVRow → KILLED
    return RosterStudent.builder()
235
        .firstName(firstName)
236
        .lastName(lastName)
237
        .studentId(row[9])
238
        .email(row[8].strip())
239
        .section("")
240
        .build();
241
  }
242
243
  public static RosterStudent fromRosterDownloadCSVRow(String[] row) {
244
    // Header order: COURSEID, EMAIL, FIRSTNAME, GITHUBID, GITHUBLOGIN, ID, LASTNAME,
245
    // ORGSTATUS, ROSTERSTATUS, SECTION, STUDENTID, TEAMS, USERID
246 1 1. fromRosterDownloadCSVRow : removed call to edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::checkRowLength → KILLED
    checkRowLength(row, 13, RosterSourceType.ROSTER_DOWNLOAD);
247 1 1. fromRosterDownloadCSVRow : replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::fromRosterDownloadCSVRow → KILLED
    return RosterStudent.builder()
248
        .firstName(row[2])
249
        .lastName(row[6])
250
        .studentId(row[10])
251
        .email(row[1].strip())
252
        .section(row[9])
253
        .build();
254
  }
255
256
  /**
257
   * Get everything except up to and not including the last space in the full name. If the string
258
   * contains no spaces, return an empty string.
259
   *
260
   * @param fullName
261
   * @return
262
   */
263
  public static String getFirstName(String fullName) {
264
    int lastSpaceIndex = fullName.lastIndexOf(" ");
265 1 1. getFirstName : negated conditional → KILLED
    if (lastSpaceIndex == -1) {
266
      return ""; // No spaces found, return empty string
267
    }
268 1 1. getFirstName : replaced return value with "" for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::getFirstName → KILLED
    return fullName.substring(0, lastSpaceIndex).trim(); // Return everything before the last space
269
  }
270
271
  /**
272
   * Get everything after the last space in the full name. If the string contains no spaces, return
273
   * the entire input string as the result.
274
   *
275
   * @param fullName
276
   * @return best estimate of last name
277
   */
278
  public static String getLastName(String fullName) {
279
    int lastSpaceIndex = fullName.lastIndexOf(" ");
280 1 1. getLastName : negated conditional → KILLED
    if (lastSpaceIndex == -1) {
281 1 1. getLastName : replaced return value with "" for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::getLastName → KILLED
      return fullName; // No spaces found, return the entire string
282
    }
283 2 1. getLastName : Replaced integer addition with subtraction → KILLED
2. getLastName : replaced return value with "" for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::getLastName → KILLED
    return fullName.substring(lastSpaceIndex + 1).trim(); // Return everything after the last space
284
  }
285
}

Mutations

83

1.1
Location : getRosterSourceType
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_getRosterSourceType()]
changed conditional boundary → KILLED

2.2
Location : getRosterSourceType
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_getRosterSourceType()]
negated conditional → KILLED

85

1.1
Location : getRosterSourceType
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_getRosterSourceType()]
negated conditional → KILLED

2.2
Location : getRosterSourceType
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_getRosterSourceType()]
changed conditional boundary → KILLED

86

1.1
Location : getRosterSourceType
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_getRosterSourceType()]
negated conditional → KILLED

91

1.1
Location : getRosterSourceType
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_getRosterSourceType()]
negated conditional → KILLED

92

1.1
Location : getRosterSourceType
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_getRosterSourceType()]
replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::getRosterSourceType → KILLED

97

1.1
Location : getRosterSourceType
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_getRosterSourceType()]
replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::getRosterSourceType → KILLED

124

1.1
Location : lambda$uploadRosterStudentsCSV$0
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:instructor_cannot_upload_students_for_a_course_that_does_not_exist()]
replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::lambda$uploadRosterStudentsCSV$0 → KILLED

127

1.1
Location : lambda$uploadRosterStudentsCSV$1
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:drops_handled_correctly()]
replaced boolean return with true for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::lambda$uploadRosterStudentsCSV$1 → KILLED

2.2
Location : lambda$uploadRosterStudentsCSV$1
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:drops_handled_correctly()]
negated conditional → KILLED

128

1.1
Location : lambda$uploadRosterStudentsCSV$2
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:drops_handled_correctly()]
removed call to edu/ucsb/cs/scaffold/entity/RosterStudent::setRosterStatus → KILLED

2.2
Location : uploadRosterStudentsCSV
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:drops_handled_correctly()]
removed call to java/util/stream/Stream::forEach → KILLED

139

1.1
Location : uploadRosterStudentsCSV
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:unrecognized_csv_format_throws_an_exception()]
negated conditional → KILLED

142

1.1
Location : uploadRosterStudentsCSV
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:students_with_non_matching_student_id_and_email_are_rejected()]
negated conditional → KILLED

143

1.1
Location : uploadRosterStudentsCSV
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:students_with_non_matching_student_id_and_email_are_rejected()]
removed call to com/opencsv/CSVReader::skip → KILLED

150

1.1
Location : uploadRosterStudentsCSV
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:students_with_non_matching_student_id_and_email_are_rejected()]
negated conditional → KILLED

154

1.1
Location : uploadRosterStudentsCSV
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:instructor_can_upload_students_for_an_existing_course_chico()]
negated conditional → KILLED

157

1.1
Location : uploadRosterStudentsCSV
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:updates_in_upsert_correctly()]
Replaced integer addition with subtraction → KILLED

161

1.1
Location : uploadRosterStudentsCSV
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:students_with_non_matching_student_id_and_email_are_rejected()]
negated conditional → KILLED

164

1.1
Location : lambda$uploadRosterStudentsCSV$3
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:updates_in_upsert_correctly()]
replaced boolean return with true for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::lambda$uploadRosterStudentsCSV$3 → KILLED

2.2
Location : lambda$uploadRosterStudentsCSV$3
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:updates_in_upsert_correctly()]
negated conditional → KILLED

173

1.1
Location : uploadRosterStudentsCSV
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:instructor_can_upload_students_for_an_existing_course_chico()]
removed call to edu/ucsb/cs/scaffold/services/UpdateUserService::attachUsersToRosterStudents → KILLED

174

1.1
Location : uploadRosterStudentsCSV
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:updates_in_upsert_correctly()]
replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::uploadRosterStudentsCSV → KILLED

177

1.1
Location : uploadRosterStudentsCSV
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:students_with_non_matching_student_id_and_email_are_rejected()]
replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::uploadRosterStudentsCSV → KILLED

182

1.1
Location : fromCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowOregonState_notEnoughColumns()]
negated conditional → KILLED

183

1.1
Location : fromCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowUCSB_sectionField()]
replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::fromCSVRow → KILLED

184

1.1
Location : fromCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowOregonState_notEnoughColumns()]
negated conditional → KILLED

185

1.1
Location : fromCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowChico_sectionField_emailSanitized()]
replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::fromCSVRow → KILLED

186

1.1
Location : fromCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowOregonState_notEnoughColumns()]
negated conditional → KILLED

187

1.1
Location : fromCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowOregonState_noComma()]
replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::fromCSVRow → KILLED

188

1.1
Location : fromCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowRosterDownload_sectionField()]
negated conditional → KILLED

189

1.1
Location : fromCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowRosterDownload_sectionField()]
replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::fromCSVRow → KILLED

196

1.1
Location : checkRowLength
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_checkRowLength_throwsException()]
negated conditional → KILLED

2.2
Location : checkRowLength
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowRosterDownload_sectionField()]
changed conditional boundary → KILLED

206

1.1
Location : fromUCSBEgradesCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowUCSB_notEnoughColumns()]
removed call to edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::checkRowLength → KILLED

207

1.1
Location : fromUCSBEgradesCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowUCSB_sectionField()]
replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::fromUCSBEgradesCSVRow → KILLED

217

1.1
Location : fromChicoCanvasCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowChico_notEnoughColumns()]
removed call to edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::checkRowLength → KILLED

218

1.1
Location : fromChicoCanvasCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowChico_sectionField_emailSanitized()]
replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::fromChicoCanvasCSVRow → KILLED

229

1.1
Location : fromOregonStateCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowOregonState_notEnoughColumns()]
removed call to edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::checkRowLength → KILLED

233

1.1
Location : fromOregonStateCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowOregonState_noComma()]
negated conditional → KILLED

2.2
Location : fromOregonStateCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowOregonState_noComma()]
changed conditional boundary → KILLED

234

1.1
Location : fromOregonStateCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowOregonState_noComma()]
replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::fromOregonStateCSVRow → KILLED

246

1.1
Location : fromRosterDownloadCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowRosterDownload_notEnoughColumns()]
removed call to edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::checkRowLength → KILLED

247

1.1
Location : fromRosterDownloadCSVRow
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_fromCSVRowRosterDownload_sectionField()]
replaced return value with null for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::fromRosterDownloadCSVRow → KILLED

265

1.1
Location : getFirstName
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_getFirstname()]
negated conditional → KILLED

268

1.1
Location : getFirstName
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_getFirstname()]
replaced return value with "" for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::getFirstName → KILLED

280

1.1
Location : getLastName
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_getLastName()]
negated conditional → KILLED

281

1.1
Location : getLastName
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_getLastName()]
replaced return value with "" for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::getLastName → KILLED

283

1.1
Location : getLastName
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_getLastName()]
Replaced integer addition with subtraction → KILLED

2.2
Location : getLastName
Killed by : edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.RosterStudentsCSVControllerTests]/[method:test_getLastName()]
replaced return value with "" for edu/ucsb/cs/scaffold/controller/RosterStudentsCSVController::getLastName → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0