CoursesController.java

1
package edu.ucsb.cs156.frontiers.controllers;
2
3
import com.fasterxml.jackson.core.JsonProcessingException;
4
import edu.ucsb.cs156.frontiers.entities.Course;
5
import edu.ucsb.cs156.frontiers.entities.CourseStaff;
6
import edu.ucsb.cs156.frontiers.entities.RosterStudent;
7
import edu.ucsb.cs156.frontiers.entities.User;
8
import edu.ucsb.cs156.frontiers.enums.OrgStatus;
9
import edu.ucsb.cs156.frontiers.errors.EntityNotFoundException;
10
import edu.ucsb.cs156.frontiers.errors.InvalidInstallationTypeException;
11
import edu.ucsb.cs156.frontiers.models.CurrentUser;
12
import edu.ucsb.cs156.frontiers.repositories.AdminRepository;
13
import edu.ucsb.cs156.frontiers.repositories.CourseRepository;
14
import edu.ucsb.cs156.frontiers.repositories.CourseStaffRepository;
15
import edu.ucsb.cs156.frontiers.repositories.InstructorRepository;
16
import edu.ucsb.cs156.frontiers.repositories.RosterStudentRepository;
17
import edu.ucsb.cs156.frontiers.repositories.UserRepository;
18
import edu.ucsb.cs156.frontiers.services.OrganizationLinkerService;
19
import io.swagger.v3.oas.annotations.Operation;
20
import io.swagger.v3.oas.annotations.Parameter;
21
import io.swagger.v3.oas.annotations.tags.Tag;
22
import java.security.NoSuchAlgorithmException;
23
import java.security.spec.InvalidKeySpecException;
24
import java.util.ArrayList;
25
import java.util.List;
26
import java.util.Map;
27
import java.util.Optional;
28
import java.util.stream.Collectors;
29
import lombok.extern.slf4j.Slf4j;
30
import org.springframework.beans.factory.annotation.Autowired;
31
import org.springframework.http.HttpHeaders;
32
import org.springframework.http.HttpStatus;
33
import org.springframework.http.ResponseEntity;
34
import org.springframework.security.access.prepost.PreAuthorize;
35
import org.springframework.web.bind.annotation.*;
36
37
@Tag(name = "Course")
38
@RequestMapping("/api/courses")
39
@RestController
40
@Slf4j
41
public class CoursesController extends ApiController {
42
43
  @Autowired private CourseRepository courseRepository;
44
45
  @Autowired private UserRepository userRepository;
46
47
  @Autowired private RosterStudentRepository rosterStudentRepository;
48
49
  @Autowired private CourseStaffRepository courseStaffRepository;
50
51
  @Autowired private InstructorRepository instructorRepository;
52
53
  @Autowired private AdminRepository adminRepository;
54
55
  @Autowired private OrganizationLinkerService linkerService;
56
57
  /**
58
   * This method creates a new Course.
59
   *
60
   * @param courseName the name of the course
61
   * @param term the term of the course
62
   * @param school the school of the course
63
   * @return the created course
64
   */
65
  @Operation(summary = "Create a new course")
66
  @PreAuthorize("hasRole('ROLE_ADMIN') || hasRole('ROLE_INSTRUCTOR')")
67
  @PostMapping("/post")
68
  public InstructorCourseView postCourse(
69
      @Parameter(name = "courseName") @RequestParam String courseName,
70
      @Parameter(name = "term") @RequestParam String term,
71
      @Parameter(name = "school") @RequestParam String school) {
72
    // get current date right now and set status to pending
73
    CurrentUser currentUser = getCurrentUser();
74
    Course course =
75
        Course.builder()
76
            .courseName(courseName)
77
            .term(term)
78
            .school(school)
79
            .instructorEmail(currentUser.getUser().getEmail())
80
            .build();
81
    Course savedCourse = courseRepository.save(course);
82
83 1 1. postCourse : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::postCourse → KILLED
    return new InstructorCourseView(savedCourse);
84
  }
85
86
  /** Projection of Course entity with fields that are relevant for instructors and admins */
87
  public static record InstructorCourseView(
88
      Long id,
89
      String installationId,
90
      String orgName,
91
      String courseName,
92
      String term,
93
      String school,
94
      String instructorEmail,
95
      int numStudents,
96
      int numStaff) {
97
98
    // Creates view from Course entity
99
    public InstructorCourseView(Course c) {
100
      this(
101
          c.getId(),
102
          c.getInstallationId(),
103
          c.getOrgName(),
104
          c.getCourseName(),
105
          c.getTerm(),
106
          c.getSchool(),
107
          c.getInstructorEmail(),
108 1 1. <init> : negated conditional → KILLED
          c.getRosterStudents() != null ? c.getRosterStudents().size() : 0,
109 1 1. <init> : negated conditional → KILLED
          c.getCourseStaff() != null ? c.getCourseStaff().size() : 0);
110
    }
111
  }
112
113
  /**
114
   * This method returns a list of courses.
115
   *
116
   * @return a list of all courses for an instructor.
117
   */
118
  @Operation(summary = "List all courses for an instructor")
119
  @PreAuthorize("hasRole('ROLE_INSTRUCTOR')")
120
  @GetMapping("/allForInstructors")
121
  public Iterable<InstructorCourseView> allForInstructors() {
122
    CurrentUser currentUser = getCurrentUser();
123
    String instructorEmail = currentUser.getUser().getEmail();
124
    List<Course> courses = courseRepository.findByInstructorEmail(instructorEmail);
125
126
    List<InstructorCourseView> courseViews =
127
        courses.stream().map(InstructorCourseView::new).collect(Collectors.toList());
128 1 1. allForInstructors : replaced return value with Collections.emptyList for edu/ucsb/cs156/frontiers/controllers/CoursesController::allForInstructors → KILLED
    return courseViews;
129
  }
130
131
  /**
132
   * This method returns a list of courses.
133
   *
134
   * @return a list of all courses for an admin.
135
   */
136
  @Operation(summary = "List all courses for an admin")
137
  @PreAuthorize("hasRole('ROLE_ADMIN')")
138
  @GetMapping("/allForAdmins")
139
  public Iterable<InstructorCourseView> allForAdmins() {
140
    List<Course> courses = courseRepository.findAll();
141
142
    List<InstructorCourseView> courseViews =
143
        courses.stream().map(InstructorCourseView::new).collect(Collectors.toList());
144 1 1. allForAdmins : replaced return value with Collections.emptyList for edu/ucsb/cs156/frontiers/controllers/CoursesController::allForAdmins → KILLED
    return courseViews;
145
  }
146
147
  /**
148
   * This method returns single course by its id
149
   *
150
   * @return a course
151
   */
152
  @Operation(summary = "Get course by id")
153
  @PreAuthorize("@CourseSecurity.hasManagePermissions(#root, #id)")
154
  @GetMapping("/{id}")
155
  public InstructorCourseView getCourseById(@Parameter(name = "id") @PathVariable Long id) {
156
    Course course =
157
        courseRepository
158
            .findById(id)
159 1 1. lambda$getCourseById$0 : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::lambda$getCourseById$0 → KILLED
            .orElseThrow(() -> new EntityNotFoundException(Course.class, id));
160
    // Convert to InstructorCourseView
161
    InstructorCourseView courseView = new InstructorCourseView(course);
162 1 1. getCourseById : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::getCourseById → KILLED
    return courseView;
163
  }
164
165
  /**
166
   * This is the outgoing method, redirecting from Frontiers to GitHub to allow a Course to be
167
   * linked to a GitHub Organization. It redirects from Frontiers to the GitHub app installation
168
   * process, and will return with the {@link #addInstallation(Optional, String, String, Long)
169
   * addInstallation()} endpoint
170
   *
171
   * @param courseId id of the course to be linked to
172
   * @return dynamically loaded url to install Frontiers to a Github Organization, with the courseId
173
   *     marked as the state parameter, which GitHub will return.
174
   */
175
  @Operation(summary = "Authorize Frontiers to a Github Course")
176
  @PreAuthorize("@CourseSecurity.hasManagePermissions(#root, #courseId)")
177
  @GetMapping("/redirect")
178
  public ResponseEntity<Void> linkCourse(@Parameter Long courseId)
179
      throws JsonProcessingException, NoSuchAlgorithmException, InvalidKeySpecException {
180
    String newUrl = linkerService.getRedirectUrl();
181
    newUrl += "/installations/new?state=" + courseId;
182
    // found this convenient solution here:
183
    // https://stackoverflow.com/questions/29085295/spring-mvc-restcontroller-and-redirect
184 1 1. linkCourse : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::linkCourse → KILLED
    return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY)
185
        .header(HttpHeaders.LOCATION, newUrl)
186
        .build();
187
  }
