diff --git a/jplag.cli/src/main/java/de/jplag/CLI.java b/jplag.cli/src/main/java/de/jplag/CLI.java index 3646b90f7..87606d657 100644 --- a/jplag.cli/src/main/java/de/jplag/CLI.java +++ b/jplag.cli/src/main/java/de/jplag/CLI.java @@ -27,8 +27,7 @@ import de.jplag.options.LanguageOption; import de.jplag.options.SimilarityMetric; import de.jplag.options.Verbosity; -import de.jplag.reporting.JsonReport; -import de.jplag.reporting.Report; +import de.jplag.reporting.reportobject.ReportObjectFactory; import de.jplag.strategy.ComparisonMode; /** @@ -65,9 +64,8 @@ public static void main(String[] args) { JPlag program = new JPlag(options); logger.info("JPlag initialized"); JPlagResult result = program.run(); - Report report = new JsonReport(); - report.saveReport(result, arguments.getString(RESULT_FOLDER.flagWithoutDash())); - finalizeLogger(); + ReportObjectFactory.createAndSaveReport(result, arguments.getString(RESULT_FOLDER.flagWithoutDash())); + } catch (ExitException exception) { logger.error(exception.getMessage(), exception); finalizeLogger(); diff --git a/jplag/src/main/java/de/jplag/JPlagResult.java b/jplag/src/main/java/de/jplag/JPlagResult.java index 59f8b5ac7..51d2088bd 100644 --- a/jplag/src/main/java/de/jplag/JPlagResult.java +++ b/jplag/src/main/java/de/jplag/JPlagResult.java @@ -136,9 +136,15 @@ private int[] calculateSimilarityDistribution(List comparisons) private int[] calculateDistributionFor(List comparisons, Function similarityExtractor) { int[] similarityDistribution = new int[SIMILARITY_DISTRIBUTION_SIZE]; - comparisons.stream().map(similarityExtractor).map(percent -> percent / SIMILARITY_DISTRIBUTION_SIZE).map(Float::intValue) - .map(index -> index == SIMILARITY_DISTRIBUTION_SIZE ? SIMILARITY_DISTRIBUTION_SIZE - 1 : index) - .forEach(index -> similarityDistribution[SIMILARITY_DISTRIBUTION_SIZE - 1 - index]++); + int similarityDistributionBucketSize = 100 / SIMILARITY_DISTRIBUTION_SIZE; + for (JPlagComparison comparison : comparisons) { + float similarity = similarityExtractor.apply(comparison); // extract similarity in percent: 0f <= similarity <= 100f + int index = (int) (similarity / similarityDistributionBucketSize); // divide similarity by bucket size to find index of correct bucket. + index = Math.min(index, SIMILARITY_DISTRIBUTION_SIZE - 1);// index is out of bounds when similarity is 100%. decrease by one to count + // towards the highest value bucket + similarityDistribution[SIMILARITY_DISTRIBUTION_SIZE - 1 - index]++; // count comparison towards its determined bucket. bucket order is + // reversed, so that the highest value bucket has the lowest index + } return similarityDistribution; } } diff --git a/jplag/src/main/java/de/jplag/reporting/JsonReport.java b/jplag/src/main/java/de/jplag/reporting/JsonReport.java deleted file mode 100644 index f2477cd51..000000000 --- a/jplag/src/main/java/de/jplag/reporting/JsonReport.java +++ /dev/null @@ -1,36 +0,0 @@ -package de.jplag.reporting; - -import java.io.File; -import java.util.List; - -import de.jplag.JPlagResult; -import de.jplag.reporting.jsonfactory.JsonFactory; -import de.jplag.reporting.reportobject.ReportObjectFactory; -import de.jplag.reporting.reportobject.model.JPlagReport; - -// ReportImplementation -> JsonReport - -/** - * A report generator which reports the JPlagResult in Json format. - */ -public class JsonReport implements Report { - - @Override - public List getReportStrings(JPlagResult result) { - JPlagReport report = ReportObjectFactory.getReportObject(result); - return JsonFactory.getJsonStrings(report); - } - - @Override - public boolean saveReport(JPlagResult result, String path) { - JPlagReport report = ReportObjectFactory.getReportObject(result); - File directory = new File(path); - if (!directory.exists()) { - if (!directory.mkdirs()) { - logger.error("Failed to create dir."); - } - } - return JsonFactory.saveJsonFiles(report, path); - } - -} diff --git a/jplag/src/main/java/de/jplag/reporting/Report.java b/jplag/src/main/java/de/jplag/reporting/Report.java deleted file mode 100644 index 6fa60a0c9..000000000 --- a/jplag/src/main/java/de/jplag/reporting/Report.java +++ /dev/null @@ -1,34 +0,0 @@ -package de.jplag.reporting; - -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import de.jplag.JPlagResult; - -// ReportStrategy -> Report - -/** - * Strategy interface for reporting. A report generator should implement this interface. - */ -public interface Report { - - Logger logger = LoggerFactory.getLogger(Report.class); - - /** - * This function returns a list containing the report objects as simple strings. The first element is the string of the - * overview object. Each following element is a string of a comparison report object. - * @param result The result of a JPlag comparison - * @return A list containing report objects to string. First element is Overview. Other elements are comparisons. - */ - List getReportStrings(JPlagResult result); - - /** - * Creates and saves JPlag report files to the disk. - * @param result The result of a JPlag comparison. - * @param path Path to the directory where the report should be saved. - * @return True if the process is successful, otherwise false. - */ - boolean saveReport(JPlagResult result, String path); -} diff --git a/jplag/src/main/java/de/jplag/reporting/jsonfactory/FileWriter.java b/jplag/src/main/java/de/jplag/reporting/jsonfactory/FileWriter.java new file mode 100644 index 000000000..dd4086516 --- /dev/null +++ b/jplag/src/main/java/de/jplag/reporting/jsonfactory/FileWriter.java @@ -0,0 +1,29 @@ +package de.jplag.reporting.jsonfactory; + +import java.io.IOException; +import java.nio.file.Path; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public class FileWriter { + private static final Logger logger = LoggerFactory.getLogger(FileWriter.class); + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + /** + * Saves the provided object to the provided path under the provided name + * @param fileToSave The object to save + * @param folderPath The path to save the object to + * @param fileName The name to save the object under + */ + public void saveAsJSON(Object fileToSave, String folderPath, String fileName) { + try { + objectMapper.writeValue(Path.of(folderPath, fileName).toFile(), fileToSave); + } catch (IOException e) { + logger.error("Failed to save json file " + fileName + ": " + e.getMessage(), e); + } + } +} diff --git a/jplag/src/main/java/de/jplag/reporting/jsonfactory/JsonFactory.java b/jplag/src/main/java/de/jplag/reporting/jsonfactory/JsonFactory.java deleted file mode 100644 index e9c4ca2a8..000000000 --- a/jplag/src/main/java/de/jplag/reporting/jsonfactory/JsonFactory.java +++ /dev/null @@ -1,62 +0,0 @@ -package de.jplag.reporting.jsonfactory; - -import java.io.IOException; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -import de.jplag.reporting.reportobject.model.ComparisonReport; -import de.jplag.reporting.reportobject.model.JPlagReport; - -/** - * Factory class, responsible for creating Json strings and writing them to files. - */ -public class JsonFactory { - - private static final Logger logger = LoggerFactory.getLogger(JsonFactory.class); - - private static final ObjectMapper mapper = new ObjectMapper(); - - /** - * Uses Jackson to create Json Strings from JPlagReport object. - * @return A list, first element is Json String of Overview object. The rest elements are Json Strings of Comparison - * objects. - */ - public static List getJsonStrings(JPlagReport jPlagReport) { - List jsonReports = new ArrayList<>(); - try { - jsonReports.add(mapper.writeValueAsString(jPlagReport.overviewReport())); - for (ComparisonReport comparisonReport : jPlagReport.comparisons()) { - jsonReports.add(mapper.writeValueAsString(comparisonReport)); - } - } catch (JsonProcessingException e) { - logger.error("Error converting object to json " + e.getMessage(), e); - } - return jsonReports; - } - - /** - * Creates Json Files for the given JPlagReport and saves them in the given folder. - * @return A boolean, representing whether the process was successful. - */ - public static boolean saveJsonFiles(JPlagReport jPlagReport, String folderPath) { - try { - ObjectMapper mapper = new ObjectMapper(); - mapper.writeValue(Path.of(folderPath, "overview.json").toFile(), jPlagReport.overviewReport()); - for (ComparisonReport report : jPlagReport.comparisons()) { - String name = report.firstSubmissionId().concat("-").concat(report.secondSubmissionId()).concat(".json"); - mapper.writeValue(Path.of(folderPath, name).toFile(), report); - } - } catch (IOException e) { - logger.error("Failed to save json files: " + e.getMessage(), e); - return false; - } - return true; - } -} diff --git a/jplag/src/main/java/de/jplag/reporting/reportobject/ReportObjectFactory.java b/jplag/src/main/java/de/jplag/reporting/reportobject/ReportObjectFactory.java index 5424bba0b..01e486cb2 100644 --- a/jplag/src/main/java/de/jplag/reporting/reportobject/ReportObjectFactory.java +++ b/jplag/src/main/java/de/jplag/reporting/reportobject/ReportObjectFactory.java @@ -1,47 +1,63 @@ package de.jplag.reporting.reportobject; -import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashSet; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import de.jplag.*; +import de.jplag.JPlagComparison; +import de.jplag.JPlagResult; +import de.jplag.Submission; +import de.jplag.reporting.jsonfactory.FileWriter; import de.jplag.reporting.reportobject.mapper.ClusteringResultMapper; +import de.jplag.reporting.reportobject.mapper.ComparisonReportMapper; import de.jplag.reporting.reportobject.mapper.MetricMapper; -import de.jplag.reporting.reportobject.model.*; -import de.jplag.reporting.reportobject.model.Match; +import de.jplag.reporting.reportobject.model.Metric; +import de.jplag.reporting.reportobject.model.OverviewReport; /** * Factory class, responsible for converting a JPlagResult object to Overview and Comparison DTO classes. */ public class ReportObjectFactory { - private static final Logger logger = LoggerFactory.getLogger(ReportObjectFactory.class); + private static final ClusteringResultMapper clusteringResultMapper = new ClusteringResultMapper(); private static final MetricMapper metricMapper = new MetricMapper(); + private static final ComparisonReportMapper comparisonReportMapper = new ComparisonReportMapper(); + private static final FileWriter fileWriter = new FileWriter(); + public static final String OVERVIEW_FILE_NAME = "overview.json"; + public static final String SUBMISSIONS_FOLDER = "submissions"; /** - * Converts a JPlagResult to a JPlagReport. - * @return JPlagReport for the given JPlagResult. + * @param result The JPlagResult to be converted into a report. + * @param path The Path to save the report to */ - public static JPlagReport getReportObject(JPlagResult result) { - OverviewReport overviewReport = generateOverviewReport(result); - List comparisons = generateComparisonReports(result); - return new JPlagReport(overviewReport, comparisons); + public static void createAndSaveReport(JPlagResult result, String path) { + createDirectory(path); + writeOverview(result, path); + copySubmissionFilesToReport(path, result); + comparisonReportMapper.writeComparisonReports(result, path); } - /** - * Generates an Overview DTO of a JPlagResult. - */ - private static OverviewReport generateOverviewReport(JPlagResult result) { + private static File createDirectory(String path, String name) { + File directory = new File(path.concat("/").concat(name)); + if (!directory.exists() && !directory.mkdirs()) { + logger.error("Failed to create dir."); + } + return directory; + } + + private static void createDirectory(String path) { + createDirectory(path, ""); + } + + private static void writeOverview(JPlagResult result, String path) { List comparisons = getComparisons(result); OverviewReport overviewReport = new OverviewReport(); @@ -66,24 +82,31 @@ private static OverviewReport generateOverviewReport(JPlagResult result) { overviewReport.setMetrics(getMetrics(result)); overviewReport.setClusters(clusteringResultMapper.map(result)); - return overviewReport; + fileWriter.saveAsJSON(overviewReport, path, OVERVIEW_FILE_NAME); + } - /** - * Generates detailed ComparisonReport DTO for each comparison in a JPlagResult. - * @return A list with ComparisonReport DTOs. - */ - private static List generateComparisonReports(JPlagResult result) { - List comparisons = new ArrayList<>(); - getComparisons(result).forEach(comparison -> comparisons.add( // - new ComparisonReport(comparison.getFirstSubmission().getName(), // - comparison.getSecondSubmission().getName(), // - comparison.similarity(), // - getFilesForSubmission(comparison.getFirstSubmission()), // - getFilesForSubmission(comparison.getSecondSubmission()), // - convertMatchesToReportMatches(result, comparison, comparison.getMatches()) // - ))); - return comparisons; + private static void copySubmissionFilesToReport(String path, JPlagResult result) { + List comparisons = result.getComparisons(result.getOptions().getMaximumNumberOfComparisons()); + var submissions = getSubmissions(comparisons); + var submissionsPath = createDirectory(path, SUBMISSIONS_FOLDER); + for (var submission : submissions) { + File directory = createDirectory(submissionsPath.getPath(), submission.getName()); + for (var file : submission.getFiles()) { + try { + Files.copy(file.toPath(), (new File(directory, file.getName())).toPath(), StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + logger.error("Could not save submission file " + file, e); + } + } + } + } + + private static Set getSubmissions(List comparisons) { + var submissions = comparisons.stream().map(JPlagComparison::getFirstSubmission).collect(Collectors.toSet()); + Set secondSubmissions = comparisons.stream().map(JPlagComparison::getSecondSubmission).collect(Collectors.toSet()); + submissions.addAll(secondSubmissions); + return submissions; } private static List getComparisons(JPlagResult result) { @@ -91,11 +114,6 @@ private static List getComparisons(JPlagResult result) { return result.getComparisons(numberOfComparisons); } - private static List convertMatchesToReportMatches(JPlagResult result, JPlagComparison comparison, List matches) { - return matches.stream().map(match -> convertMatchToReportMatch(comparison, match, !result.getOptions().getLanguage().supportsColumns())) - .toList(); - } - /** * Gets the names of all submissions. * @return A list containing all submission names. @@ -129,51 +147,6 @@ private static List getMetrics(JPlagResult result) { return List.of(metricMapper.getAverageMetric(result), metricMapper.getMaxMetric(result)); } - /** - * Converts files of a submission to FilesOFSubmission DTO. - * @return A list containing FilesOfSubmission DTOs. - */ - private static List getFilesForSubmission(Submission submission) { - return submission.getFiles().stream().map(file -> new FilesOfSubmission(file.getName(), readFileLines(file))).toList(); - } - - /** - * Converts a JPlag Match object to a Match DTO. - * @param comparison The comparison from which the match originates. - * @param match The match to be converted. - * @param usesIndex Indicates whether the language uses indexes. - * @return A Match DTO. - */ - private static Match convertMatchToReportMatch(JPlagComparison comparison, de.jplag.Match match, boolean usesIndex) { - TokenList tokensFirst = comparison.getFirstSubmission().getTokenList(); - TokenList tokensSecond = comparison.getSecondSubmission().getTokenList(); - Token startTokenFirst = tokensFirst.getToken(match.startOfFirst()); - Token endTokenFirst = tokensFirst.getToken(match.startOfFirst() + match.length() - 1); - Token startTokenSecond = tokensSecond.getToken(match.startOfSecond()); - Token endTokenSecond = tokensSecond.getToken(match.startOfSecond() + match.length() - 1); - - int startFirst = usesIndex ? startTokenFirst.getIndex() : startTokenFirst.getLine(); - int endFirst = usesIndex ? endTokenFirst.getIndex() : endTokenFirst.getLine(); - int startSecond = usesIndex ? startTokenSecond.getIndex() : startTokenSecond.getLine(); - int endSecond = usesIndex ? endTokenSecond.getIndex() : endTokenSecond.getLine(); - int tokens = match.length(); - - return new Match(startTokenFirst.getFile(), startTokenSecond.getFile(), startFirst, endFirst, startSecond, endSecond, tokens); - } - - private static List readFileLines(File file) { - List lines = new ArrayList<>(); - try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) { - String line; - while ((line = bufferedReader.readLine()) != null) { - lines.add(line); - } - } catch (IOException exception) { - logger.error("Could not read file: " + exception.getMessage(), exception); - } - return lines; - } - private static String getDate() { SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yy"); Date date = new Date(); diff --git a/jplag/src/main/java/de/jplag/reporting/reportobject/mapper/ComparisonReportMapper.java b/jplag/src/main/java/de/jplag/reporting/reportobject/mapper/ComparisonReportMapper.java new file mode 100644 index 000000000..5785bf444 --- /dev/null +++ b/jplag/src/main/java/de/jplag/reporting/reportobject/mapper/ComparisonReportMapper.java @@ -0,0 +1,56 @@ +package de.jplag.reporting.reportobject.mapper; + +import java.util.List; + +import de.jplag.*; +import de.jplag.reporting.jsonfactory.FileWriter; +import de.jplag.reporting.reportobject.model.ComparisonReport; +import de.jplag.reporting.reportobject.model.Match; + +public class ComparisonReportMapper { + + private static final FileWriter FILE_WRITER = new FileWriter(); + + /** + * Generates detailed ComparisonReport DTO for each comparison in a JPlagResult. + * @param jPlagResult The JPlagResult to generate the comparison reports from. contains information about a comparison + * between two submission. The JPlagResult is used to extract the information on matches between two submissions. + */ + public void writeComparisonReports(JPlagResult jPlagResult, String path) { + int numberOfComparisons = jPlagResult.getOptions().getMaximumNumberOfComparisons(); + List comparisons = jPlagResult.getComparisons(numberOfComparisons); + writeComparisons(jPlagResult, path, comparisons); + } + + private void writeComparisons(JPlagResult jPlagResult, String path, List comparisons) { + for (JPlagComparison comparison : comparisons) { + var comparisonReport = new ComparisonReport(comparison.getFirstSubmission().getName(), comparison.getSecondSubmission().getName(), + comparison.similarity(), convertMatchesToReportMatches(jPlagResult, comparison)); + String fileName = comparisonReport.firstSubmissionId().concat("-").concat(comparisonReport.secondSubmissionId()).concat(".json"); + FILE_WRITER.saveAsJSON(comparisonReport, path, fileName); + } + } + + private List convertMatchesToReportMatches(JPlagResult result, JPlagComparison comparison) { + return comparison.getMatches().stream() + .map(match -> convertMatchToReportMatch(comparison, match, result.getOptions().getLanguage().supportsColumns())).toList(); + } + + private Match convertMatchToReportMatch(JPlagComparison comparison, de.jplag.Match match, boolean usesIndex) { + TokenList tokensFirst = comparison.getFirstSubmission().getTokenList(); + TokenList tokensSecond = comparison.getSecondSubmission().getTokenList(); + Token startTokenFirst = tokensFirst.getToken(match.startOfFirst()); + Token endTokenFirst = tokensFirst.getToken(match.startOfFirst() + match.length() - 1); + Token startTokenSecond = tokensSecond.getToken(match.startOfSecond()); + Token endTokenSecond = tokensSecond.getToken(match.startOfSecond() + match.length() - 1); + + int startFirst = usesIndex ? startTokenFirst.getIndex() : startTokenFirst.getLine(); + int endFirst = usesIndex ? endTokenFirst.getIndex() : endTokenFirst.getLine(); + int startSecond = usesIndex ? startTokenSecond.getIndex() : startTokenSecond.getLine(); + int endSecond = usesIndex ? endTokenSecond.getIndex() : endTokenSecond.getLine(); + int tokens = match.length(); + + return new Match(startTokenFirst.getFile(), startTokenSecond.getFile(), startFirst, endFirst, startSecond, endSecond, tokens); + } + +} diff --git a/jplag/src/main/java/de/jplag/reporting/reportobject/mapper/MetricMapper.java b/jplag/src/main/java/de/jplag/reporting/reportobject/mapper/MetricMapper.java index 1614c7114..c761a9a59 100644 --- a/jplag/src/main/java/de/jplag/reporting/reportobject/mapper/MetricMapper.java +++ b/jplag/src/main/java/de/jplag/reporting/reportobject/mapper/MetricMapper.java @@ -1,7 +1,7 @@ package de.jplag.reporting.reportobject.mapper; -import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; @@ -37,10 +37,10 @@ private static List intArrayToList(int[] array) { } private static List getTopComparisons(List comparisons, Function similarityExtractor) { - List topComparisons = new ArrayList<>(); - comparisons.forEach(comparison -> topComparisons.add(new TopComparison(comparison.getFirstSubmission().getName(), - comparison.getSecondSubmission().getName(), similarityExtractor.apply(comparison)))); - return topComparisons; + return comparisons.stream().sorted(Comparator.comparing(similarityExtractor).reversed()) + .map(comparison -> new TopComparison(comparison.getFirstSubmission().getName(), comparison.getSecondSubmission().getName(), + similarityExtractor.apply(comparison))) + .toList(); } private static List getTopComparisons(List comparisons) { diff --git a/jplag/src/main/java/de/jplag/reporting/reportobject/model/ComparisonReport.java b/jplag/src/main/java/de/jplag/reporting/reportobject/model/ComparisonReport.java index 9df5a333e..76df802cf 100644 --- a/jplag/src/main/java/de/jplag/reporting/reportobject/model/ComparisonReport.java +++ b/jplag/src/main/java/de/jplag/reporting/reportobject/model/ComparisonReport.java @@ -4,18 +4,14 @@ import com.fasterxml.jackson.annotation.JsonProperty; -public record ComparisonReport(@JsonProperty("first_submission_id") String firstSubmissionId, - @JsonProperty("second_submission_id") String secondSubmissionId, @JsonProperty("match_percentage") float matchPercentage, - @JsonProperty("files_of_first_submission") List filesOfFirstSubmission, - @JsonProperty("files_of_second_submission") List filesOfSecondSubmission, @JsonProperty("matches") List matches) { - public ComparisonReport(String firstSubmissionId, String secondSubmissionId, float matchPercentage, - List filesOfFirstSubmission, List filesOfSecondSubmission, List matches) { +/** + * ReportViewer DTO for the comparison of two submissions. + * @param firstSubmissionId id of the first submission + * @param secondSubmissionId id of the second submission + * @param matchPercentage similarity in percent. between 0f and 100f. + * @param matches the list of matches found in the comparison of the two submissions + */ +public record ComparisonReport(@JsonProperty("id1") String firstSubmissionId, @JsonProperty("id2") String secondSubmissionId, + @JsonProperty("similarity") float matchPercentage, @JsonProperty("matches") List matches) { - this.firstSubmissionId = firstSubmissionId; - this.secondSubmissionId = secondSubmissionId; - this.matchPercentage = matchPercentage; - this.filesOfFirstSubmission = List.copyOf(filesOfFirstSubmission); - this.filesOfSecondSubmission = List.copyOf(filesOfSecondSubmission); - this.matches = matches; - } } diff --git a/jplag/src/main/java/de/jplag/reporting/reportobject/model/FilesOfSubmission.java b/jplag/src/main/java/de/jplag/reporting/reportobject/model/FilesOfSubmission.java deleted file mode 100644 index 935a096c2..000000000 --- a/jplag/src/main/java/de/jplag/reporting/reportobject/model/FilesOfSubmission.java +++ /dev/null @@ -1,28 +0,0 @@ -package de.jplag.reporting.reportobject.model; - -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonProperty; - -public class FilesOfSubmission { - - @JsonProperty("file_name") - private final String fileName; - - @JsonProperty("lines") - private final List lines; - - public FilesOfSubmission(String fileName, List fileCode) { - this.fileName = fileName; - this.lines = List.copyOf(fileCode); - } - - public String getFileName() { - return fileName; - } - - public List getLines() { - return lines; - } - -} diff --git a/jplag/src/main/java/de/jplag/reporting/reportobject/model/JPlagReport.java b/jplag/src/main/java/de/jplag/reporting/reportobject/model/JPlagReport.java deleted file mode 100644 index 43ccdd7f8..000000000 --- a/jplag/src/main/java/de/jplag/reporting/reportobject/model/JPlagReport.java +++ /dev/null @@ -1,10 +0,0 @@ -package de.jplag.reporting.reportobject.model; - -import java.util.List; - -public record JPlagReport(OverviewReport overviewReport, List comparisons) { - public JPlagReport(OverviewReport overviewReport, List comparisons) { - this.overviewReport = overviewReport; - this.comparisons = List.copyOf(comparisons); - } -} diff --git a/jplag/src/main/java/de/jplag/reporting/reportobject/model/Match.java b/jplag/src/main/java/de/jplag/reporting/reportobject/model/Match.java index 0c6171697..8af13af20 100644 --- a/jplag/src/main/java/de/jplag/reporting/reportobject/model/Match.java +++ b/jplag/src/main/java/de/jplag/reporting/reportobject/model/Match.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; -public record Match(@JsonProperty("first_file_name") String firstFileName, @JsonProperty("second_file_name") String secondFileName, - @JsonProperty("start_in_first") int startInFirst, @JsonProperty("end_in_first") int endInFirst, - @JsonProperty("start_in_second") int startInSecond, @JsonProperty("end_in_second") int endInSecond, @JsonProperty("tokens") int tokens) { +public record Match(@JsonProperty("file1") String firstFileName, @JsonProperty("file2") String secondFileName, + @JsonProperty("start1") int startInFirst, @JsonProperty("end1") int endInFirst, @JsonProperty("start2") int startInSecond, + @JsonProperty("end2") int endInSecond, @JsonProperty("tokens") int tokens) { } diff --git a/report-viewer/package.json b/report-viewer/package.json index 88059f2a9..41e22c9ca 100644 --- a/report-viewer/package.json +++ b/report-viewer/package.json @@ -14,7 +14,8 @@ "core-js": "^3.24.1", "gitart-vue-dialog": "^2.4.0", "highlight.js": "^11.6.0", - "jszip": "^3.10.1", + "jszip": "^3.10.0", + "node-polyfill-webpack-plugin": "^2.0.0", "vue": "^3.2.37", "vue-chart-3": "^3.1.8", "vue-draggable-next": "^2.1.1", diff --git a/report-viewer/src/components/ClusterRadarChart.vue b/report-viewer/src/components/ClusterRadarChart.vue index 7593097a5..2a5ec50d6 100644 --- a/report-viewer/src/components/ClusterRadarChart.vue +++ b/report-viewer/src/components/ClusterRadarChart.vue @@ -46,6 +46,7 @@ export default defineComponent({ }, }, setup(props) { + let hasNoMember = false; const getIdOfFirstSubmission = () => { const firstMember = props.cluster.members.keys().next().value; hasNoMember = !firstMember; @@ -83,7 +84,6 @@ export default defineComponent({ }); const options = ref(radarChartOptions); - let hasNoMember = false; watch( () => selectedMember.value, (val) => { diff --git a/report-viewer/src/components/ComparisonsTable.vue b/report-viewer/src/components/ComparisonsTable.vue index 66b10b0b5..7eba55b09 100644 --- a/report-viewer/src/components/ComparisonsTable.vue +++ b/report-viewer/src/components/ComparisonsTable.vue @@ -87,7 +87,15 @@ @click="toggleDialog(index)" /> - + -import {defineComponent, ref, watch} from "vue"; -import {BarChart} from "vue-chart-3" -import {Chart, registerables} from 'chart.js'; -import ChartDataLabels from 'chartjs-plugin-datalabels'; +import { defineComponent, ref, watch } from "vue"; +import { BarChart } from "vue-chart-3"; +import { Chart, registerables } from "chart.js"; +import ChartDataLabels from "chartjs-plugin-datalabels"; Chart.register(...registerables); Chart.register(ChartDataLabels); export default defineComponent({ name: "DistributionDiagram", - components: {BarChart}, + components: { BarChart }, props: { distribution: { type: Array, - required: true - } + required: true, + }, }, setup(props) { //Highest count of submissions in a percentage range. We set the diagrams maximum shown value to maxVal + 5, //otherwise maximum is set to the highest count of submissions and is one bar always reaches the end. let maxVal = ref(Math.max(...props.distribution)); - const labels = ['0-10%', '11-20%', '21-30%', '31-40%', '41-50%', '51-60%', '61-70%', '71-80%', '81-90%', '91-100%'] + const labels = [ + "91-100%", + "81-90%", + "71-80%", + "61-70%", + "51-60%", + "41-50%", + "31-40%", + "21-30%", + "11-20%", + "0-10%", + ]; const dataSetStyle = { - label: 'Count', - backgroundColor: 'rgba(149, 168, 241, 0.5)', + label: "Count", + backgroundColor: "rgba(149, 168, 241, 0.5)", borderWidth: 2, - borderColor: 'rgba(149, 168, 241, 1)', - tickColor: '#000000' - } + borderColor: "rgba(149, 168, 241, 1)", + tickColor: "#000000", + }; let chartData = ref({ labels: labels, - datasets: [{ - ...dataSetStyle, - data: props.distribution, - }] - }) + datasets: [ + { + ...dataSetStyle, + data: props.distribution, + }, + ], + }); const options = ref({ responsive: true, maintainAspectRatio: false, - indexAxis: 'y', + indexAxis: "y", scales: { x: { suggestedMax: maxVal.value + 5, ticks: { - color: '#000000', - } + color: "#000000", + }, }, y: { ticks: { - color: '#000000', - } - } + color: "#000000", + }, + }, }, plugins: { datalabels: { - color: '#000000', + color: "#000000", font: { - weight: 'bold' + weight: "bold", }, - anchor: 'end', - align: 'end', - clamp: true + anchor: "end", + align: "end", + clamp: true, }, legend: { display: false, - } - } - }) + }, + }, + }); //We watch the given distributions parameter. When the distribution of another metric is passed, the diagram is //updated with the new data. - watch(() => props.distribution, (val) => { - chartData.value = { - labels: labels, - datasets: [{ + watch( + () => props.distribution, + (val) => { + chartData.value = { + labels: labels, + datasets: [ + { ...dataSetStyle, data: val, - }] - } + }, + ], + }; - maxVal.value = Math.max(...val) - options.value.scales.x.suggestedMax = maxVal.value + 5 - } - ) + maxVal.value = Math.max(...val); + options.value.scales.x.suggestedMax = maxVal.value + 5; + } + ); return { chartData, - options - } - } - -}) + options, + }; + }, +});