CoursesCSVController.java

1
package edu.ucsb.cs156.courses.controllers;
2
3
import com.opencsv.bean.StatefulBeanToCsvBuilder;
4
import com.opencsv.exceptions.CsvDataTypeMismatchException;
5
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
6
import edu.ucsb.cs156.courses.collections.ConvertedSectionCollection;
7
import edu.ucsb.cs156.courses.documents.ConvertedSection;
8
import edu.ucsb.cs156.courses.models.SectionCSVLine;
9
import io.swagger.v3.oas.annotations.Operation;
10
import io.swagger.v3.oas.annotations.Parameter;
11
import io.swagger.v3.oas.annotations.media.Content;
12
import io.swagger.v3.oas.annotations.media.Schema;
13
import io.swagger.v3.oas.annotations.responses.ApiResponse;
14
import io.swagger.v3.oas.annotations.tags.Tag;
15
import java.io.IOException;
16
import java.io.OutputStreamWriter;
17
import java.io.Writer;
18
import java.nio.charset.StandardCharsets;
19
import java.util.List;
20
import java.util.stream.Collectors;
21
import lombok.extern.slf4j.Slf4j;
22
import org.springframework.beans.factory.annotation.Autowired;
23
import org.springframework.data.util.Streamable;
24
import org.springframework.http.HttpHeaders;
25
import org.springframework.http.MediaType;
26
import org.springframework.http.ResponseEntity;
27
import org.springframework.web.bind.annotation.GetMapping;
28
import org.springframework.web.bind.annotation.RequestMapping;
29
import org.springframework.web.bind.annotation.RequestParam;
30
import org.springframework.web.bind.annotation.RestController;
31
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
32
33
@Slf4j
34
@Tag(name = "API for course data as CSV downloads")
35
@RequestMapping("/api/courses/csv")
36
@RestController
37
public class CoursesCSVController extends ApiController {
38
39
  @Autowired ConvertedSectionCollection convertedSectionCollection;
40
41
  @Operation(
42
      summary = "Download Course List as CSV File",
43
      description = "Returns a CSV file as a response",
44
      responses = {
45
        @ApiResponse(
46
            responseCode = "200",
47
            description = "CSV file",
48
            content =
49
                @Content(
50
                    mediaType = "text/csv",
51
                    schema = @Schema(type = "string", format = "binary"))),
52
        @ApiResponse(responseCode = "500", description = "Internal Server Error")
53
      })
54
  @GetMapping(value = "/quarter", produces = "text/csv")
55
  public ResponseEntity<StreamingResponseBody> csvForCourses(
56
      @Parameter(name = "yyyyq", description = "quarter in yyyyq format", example = "20252")
57
          @RequestParam
58
          String yyyyq,
59
      @Parameter(
60
              name = "testException",
61
              description = "test exception (e.g. CsvDataTypeMismatchException)",
62
              example = "")
63
          @RequestParam(required = false, defaultValue = "")
64
          String testException)
65
      throws Exception, IOException {
66
    StreamingResponseBody stream =
67
        (outputStream) -> {
68
          Iterable<ConvertedSection> iterable = convertedSectionCollection.findByQuarter(yyyyq);
69
70
          List<SectionCSVLine> list =
71
              Streamable.of(iterable).toList().stream()
72
                  .map(
73
                      section -> {
74 1 1. lambda$csvForCourses$0 : replaced return value with null for edu/ucsb/cs156/courses/controllers/CoursesCSVController::lambda$csvForCourses$0 → KILLED
                        return SectionCSVLine.toSectionCSVLine(section);
75
                      })
76
                  .collect(Collectors.toList());
77
78
          try (Writer writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) {
79
            try {
80 1 1. lambda$csvForCourses$1 : negated conditional → KILLED
              if (testException.equals("CsvDataTypeMismatchException")) {
81
                throw new CsvDataTypeMismatchException("test exception");
82
              }
83 1 1. lambda$csvForCourses$1 : removed call to com/opencsv/bean/StatefulBeanToCsv::write → KILLED
              new StatefulBeanToCsvBuilder<SectionCSVLine>(writer).build().write(list);
84
            } catch (CsvDataTypeMismatchException | CsvRequiredFieldEmptyException e) {
85
              log.error("Error writing CSV file", e);
86
              throw new IOException("Error writing CSV file: " + e.getMessage());
87
            }
88
          }
89
        };
90
91 1 1. csvForCourses : replaced return value with null for edu/ucsb/cs156/courses/controllers/CoursesCSVController::csvForCourses → KILLED
    return ResponseEntity.ok()
92
        .contentType(MediaType.parseMediaType("text/csv; charset=UTF-8"))
93
        .header(
94
            HttpHeaders.CONTENT_DISPOSITION,
95
            String.format("attachment;filename=courses_%s.csv", yyyyq))
96
        .header(HttpHeaders.CONTENT_TYPE, "text/csv; charset=UTF-8")
97
        .header(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION)
98
        .body(stream);
99
  }
100
}

Mutations

74

1.1
Location : lambda$csvForCourses$0
Killed by : edu.ucsb.cs156.courses.controllers.CoursesCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.courses.controllers.CoursesCSVControllerTests]/[method:testCsvForQuarter_success()]
replaced return value with null for edu/ucsb/cs156/courses/controllers/CoursesCSVController::lambda$csvForCourses$0 → KILLED

80

1.1
Location : lambda$csvForCourses$1
Killed by : edu.ucsb.cs156.courses.controllers.CoursesCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.courses.controllers.CoursesCSVControllerTests]/[method:testCsvForQuarter_success()]
negated conditional → KILLED

83

1.1
Location : lambda$csvForCourses$1
Killed by : edu.ucsb.cs156.courses.controllers.CoursesCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.courses.controllers.CoursesCSVControllerTests]/[method:testCsvForQuarter_success()]
removed call to com/opencsv/bean/StatefulBeanToCsv::write → KILLED

91

1.1
Location : csvForCourses
Killed by : edu.ucsb.cs156.courses.controllers.CoursesCSVControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.courses.controllers.CoursesCSVControllerTests]/[method:testCsvForQuarter_success()]
replaced return value with null for edu/ucsb/cs156/courses/controllers/CoursesCSVController::csvForCourses → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0