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

Mutations

90

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

115

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

116

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

135

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

151

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

166

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

169

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

189

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

193

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

195

1.1
Location : getCourseCanvasInfo
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:getCanvasInfo_obscuresCorrectlyForFourCharacters()]
changed conditional boundary → KILLED

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

198

1.1
Location : getCourseCanvasInfo
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:getCanvasInfo_obscuresCorrectlyForFourCharacters()]
Replaced integer subtraction with addition → KILLED

199

1.1
Location : getCourseCanvasInfo
Killed by : edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CoursesControllerTests]/[method:getCanvasInfo_obscuresCorrectlyForFourCharacters()]
Replaced integer subtraction with addition → KILLED

202

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

204

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

205

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

227

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

252

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

253

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

260

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:testCourseLinkNotFound()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CoursesController::lambda$addInstallation$2 → KILLED

261

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

262

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

263

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

266

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

267

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

270

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

272

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/RosterStudent::setOrgStatus → KILLED

276

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

278

1.1
Location : lambda$addInstallation$4
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

281

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

297

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

324

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

325

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

339

1.1
Location : lambda$listCoursesForCurrentUser$5
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$5 → KILLED

370

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

384

1.1
Location : lambda$staffCourses$6
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$6 → KILLED

401

1.1
Location : lambda$updateInstructorEmail$7
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$7 → KILLED

407

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

411

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

414

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

425

1.1
Location : lambda$deleteCourse$8
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$8 → KILLED

428

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

432

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

433

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

434

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

457

1.1
Location : lambda$updateCourse$9
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$9 → KILLED

459

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

460

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

461

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

465

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

489

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

491

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

492

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

493

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

494

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

497

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

498

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

499

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

500

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

505

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

514

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

515

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

Active mutators

Tests examined


Report generated by PIT 1.17.0