188
189
  /**
190
   * @param installation_id id of the incoming GitHub Organization installation
191
   * @param setup_action whether the permissions are installed or updated. Required RequestParam but
192
   *     not used by the method.
193
   * @param code token to be exchanged with GitHub to ensure the request is legitimate and not
194
   *     spoofed.
195
   * @param state id of the Course to be linked with the GitHub installation.
196
   * @return ResponseEntity, returning /success if the course was successfully linked or /noperms if
197
   *     the user does not have the permission to install the application on GitHub. Alternately
198
   *     returns 403 Forbidden if the user is not the creator.
199
   */
200
  @Operation(summary = "Link a Course to a Github Organization by installing Github App")
201
  @PreAuthorize("hasRole('ROLE_ADMIN') || hasRole('ROLE_INSTRUCTOR')")
202
  @GetMapping("link")
203
  public ResponseEntity<Void> addInstallation(
204
      @Parameter(name = "installationId") @RequestParam Optional<String> installation_id,
205
      @Parameter(name = "setupAction") @RequestParam String setup_action,
206
      @Parameter(name = "code") @RequestParam String code,
207
      @Parameter(name = "state") @RequestParam Long state)
208
      throws NoSuchAlgorithmException, InvalidKeySpecException, JsonProcessingException {
209 1 1. addInstallation : negated conditional → KILLED
    if (installation_id.isEmpty()) {
210 1 1. addInstallation : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::addInstallation → KILLED
      return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY)
211
          .header(HttpHeaders.LOCATION, "/courses/nopermissions")
212
          .build();
213
    } else {
214
      Course course =
215
          courseRepository
216
              .findById(state)
217 1 1. lambda$addInstallation$1 : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::lambda$addInstallation$1 → KILLED
              .orElseThrow(() -> new EntityNotFoundException(Course.class, state));
218 1 1. addInstallation : negated conditional → KILLED
      if (!isCurrentUserAdmin()
219 1 1. addInstallation : negated conditional → KILLED
          && !course.getInstructorEmail().equals(getCurrentUser().getUser().getEmail())) {
220 1 1. addInstallation : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::addInstallation → KILLED
        return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
221
      } else {
222
        String orgName = linkerService.getOrgName(installation_id.get());
223 1 1. addInstallation : removed call to edu/ucsb/cs156/frontiers/entities/Course::setInstallationId → KILLED
        course.setInstallationId(installation_id.get());
224 1 1. addInstallation : removed call to edu/ucsb/cs156/frontiers/entities/Course::setOrgName → KILLED
        course.setOrgName(orgName);
225
        course
226
            .getRosterStudents()
227 1 1. addInstallation : removed call to java/util/List::forEach → KILLED
            .forEach(
228
                rs -> {
229 1 1. lambda$addInstallation$2 : removed call to edu/ucsb/cs156/frontiers/entities/RosterStudent::setOrgStatus → KILLED
                  rs.setOrgStatus(OrgStatus.JOINCOURSE);
230
                });
231
        course
232
            .getCourseStaff()
233 1 1. addInstallation : removed call to java/util/List::forEach → KILLED
            .forEach(
234
                cs -> {
235 1 1. lambda$addInstallation$3 : removed call to edu/ucsb/cs156/frontiers/entities/CourseStaff::setOrgStatus → KILLED
                  cs.setOrgStatus(OrgStatus.JOINCOURSE);
236
                });
237
        courseRepository.save(course);
238 1 1. addInstallation : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::addInstallation → KILLED
        return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY)
239
            .header(HttpHeaders.LOCATION, "/login/success")
240
            .build();
241
      }
242
    }
243
  }
244
245
  /**
246
   * This method handles the InvalidInstallationTypeException.
247
   *
248
   * @param e the exception
249
   * @return a map with the type and message of the exception
250
   */
251
  @ExceptionHandler({InvalidInstallationTypeException.class})
252
  @ResponseStatus(HttpStatus.BAD_REQUEST)
253
  public Object handleInvalidInstallationType(Throwable e) {
254 1 1. handleInvalidInstallationType : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::handleInvalidInstallationType → KILLED
    return Map.of(
255
        "type", e.getClass().getSimpleName(),
256
        "message", e.getMessage());
257
  }
258
259
  public record RosterStudentCoursesDTO(
260
      Long id,
261
      String installationId,
262
      String orgName,
263
      String courseName,
264
      String term,
265
      String school,
266
      OrgStatus studentStatus,
267
      Long rosterStudentId) {}
268
269
  /**
270
   * This method returns a list of courses that the current user is enrolled.
271
   *
272
   * @return a list of courses in the DTO form along with the student status in the organization.
273
   */
274
  @Operation(summary = "List all courses for the current student, including their org status")
275
  @PreAuthorize("hasRole('ROLE_USER')")
276
  @GetMapping("/list")
277
  public List<RosterStudentCoursesDTO> listCoursesForCurrentUser() {
278
    String email = getCurrentUser().getUser().getEmail();
279
    Iterable<RosterStudent> rosterStudentsIterable = rosterStudentRepository.findAllByEmail(email);
280
    List<RosterStudent> rosterStudents = new ArrayList<>();
281 1 1. listCoursesForCurrentUser : removed call to java/lang/Iterable::forEach → KILLED
    rosterStudentsIterable.forEach(rosterStudents::add);
282 1 1. listCoursesForCurrentUser : replaced return value with Collections.emptyList for edu/ucsb/cs156/frontiers/controllers/CoursesController::listCoursesForCurrentUser → KILLED
    return rosterStudents.stream()
283
        .map(
284
            rs -> {
285
              Course course = rs.getCourse();
286
              RosterStudentCoursesDTO rsDto =
287
                  new RosterStudentCoursesDTO(
288
                      course.getId(),
289
                      course.getInstallationId(),
290
                      course.getOrgName(),
291
                      course.getCourseName(),
292
                      course.getTerm(),
293
                      course.getSchool(),
294
                      rs.getOrgStatus(),
295
                      rs.getId());
296 1 1. lambda$listCoursesForCurrentUser$4 : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::lambda$listCoursesForCurrentUser$4 → KILLED
              return rsDto;
297
            })
298
        .collect(Collectors.toList());
299
  }
300
301
  public record StaffCoursesDTO(
302
      Long id,
303
      String installationId,
304
      String orgName,
305
      String courseName,
306
      String term,
307
      String school,
308
      OrgStatus studentStatus,
309
      Long staffId) {}
310
311
  /**
312
   * student see what courses they appear as staff in
313
   *
314
   * @param studentId the id of the student making request
315
   * @return a list of all courses student is staff in
316
   */
317
  @Operation(summary = "Student see what courses they appear as staff in")
318
  @PreAuthorize("hasRole('ROLE_USER')")
319
  @GetMapping("/staffCourses")
320
  public List<StaffCoursesDTO> staffCourses() {
321
    CurrentUser currentUser = getCurrentUser();
322
    User user = currentUser.getUser();
323
324
    String email = user.getEmail();
325
326
    List<CourseStaff> staffMembers = courseStaffRepository.findAllByEmail(email);
327 1 1. staffCourses : replaced return value with Collections.emptyList for edu/ucsb/cs156/frontiers/controllers/CoursesController::staffCourses → KILLED
    return staffMembers.stream()
328
        .map(
329
            s -> {
330
              Course course = s.getCourse();
331
              StaffCoursesDTO sDto =
332
                  new StaffCoursesDTO(
333
                      course.getId(),
334
                      course.getInstallationId(),
335
                      course.getOrgName(),
336
                      course.getCourseName(),
337
                      course.getTerm(),
338
                      course.getSchool(),
339
                      s.getOrgStatus(),
340
                      s.getId());
341 1 1. lambda$staffCourses$5 : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::lambda$staffCourses$5 → KILLED
              return sDto;
342
            })
343
        .collect(Collectors.toList());
344
  }
345
346
  @Operation(summary = "Update instructor email for a course (admin only)")
347
  @PreAuthorize("hasRole('ROLE_ADMIN')")
348
  @PutMapping("/updateInstructor")
349
  public InstructorCourseView updateInstructorEmail(
350
      @Parameter(name = "courseId") @RequestParam Long courseId,
351
      @Parameter(name = "instructorEmail") @RequestParam String instructorEmail) {
352
353
    Course course =
354
        courseRepository
355
            .findById(courseId)
356 1 1. lambda$updateInstructorEmail$6 : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::lambda$updateInstructorEmail$6 → KILLED
            .orElseThrow(() -> new EntityNotFoundException(Course.class, courseId));
357
358
    // Validate that the email exists in either instructor or admin table
359
    boolean isInstructor = instructorRepository.existsByEmail(instructorEmail);
360
    boolean isAdmin = adminRepository.existsByEmail(instructorEmail);
361
362 2 1. updateInstructorEmail : negated conditional → KILLED
2. updateInstructorEmail : negated conditional → KILLED
    if (!isInstructor && !isAdmin) {
363
      throw new IllegalArgumentException("Email must belong to either an instructor or admin");
364
    }
365
366 1 1. updateInstructorEmail : removed call to edu/ucsb/cs156/frontiers/entities/Course::setInstructorEmail → KILLED
    course.setInstructorEmail(instructorEmail);
367
    Course savedCourse = courseRepository.save(course);
368
369 1 1. updateInstructorEmail : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::updateInstructorEmail → KILLED
    return new InstructorCourseView(savedCourse);
370
  }
371
372
  @Operation(summary = "Delete a course")
373
  @PreAuthorize("hasRole('ROLE_ADMIN')")
374
  @DeleteMapping("")
375
  public Object deleteCourse(@RequestParam Long courseId)
376
      throws NoSuchAlgorithmException, InvalidKeySpecException {
377
    Course course =
378
        courseRepository
379
            .findById(courseId)
380 1 1. lambda$deleteCourse$7 : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::lambda$deleteCourse$7 → KILLED
            .orElseThrow(() -> new EntityNotFoundException(Course.class, courseId));
381
382
    // Check if course has roster students or staff
383 2 1. deleteCourse : negated conditional → KILLED
2. deleteCourse : negated conditional → KILLED
    if (!course.getRosterStudents().isEmpty() || !course.getCourseStaff().isEmpty()) {
384
      throw new IllegalArgumentException("Cannot delete course with students or staff");
385
    }
386
387 1 1. deleteCourse : removed call to edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::unenrollOrganization → KILLED
    linkerService.unenrollOrganization(course);
388 1 1. deleteCourse : removed call to edu/ucsb/cs156/frontiers/repositories/CourseRepository::delete → KILLED
    courseRepository.delete(course);
389 1 1. deleteCourse : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::deleteCourse → KILLED
    return genericMessage("Course with id %s deleted".formatted(course.getId()));
390
  }
391
392
  /**
393
   * This method updates an existing course.
394
   *
395
   * @param courseId the id of the course to update
396
   * @param courseName the new name of the course
397
   * @param term the new term of the course
398
   * @param school the new school of the course
399
   * @return the updated course
400
   */
401
  @Operation(summary = "Update an existing course")
402
  @PreAuthorize("@CourseSecurity.hasManagePermissions(#root, #courseId)")
403
  @PutMapping("")
404
  public InstructorCourseView updateCourse(
405
      @Parameter(name = "courseId") @RequestParam Long courseId,
406
      @Parameter(name = "courseName") @RequestParam String courseName,
407
      @Parameter(name = "term") @RequestParam String term,
408
      @Parameter(name = "school") @RequestParam String school) {
409
    Course course =
410
        courseRepository
411
            .findById(courseId)
412 1 1. lambda$updateCourse$8 : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::lambda$updateCourse$8 → KILLED
            .orElseThrow(() -> new EntityNotFoundException(Course.class, courseId));
413
414 1 1. updateCourse : removed call to edu/ucsb/cs156/frontiers/entities/Course::setCourseName → KILLED
    course.setCourseName(courseName);
415 1 1. updateCourse : removed call to edu/ucsb/cs156/frontiers/entities/Course::setTerm → KILLED
    course.setTerm(term);
416 1 1. updateCourse : removed call to edu/ucsb/cs156/frontiers/entities/Course::setSchool → KILLED
    course.setSchool(school);
417
418
    Course savedCourse = courseRepository.save(course);
419
420 1 1. updateCourse : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::updateCourse → KILLED
    return new InstructorCourseView(savedCourse);
421
  }
422
}

Mutations

83

1.1
Location : postCourse
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testPostCourse_byInstructor()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::postCourse → KILLED

108

1.1
Location : <init>
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testInstructorCourseView_countsStudentsAndStaff()]
negated conditional → KILLED

109

1.1
Location : <init>
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testInstructorCourseView_countsStudentsAndStaff()]
negated conditional → KILLED

128

1.1
Location : allForInstructors
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testAllCourses_ROLE_INSTRUCTOR()]
replaced return value with Collections.emptyList for edu/ucsb/cs156/frontiers/controllers/CoursesController::allForInstructors → KILLED

144

1.1
Location : allForAdmins
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testAllCourses_ROLE_ADMIN()]
replaced return value with Collections.emptyList for edu/ucsb/cs156/frontiers/controllers/CoursesController::allForAdmins → KILLED

159

1.1
Location : lambda$getCourseById$0
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testGetCourseById_courseDoesNotExist()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::lambda$getCourseById$0 → KILLED

162

1.1
Location : getCourseById
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testGetCourseById()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::getCourseById → KILLED

184

1.1
Location : linkCourse
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testRedirect()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::linkCourse → KILLED

209

1.1
Location : addInstallation
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testNoPerms()]
negated conditional → KILLED

210

1.1
Location : addInstallation
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testNoPerms()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::addInstallation → KILLED

217

1.1
Location : lambda$addInstallation$1
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testCourseLinkNotFound()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::lambda$addInstallation$1 → KILLED

218

1.1
Location : addInstallation
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testNotCreator()]
negated conditional → KILLED

219

1.1
Location : addInstallation
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testNotCreator()]
negated conditional → KILLED

220

1.1
Location : addInstallation
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testNotCreator()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::addInstallation → KILLED

223

1.1
Location : addInstallation
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testCourseLinkSuccessWhenAdminNotCreator()]
removed call to edu/ucsb/cs156/frontiers/entities/Course::setInstallationId → KILLED

224

1.1
Location : addInstallation
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testCourseLinkSuccessWhenAdminNotCreator()]
removed call to edu/ucsb/cs156/frontiers/entities/Course::setOrgName → KILLED

227

1.1
Location : addInstallation
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testLinkCourseSuccessfully()]
removed call to java/util/List::forEach → KILLED

229

1.1
Location : lambda$addInstallation$2
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testLinkCourseSuccessfully()]
removed call to edu/ucsb/cs156/frontiers/entities/RosterStudent::setOrgStatus → KILLED

233

1.1
Location : addInstallation
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testLinkCourseSuccessfully()]
removed call to java/util/List::forEach → KILLED

235

1.1
Location : lambda$addInstallation$3
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testLinkCourseSuccessfully()]
removed call to edu/ucsb/cs156/frontiers/entities/CourseStaff::setOrgStatus → KILLED

238

1.1
Location : addInstallation
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testCourseLinkSuccessWhenAdminNotCreator()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::addInstallation → KILLED

254

1.1
Location : handleInvalidInstallationType
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testNotOrganization()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::handleInvalidInstallationType → KILLED

281

1.1
Location : listCoursesForCurrentUser
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testListCoursesForCurrentUser()]
removed call to java/lang/Iterable::forEach → KILLED

282

1.1
Location : listCoursesForCurrentUser
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testListCoursesForCurrentUser()]
replaced return value with Collections.emptyList for edu/ucsb/cs156/frontiers/controllers/CoursesController::listCoursesForCurrentUser → KILLED

296

1.1
Location : lambda$listCoursesForCurrentUser$4
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testListCoursesForCurrentUser()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::lambda$listCoursesForCurrentUser$4 → KILLED

327

1.1
Location : staffCourses
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testStudenIsStaffInCourse()]
replaced return value with Collections.emptyList for edu/ucsb/cs156/frontiers/controllers/CoursesController::staffCourses → KILLED

341

1.1
Location : lambda$staffCourses$5
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testStudenIsStaffInCourse()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::lambda$staffCourses$5 → KILLED

356

1.1
Location : lambda$updateInstructorEmail$6
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testUpdateInstructorEmail_courseDoesNotExist()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::lambda$updateInstructorEmail$6 → KILLED

362

1.1
Location : updateInstructorEmail
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testUpdateInstructorEmail_emailNotFound()]
negated conditional → KILLED

2.2
Location : updateInstructorEmail
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testUpdateInstructorEmail_emailNotFound()]
negated conditional → KILLED

366

1.1
Location : updateInstructorEmail
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testUpdateInstructorEmail_byAdmin_email_is_admin()]
removed call to edu/ucsb/cs156/frontiers/entities/Course::setInstructorEmail → KILLED

369

1.1
Location : updateInstructorEmail
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:testUpdateInstructorEmail_byAdmin_email_is_admin()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::updateInstructorEmail → KILLED

380

1.1
Location : lambda$deleteCourse$7
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:delete_not_found_returns_not_found()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::lambda$deleteCourse$7 → KILLED

383

1.1
Location : deleteCourse
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:delete_success_returns_ok()]
negated conditional → KILLED

2.2
Location : deleteCourse
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:delete_success_returns_ok()]
negated conditional → KILLED

387

1.1
Location : deleteCourse
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:delete_success_returns_ok()]
removed call to edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::unenrollOrganization → KILLED

388

1.1
Location : deleteCourse
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:delete_success_returns_ok()]
removed call to edu/ucsb/cs156/frontiers/repositories/CourseRepository::delete → KILLED

389

1.1
Location : deleteCourse
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:delete_success_returns_ok()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::deleteCourse → KILLED

412

1.1
Location : lambda$updateCourse$8
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:update_course_not_found_returns_not_found()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::lambda$updateCourse$8 → KILLED

414

1.1
Location : updateCourse
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:update_course_success_returns_ok()]
removed call to edu/ucsb/cs156/frontiers/entities/Course::setCourseName → KILLED

415

1.1
Location : updateCourse
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:update_course_success_returns_ok()]
removed call to edu/ucsb/cs156/frontiers/entities/Course::setTerm → KILLED

416

1.1
Location : updateCourse
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:update_course_success_returns_ok()]
removed call to edu/ucsb/cs156/frontiers/entities/Course::setSchool → KILLED

420

1.1
Location : updateCourse
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:updateCourse_success_admin()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::updateCourse → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0