diff --git a/pom.xml b/pom.xml index 1b56db7..cc7864d 100644 --- a/pom.xml +++ b/pom.xml @@ -17,12 +17,17 @@ - + io.github.kit-sdq artemis4j 6.6.6 + + org.jcommander + jcommander + 1.83 + org.junit.jupiter junit-jupiter-api @@ -36,11 +41,10 @@ test - org.jcommander - jcommander - 1.83 + org.slf4j + slf4j-simple + 2.0.9 - @@ -96,6 +100,33 @@ origin/main + + org.apache.maven.plugins + maven-assembly-plugin + 3.6.0 + + + + true + edu.kit.kastel.sdq.scorestats.Application + + + + jar-with-dependencies + + artemis-score-stats-complete + false + + + + fatjar + + single + + package + + + org.apache.maven.plugins maven-clean-plugin @@ -140,33 +171,6 @@ - - org.apache.maven.plugins - maven-assembly-plugin - 3.6.0 - - - - true - edu.kit.kastel.sdq.scorestats.Application - - - - jar-with-dependencies - - artemis-score-stats-complete - false - - - - fatjar - - single - - package - - - diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/Application.java b/src/main/java/edu/kit/kastel/sdq/scorestats/Application.java index 0d6fd19..c505aab 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/Application.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/Application.java @@ -1,10 +1,11 @@ +/* Licensed under EPL-2.0 2023. */ package edu.kit.kastel.sdq.scorestats; import edu.kit.kastel.sdq.scorestats.cli.CLI; -public class Application { - public static void main(String[] args) { - CLI cli = new CLI(); - cli.run(args); - } +public final class Application { + public static void main(String[] args) { + CLI cli = new CLI(); + cli.run(args); + } } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/cli/arguments/Arguments.java b/src/main/java/edu/kit/kastel/sdq/scorestats/cli/arguments/Arguments.java index dd357eb..741ef5e 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/cli/arguments/Arguments.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/cli/arguments/Arguments.java @@ -15,27 +15,27 @@ */ public class Arguments { - @Parameter(names = { "-host", "-h" }, description = "Artemis host", required = true) - public String host; + @Parameter(names = { "-host", "-h" }, description = "Artemis host", required = true) + public String host; - @Parameter(names = { "-user", "-u" }, description = "Artemis user name", required = true) - public String username; + @Parameter(names = { "-user", "-u" }, description = "Artemis user name", required = true) + public String username; - @Parameter(names = { "-password", "-p" }, description = "Artemis password", password = true, required = true) - public String password; + @Parameter(names = { "-password", "-p" }, description = "Artemis password", password = true, required = true) + public String password; - @Parameter(names = { "-output", "-o" }, description = "The output directory.", converter = FileConverter.class) - public File outDir = new File("./stats"); + @Parameter(names = { "-output", "-o" }, description = "The output directory.", converter = FileConverter.class) + public File outDir = new File("./stats"); - @Parameter(names = { "-groups", - "-g" }, description = "The directory containing the group files. If no directory is specified, or if the directory is empty, only one report about all submissions will be generated.", converter = FileConverter.class, validateWith = ExistingDirectory.class) - public File groupsDir; + @Parameter(names = { "-groups", + "-g" }, description = "The directory containing the group files. If no directory is specified, or if the directory is empty, only one report about all submissions will be generated.", converter = FileConverter.class, validateWith = ExistingDirectory.class) + public File groupsDir; - @Parameter(names = { "-configs", - "-c" }, description = "The directory containing the grading config files. A config file must contain the short name of its corresponding exercise. For exercises without a config file all stats related to manual assessments will not be generated.", converter = FileConverter.class, validateWith = ExistingDirectory.class) - public File configsDir; + @Parameter(names = { "-configs", + "-c" }, description = "The directory containing the grading config files. A config file must contain the short name of its corresponding exercise. For exercises without a config file all stats related to manual assessments will not be generated.", converter = FileConverter.class, validateWith = ExistingDirectory.class) + public File configsDir; - @Parameter(names = { "-outputLimit", - "-l" }, description = "How many elements should at most be listed. This setting will be respected by all stats where the entirety of the result is not particularly significant.", validateWith = PositiveInteger.class) - public Integer outputLimit; + @Parameter(names = { "-outputLimit", + "-l" }, description = "How many elements should at most be listed. This setting will be respected by all stats where the entirety of the result is not particularly significant.", validateWith = PositiveInteger.class) + public int outputLimit = 0; } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/config/ReportBuilder.java b/src/main/java/edu/kit/kastel/sdq/scorestats/config/ReportBuilder.java index dea9ed6..ab40049 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/config/ReportBuilder.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/config/ReportBuilder.java @@ -1,3 +1,4 @@ +/* Licensed under EPL-2.0 2023. */ package edu.kit.kastel.sdq.scorestats.config; import java.io.File; @@ -24,62 +25,38 @@ public class ReportBuilder { - private Output output; - - public ReportBuilder createReport( - Arguments arguments, - Course course, - Exercise exercise, - ExerciseConfig config, - Assessments assessments, - Set students) { - - Report report = new Report<>( - course, - exercise, - config, - assessments, - students); - - ReportOutput output = new ReportOutput( - arguments, - course, - exercise, - report.accept(new ParticipationReport<>()), - report.count(new FeedbackGroupPassedCount( - AutomaticFeedbackType.MANDATORY)), - report.average(new ScoreAverage<>()), - report.average( - new FeedbackGroupPassedAverage( - AutomaticFeedbackType.FUNCTIONAL)), - report.average( - new FeedbackGroupPassedAverage( - AutomaticFeedbackType.MODELLING_CHECK)), - config == null ? null : report.average(new ManualDeductionAverage<>()), - report.frequency( - new FeedbackGroupFailedFrequency( - AutomaticFeedbackType.FUNCTIONAL)), - report.frequency( - new FeedbackGroupFailedFrequency( - AutomaticFeedbackType.MODELLING_CHECK)), - config == null ? null : report.frequency(new MistakeTypeFrequencyPerSubmission<>()), - config == null ? null : report.frequency(new MistakeTypeFrequencyPerAnnotation<>()), - config == null ? null : report.list(new CustomPenaltyAnnotationList<>())); - - this.output = output; - return this; - } - - public Output getOutput() { - return this.output; - } - - public void writeToFile(File file) { - FileWriter writer = new FileWriter(this.output, file); - try { - writer.write(); - } catch (IOException e) { - System.err.println("Error, could not write to file: %s".formatted(file.getAbsolutePath())); - } - } + private Output output; + + public ReportBuilder createReport(Arguments arguments, Course course, Exercise exercise, ExerciseConfig config, + Assessments assessments, Set students) { + + Report report = new Report<>(course, exercise, config, assessments, students); + + this.output = new ReportOutput(arguments, course, exercise, report.accept(new ParticipationReport<>()), + report.count(new FeedbackGroupPassedCount(AutomaticFeedbackType.MANDATORY)), report.average(new ScoreAverage<>()), + report.average(new FeedbackGroupPassedAverage(AutomaticFeedbackType.FUNCTIONAL)), + report.average(new FeedbackGroupPassedAverage(AutomaticFeedbackType.MODELLING_CHECK)), + config == null ? null : report.average(new ManualDeductionAverage<>()), + + report.frequency(new FeedbackGroupFailedFrequency(AutomaticFeedbackType.MANDATORY)), + report.frequency(new FeedbackGroupFailedFrequency(AutomaticFeedbackType.FUNCTIONAL)), + report.frequency(new FeedbackGroupFailedFrequency(AutomaticFeedbackType.MODELLING_CHECK)), + config == null ? null : report.frequency(new MistakeTypeFrequencyPerSubmission<>()), + config == null ? null : report.frequency(new MistakeTypeFrequencyPerAnnotation<>()), + config == null ? null : report.list(new CustomPenaltyAnnotationList<>())); + return this; + } + + public Output getOutput() { + return this.output; + } + + public void writeToFile(File file) { + FileWriter writer = new FileWriter(this.output, file); + try { + writer.write(); + } catch (IOException e) { + System.err.printf("Error, could not write to file: %s%n", file.getAbsolutePath()); + } + } } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/config/ReportOutput.java b/src/main/java/edu/kit/kastel/sdq/scorestats/config/ReportOutput.java index b94a5d1..de77289 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/config/ReportOutput.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/config/ReportOutput.java @@ -1,3 +1,4 @@ +/* Licensed under EPL-2.0 2023. */ package edu.kit.kastel.sdq.scorestats.config; import java.util.List; @@ -23,160 +24,120 @@ public class ReportOutput implements Output { - public static final int COLUMN_WIDTH = 35; - - private final Course course; - private final Exercise exercise; - private final Ratio participation; - private final Ratio mandatoryPassed; - private final Ratio averageScore; - private final Ratio averagePassedFunctional; - private final Ratio averagePassedModellingChecks; - private final Ratio averageManualDeduction; - private final FrequencyResult functionalFrequency; - private final FrequencyResult modellingFrequency; - private final FrequencyResult annotationsFrequencyPerSubmission; - private final FrequencyResult annotationsFrequencyPerAnnotations; - private final List customAnnotations; - private Arguments arguments; - - public ReportOutput( - Arguments arguments, - Course course, - Exercise exercise, - Ratio participation, - Ratio mandatoryPassed, - Ratio averageScore, - Ratio averagePassedFunctional, - Ratio averagePassedModellingChecks, - Ratio averageManualDeduction, - FrequencyResult functionalFrequency, - FrequencyResult modellingFrequency, - FrequencyResult annotationsFrequencyPerSubmission, - FrequencyResult annotationsFrequencyPerAnnotations, - List customAnnotations) { - this.arguments = Objects.requireNonNull(arguments); - this.course = Objects.requireNonNull(course); - this.exercise = Objects.requireNonNull(exercise); - this.participation = participation; - this.mandatoryPassed = mandatoryPassed; - this.averageScore = averageScore; - this.averagePassedFunctional = averagePassedFunctional; - this.averagePassedModellingChecks = averagePassedModellingChecks; - this.averageManualDeduction = averageManualDeduction; - this.functionalFrequency = functionalFrequency; - this.modellingFrequency = modellingFrequency; - this.annotationsFrequencyPerSubmission = annotationsFrequencyPerSubmission; - this.annotationsFrequencyPerAnnotations = annotationsFrequencyPerAnnotations; - this.customAnnotations = customAnnotations; - } - - @Override - public String print() { - Document document = new Document( - new LineSeparator(), - new Heading(1, this.course.getTitle()), - new Divider(), - new LineSeparator(), - - new Heading(1, this.exercise.getTitle()), - new Heading(1, "ZUSAMMENFASSUNG")); - - if (this.participation != null) { - document.append(new SummaryLine("Teilnahmen", - 1, - new RatioRow((int) this.participation.numerator(), - (int) this.participation.denominator())) - - ); - } - - if (this.mandatoryPassed != null) { - document.append(new SummaryLine("Mandatory bestanden", - 1, - new RatioRow((int) this.mandatoryPassed.numerator(), - (int) this.mandatoryPassed.denominator()))); - } - - if (this.averageScore != null) { - document.append(new SummaryLine("Ø Punktzahl", - 1, - // TODO use double denominator - new RatioRow(this.averageScore.numerator(), - (int) this.averageScore.denominator()))); - } - - if (this.averagePassedFunctional != null) { - document.append(new SummaryLine("Ø bestandene functional Tests", - 1, - new RatioRow(this.averagePassedFunctional.numerator(), - (int) this.averagePassedFunctional - .denominator()))); - } - - if (this.averagePassedModellingChecks != null) { - document.append(new SummaryLine("Ø bestandene Modelling-Checks", - 1, - new RatioRow(this.averagePassedModellingChecks.numerator(), - (int) this.averagePassedModellingChecks.denominator()))); - } - - document.append(new LineSeparator()); - - if (this.averageManualDeduction != null) { - document.append(new SummaryLine("Ø manueller Abzug", - 1, - new RatioRow(this.averageManualDeduction.numerator(), - // TODO use double denominator - (int) this.averageManualDeduction.denominator())), - new LineSeparator()); - } - - document.append(new LineSeparator()); - - if (this.functionalFrequency != null) { - document.append(new Heading(1, "HÄUFIG FEHLGESCHLAGENE FUNCTIONAL TESTS"), - new FeedbackFrequencyList(1, this.functionalFrequency), - new LineSeparator()); - } - - if (this.modellingFrequency != null) { - document.append(new Heading(1, "HÄUFIG FEHLGESCHLAGENE MODELLING-CHECKS"), - new FeedbackFrequencyList(1, this.modellingFrequency, - this.arguments.outputLimit), - new LineSeparator()); - } - - if (this.annotationsFrequencyPerSubmission != null) { - document.append(new Heading(1, - "HÄUFIGE KORREKTUR ANMERKUNGEN (mind. eine Anmerkung pro Abgabe)"), - new MistakeTypeFrequencyList(1, this.annotationsFrequencyPerSubmission, - this.arguments.outputLimit), - new LineSeparator()); - - } - - if (this.annotationsFrequencyPerSubmission != null) { - document.append(new Heading(1, - "HÄUFIGE KORREKTUR ANMERKUNGEN (mind. eine Anmerkung pro Abgabe)"), - new MistakeTypeFrequencyList(1, this.annotationsFrequencyPerSubmission, - this.arguments.outputLimit), - new LineSeparator()); - } - - if (this.annotationsFrequencyPerAnnotations != null) { - document.append( - new Heading(1, "HÄUFIGE KORREKTUR ANMERKUNGEN (alle Anmerkungen)"), - new MistakeTypeFrequencyList(1, this.annotationsFrequencyPerAnnotations, - this.arguments.outputLimit), - new LineSeparator()); - } - if (this.customAnnotations != null) { - document.append(new Heading(1, "INDIVIDUELLE KOMMENTARE"), - new CustomPenaltyList(1, this.customAnnotations), - new LineSeparator()); - } - - return document.print(); - } + public static final int COLUMN_WIDTH = 35; + + private final Course course; + private final Exercise exercise; + private final Ratio participation; + private final Ratio mandatoryPassed; + private final Ratio averageScore; + private final Ratio averagePassedFunctional; + private final Ratio averagePassedModellingChecks; + private final Ratio averageManualDeduction; + private final FrequencyResult mandatoryFrequency; + private final FrequencyResult functionalFrequency; + private final FrequencyResult modellingFrequency; + private final FrequencyResult annotationsFrequencyPerSubmission; + private final FrequencyResult annotationsFrequencyPerAnnotations; + private final List customAnnotations; + private final Arguments arguments; + + public ReportOutput(Arguments arguments, Course course, Exercise exercise, Ratio participation, Ratio mandatoryPassed, Ratio averageScore, + Ratio averagePassedFunctional, Ratio averagePassedModellingChecks, Ratio averageManualDeduction, FrequencyResult mandatoryFrequency, + FrequencyResult functionalFrequency, FrequencyResult modellingFrequency, + FrequencyResult annotationsFrequencyPerSubmission, FrequencyResult annotationsFrequencyPerAnnotations, + List customAnnotations) { + this.arguments = Objects.requireNonNull(arguments); + this.course = Objects.requireNonNull(course); + this.exercise = Objects.requireNonNull(exercise); + this.participation = participation; + this.mandatoryPassed = mandatoryPassed; + this.averageScore = averageScore; + this.averagePassedFunctional = averagePassedFunctional; + this.averagePassedModellingChecks = averagePassedModellingChecks; + this.averageManualDeduction = averageManualDeduction; + this.mandatoryFrequency = mandatoryFrequency; + this.functionalFrequency = functionalFrequency; + this.modellingFrequency = modellingFrequency; + this.annotationsFrequencyPerSubmission = annotationsFrequencyPerSubmission; + this.annotationsFrequencyPerAnnotations = annotationsFrequencyPerAnnotations; + this.customAnnotations = customAnnotations; + } + + @Override + public String print() { + Document document = new Document(new LineSeparator(), new Heading(1, this.course.getTitle()), new Divider(), new LineSeparator(), + + new Heading(1, this.exercise.getTitle()), new Heading(1, "ZUSAMMENFASSUNG")); + + if (this.participation != null) { + document.append(new SummaryLine("Teilnahmen", 1, new RatioRow((int) this.participation.numerator(), (int) this.participation.denominator())) + + ); + } + + if (this.mandatoryPassed != null) { + document.append( + new SummaryLine("Mandatory bestanden", 1, new RatioRow((int) this.mandatoryPassed.numerator(), (int) this.mandatoryPassed.denominator()))); + } + + if (this.averageScore != null) { + document.append(new SummaryLine("Ø Punktzahl", 1, new RatioRow(this.averageScore.numerator(), (int) this.averageScore.denominator()))); + } + + if (this.averagePassedFunctional != null) { + document.append(new SummaryLine("Ø bestandene functional Tests", 1, + new RatioRow(this.averagePassedFunctional.numerator(), (int) this.averagePassedFunctional.denominator()))); + } + + if (this.averagePassedModellingChecks != null) { + document.append(new SummaryLine("Ø bestandene Modelling-Checks", 1, + new RatioRow(this.averagePassedModellingChecks.numerator(), (int) this.averagePassedModellingChecks.denominator()))); + } + + document.append(new LineSeparator()); + + if (this.averageManualDeduction != null) { + document.append(new SummaryLine("Ø manueller Abzug", 1, + new RatioRow(this.averageManualDeduction.numerator(), (int) this.averageManualDeduction.denominator())), new LineSeparator()); + } + + document.append(new LineSeparator()); + + if (this.mandatoryFrequency != null) { + document.append(new Heading(1, "HÄUFIG FEHLGESCHLAGENE MANDATORY TESTS"), new FeedbackFrequencyList(1, this.mandatoryFrequency), + new LineSeparator()); + } + + if (this.functionalFrequency != null) { + document.append(new Heading(1, "HÄUFIG FEHLGESCHLAGENE FUNCTIONAL TESTS"), new FeedbackFrequencyList(1, this.functionalFrequency), + new LineSeparator()); + } + + if (this.modellingFrequency != null) { + document.append(new Heading(1, "HÄUFIG FEHLGESCHLAGENE MODELLING-CHECKS"), + new FeedbackFrequencyList(1, this.modellingFrequency, this.arguments.outputLimit), new LineSeparator()); + } + + if (this.annotationsFrequencyPerSubmission != null) { + document.append(new Heading(1, "HÄUFIGE KORREKTUR ANMERKUNGEN (mind. eine Anmerkung pro Abgabe)"), + new MistakeTypeFrequencyList(1, this.annotationsFrequencyPerSubmission, this.arguments.outputLimit), new LineSeparator()); + + } + + if (this.annotationsFrequencyPerSubmission != null) { + document.append(new Heading(1, "HÄUFIGE KORREKTUR ANMERKUNGEN (mind. eine Anmerkung pro Abgabe)"), + new MistakeTypeFrequencyList(1, this.annotationsFrequencyPerSubmission, this.arguments.outputLimit), new LineSeparator()); + } + + if (this.annotationsFrequencyPerAnnotations != null) { + document.append(new Heading(1, "HÄUFIGE KORREKTUR ANMERKUNGEN (alle Anmerkungen)"), + new MistakeTypeFrequencyList(1, this.annotationsFrequencyPerAnnotations, this.arguments.outputLimit), new LineSeparator()); + } + if (this.customAnnotations != null) { + document.append(new Heading(1, "INDIVIDUELLE KOMMENTARE"), new CustomPenaltyList(1, this.customAnnotations), new LineSeparator()); + } + + return document.print(); + } } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/core/assessment/PrefixMatcher.java b/src/main/java/edu/kit/kastel/sdq/scorestats/core/assessment/PrefixMatcher.java index 24f63ed..b7d76bc 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/core/assessment/PrefixMatcher.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/core/assessment/PrefixMatcher.java @@ -8,30 +8,30 @@ * @author Moritz Hertler * @version 1.0 */ -public class PrefixMatcher implements FeedbackGroupMatcher { +public final class PrefixMatcher implements FeedbackGroupMatcher { - private final String prefix; + private final String prefix; - public PrefixMatcher(String prefix) { - this.prefix = prefix; - } + public PrefixMatcher(String prefix) { + this.prefix = prefix; + } - public String getPrefix() { - return this.prefix; - } + public String getPrefix() { + return this.prefix; + } - /** - * Returns {@code true} if {@link Feedback#getText()} begins with the prefix. - * - * @param feedback the feedback - * @returns {@code true} if {@link Feedback#getText()} begins with the prefix - */ - @Override - public boolean matches(Feedback feedback) { - if (feedback.getFeedbackType() == FeedbackType.MANUAL_UNREFERENCED) { - throw new IllegalArgumentException(); - } + /** + * Returns {@code true} if {@link Feedback#getText()} begins with the prefix. + * + * @param feedback the feedback + * @return {@code true} if {@link Feedback#getText()} begins with the prefix + */ + @Override + public boolean matches(Feedback feedback) { + if (feedback.getFeedbackType() == FeedbackType.MANUAL_UNREFERENCED) { + throw new IllegalArgumentException(); + } - return feedback.getText().startsWith(this.prefix); - } + return feedback.getText().startsWith(this.prefix); + } } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/core/client/Artemis4JArtemisClient.java b/src/main/java/edu/kit/kastel/sdq/scorestats/core/client/Artemis4JArtemisClient.java index 9398492..5d4d847 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/core/client/Artemis4JArtemisClient.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/core/client/Artemis4JArtemisClient.java @@ -10,7 +10,6 @@ import edu.kit.kastel.sdq.artemis4j.api.ArtemisClientException; import edu.kit.kastel.sdq.artemis4j.api.artemis.Course; import edu.kit.kastel.sdq.artemis4j.api.artemis.Exercise; -import edu.kit.kastel.sdq.artemis4j.api.artemis.ExerciseStats; import edu.kit.kastel.sdq.artemis4j.api.artemis.assessment.Feedback; import edu.kit.kastel.sdq.artemis4j.api.artemis.assessment.Result; import edu.kit.kastel.sdq.artemis4j.api.artemis.assessment.Submission; @@ -44,20 +43,11 @@ public void login(String username, String password) throws ArtemisClientExceptio this.client.login(); } - public boolean isReady() { - return this.client != null && this.client.isReady(); - } - public List loadCourses() throws ArtemisClientException { return this.client.getCourseArtemisClient().getCourses(); } - public ExerciseStats loadStats(Exercise exercise) throws ArtemisClientException { - return this.client.getAssessmentArtemisClient().getStats(exercise); - } - - public Assessments loadAssessments(Exercise exercise, ExerciseConfig config) - throws ArtemisClientException { + public Assessments loadAssessments(Exercise exercise, ExerciseConfig config) throws ArtemisClientException { List submissions = this.client.getSubmissionArtemisClient().getSubmissions(exercise); @@ -72,8 +62,7 @@ public Assessments loadAssessments(Exercise exercise, ExerciseConfig config) for (Submission submission : submissions) { Result result = submission.getLatestResult(); - List feedbacks = this.client.getAssessmentArtemisClient() - .getFeedbacks(submission, result); + List feedbacks = this.client.getAssessmentArtemisClient().getFeedbacks(submission, result); feedbacks.forEach(Feedback::init); boolean success = loadDetailText(result, feedbacks); if (!success) { @@ -101,7 +90,7 @@ public Assessments loadAssessments(Exercise exercise, ExerciseConfig config) assessments.put(id, assessment); } - return new Assessments(skippedStudents, assessments); + return new Assessments<>(skippedStudents, assessments); } private boolean loadDetailText(Result result, List feedbacks) { diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/core/client/ArtemisClient.java b/src/main/java/edu/kit/kastel/sdq/scorestats/core/client/ArtemisClient.java index 5e05879..d7e845d 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/core/client/ArtemisClient.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/core/client/ArtemisClient.java @@ -1,31 +1,25 @@ /* Licensed under EPL-2.0 2023. */ package edu.kit.kastel.sdq.scorestats.core.client; -import java.util.List; - import edu.kit.kastel.sdq.artemis4j.api.ArtemisClientException; import edu.kit.kastel.sdq.artemis4j.api.artemis.Course; import edu.kit.kastel.sdq.artemis4j.api.artemis.Exercise; -import edu.kit.kastel.sdq.artemis4j.api.artemis.ExerciseStats; import edu.kit.kastel.sdq.artemis4j.grading.config.ExerciseConfig; import edu.kit.kastel.sdq.scorestats.core.assessment.Assessments; +import java.util.List; + /** * A client to interact with the artemis api. - * + * * @author Moritz Hertler * @version 1.0 */ public interface ArtemisClient { - public void login(String username, String password) throws ArtemisClientException; - - public boolean isReady(); - - public List loadCourses() throws ArtemisClientException; + void login(String username, String password) throws ArtemisClientException; - public ExerciseStats loadStats(Exercise exercise) throws ArtemisClientException; + List loadCourses() throws ArtemisClientException; - public Assessments loadAssessments(Exercise exercise, ExerciseConfig config) - throws ArtemisClientException; + Assessments loadAssessments(Exercise exercise, ExerciseConfig config) throws ArtemisClientException; } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/ReportAverageVisitor.java b/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/ReportAverageVisitor.java index ab1e2cb..ae7c8d1 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/ReportAverageVisitor.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/ReportAverageVisitor.java @@ -13,22 +13,20 @@ * @version 1.0 */ public interface ReportAverageVisitor { - Iterable iterable(Report.ReportData data); + Iterable iterable(Report.ReportData data); - /** - * The summand added to the current average based on the current {@code value}. - * - * @param value - * @param data - * @return the summand - */ - double summand(T value, Report.ReportData data); + /** + * The summand added to the current average based on the current {@code value}. + * + * @return the summand + */ + double summand(T value, Report.ReportData data); - /** - * The maximum value the average could be. - * - * @param data the data - * @return the maximum value - */ - double max(Report.ReportData data); + /** + * The maximum value the average could be. + * + * @param data the data + * @return the maximum value + */ + double max(Report.ReportData data); } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/ReportCountVisitor.java b/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/ReportCountVisitor.java index e3057bf..16af498 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/ReportCountVisitor.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/ReportCountVisitor.java @@ -13,13 +13,12 @@ * @version 1.0 */ public interface ReportCountVisitor { - Iterable iterable(Report.ReportData data); + Iterable iterable(Report.ReportData data); - /** - * Returns {@code true} if the current {@code value} should be counted. - * - * @param value - * @return {@code true} if the current {@code value} should be counted - */ - boolean count(T value); + /** + * Returns {@code true} if the current {@code value} should be counted. + * + * @return {@code true} if the current {@code value} should be counted + */ + boolean count(T value); } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/ReportFrequencyVisitor.java b/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/ReportFrequencyVisitor.java index a4cd4c9..bab1ced 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/ReportFrequencyVisitor.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/ReportFrequencyVisitor.java @@ -16,22 +16,21 @@ * @version 1.0 */ public interface ReportFrequencyVisitor { - Iterable iterable(Report.ReportData data); + Iterable iterable(Report.ReportData data); - /** - * Returns the elements based of the current {@code value} to add to the - * frequency. - * - * @param value - * @return the elements to add to the frequency - */ - Collection count(T value); + /** + * Returns the elements based of the current {@code value} to add to the + * frequency. + * + * @return the elements to add to the frequency + */ + Collection count(T value); - /** - * The maximum value the frequency could be. - * - * @param data the data - * @return the maximum value - */ - int max(Report.ReportData data); + /** + * The maximum value the frequency could be. + * + * @param data the data + * @return the maximum value + */ + int max(Report.ReportData data); } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/ReportListVisitor.java b/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/ReportListVisitor.java index 8806554..24bc61f 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/ReportListVisitor.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/ReportListVisitor.java @@ -16,13 +16,12 @@ * @version 1.0 */ public interface ReportListVisitor { - Iterable iterable(Report.ReportData data); + Iterable iterable(Report.ReportData data); - /** - * Returns the elements based on the current {@code value} to add to the list. - * - * @param value - * @return the elements to add to the list - */ - List list(T value); + /** + * Returns the elements based on the current {@code value} to add to the list. + * + * @return the elements to add to the list + */ + List list(T value); } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/visitors/FeedbackGroupFailedFrequency.java b/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/visitors/FeedbackGroupFailedFrequency.java index dd929a8..ec966c2 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/visitors/FeedbackGroupFailedFrequency.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/visitors/FeedbackGroupFailedFrequency.java @@ -2,8 +2,8 @@ package edu.kit.kastel.sdq.scorestats.core.report.visitors; import java.util.List; -import java.util.stream.Collectors; +import edu.kit.kastel.sdq.artemis4j.api.artemis.assessment.Feedback; import edu.kit.kastel.sdq.scorestats.core.assessment.Assessment; import edu.kit.kastel.sdq.scorestats.core.assessment.FeedbackGroup; import edu.kit.kastel.sdq.scorestats.core.report.Report.ReportData; @@ -19,28 +19,26 @@ */ public class FeedbackGroupFailedFrequency implements ReportFrequencyVisitor, String> { - private final K key; - - public FeedbackGroupFailedFrequency(K key) { - this.key = key; - } - - @Override - public Iterable> iterable(ReportData data) { - return data.selectedAssessments(); - } - - @Override - public List count(Assessment value) { - FeedbackGroup feedbackGroup = value.getFeedbackGroup(this.key); - return feedbackGroup.getFailedFeedbacks().stream() - .map(e -> e.getText()) - .collect(Collectors.toList()); - } - - @Override - public int max(ReportData data) { - return data.selectedAssessments().size(); - } + private final K key; + + public FeedbackGroupFailedFrequency(K key) { + this.key = key; + } + + @Override + public Iterable> iterable(ReportData data) { + return data.selectedAssessments(); + } + + @Override + public List count(Assessment value) { + FeedbackGroup feedbackGroup = value.getFeedbackGroup(this.key); + return feedbackGroup.getFailedFeedbacks().stream().map(Feedback::getText).toList(); + } + + @Override + public int max(ReportData data) { + return data.selectedAssessments().size(); + } } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/visitors/MistakeTypeFrequencyPerAnnotation.java b/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/visitors/MistakeTypeFrequencyPerAnnotation.java index 868d1a5..1e57c4b 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/visitors/MistakeTypeFrequencyPerAnnotation.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/core/report/visitors/MistakeTypeFrequencyPerAnnotation.java @@ -2,8 +2,8 @@ package edu.kit.kastel.sdq.scorestats.core.report.visitors; import java.util.Collection; -import java.util.stream.Collectors; +import edu.kit.kastel.sdq.artemis4j.api.grading.IAnnotation; import edu.kit.kastel.sdq.artemis4j.api.grading.IMistakeType; import edu.kit.kastel.sdq.scorestats.core.report.Report.ReportData; import edu.kit.kastel.sdq.scorestats.core.assessment.Assessment; @@ -20,25 +20,23 @@ */ public class MistakeTypeFrequencyPerAnnotation implements ReportFrequencyVisitor, IMistakeType> { - @Override - public Iterable> iterable(ReportData data) { - return data.selectedAssessments(); - } + @Override + public Iterable> iterable(ReportData data) { + return data.selectedAssessments(); + } - @Override - public Collection count(Assessment value) { - return value.getAnnotations().stream() - .map(annotation -> annotation.getMistakeType()) - .collect(Collectors.toList()); - } + @Override + public Collection count(Assessment value) { + return value.getAnnotations().stream().map(IAnnotation::getMistakeType).toList(); + } - @Override - public int max(ReportData data) { - int sum = 0; - for (Assessment assessment : data.selectedAssessments()) { - sum += assessment.getAnnotations().size(); - } - return sum; - } + @Override + public int max(ReportData data) { + int sum = 0; + for (Assessment assessment : data.selectedAssessments()) { + sum += assessment.getAnnotations().size(); + } + return sum; + } } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/input/ConfigFileMapper.java b/src/main/java/edu/kit/kastel/sdq/scorestats/input/ConfigFileMapper.java index c53630b..506125c 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/input/ConfigFileMapper.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/input/ConfigFileMapper.java @@ -18,49 +18,48 @@ */ public class ConfigFileMapper { - /** - * The last file in the given directory containing the short name of a given - * exercise is mapped to that exercise. - * - * The matching is case insensitive. - * - * If an exercise has no matching config file, the map will contain {@code null} - * for that exercise. - * - * @param exercises the exercises - * @param directory the directory containing the config files - * @return the map of exercises to exercise configs - * @throws ConfigFileParserException if a config file could not be parsed - */ - public Map mapConfigFiles(List exercises, File directory) - throws ConfigFileParserException { - if (!directory.isDirectory()) { - throw new IllegalArgumentException("File must be a directory."); - } + /** + * The last file in the given directory containing the short name of a given + * exercise is mapped to that exercise. + * + * The matching is case-insensitive. + * + * If an exercise has no matching config file, the map will contain {@code null} + * for that exercise. + * + * @param exercises the exercises + * @param directory the directory containing the config files + * @return the map of exercises to exercise configs + * @throws ConfigFileParserException if a config file could not be parsed + */ + public Map mapConfigFiles(List exercises, File directory) throws ConfigFileParserException { + if (directory != null && !directory.isDirectory()) { + throw new IllegalArgumentException("File must be a directory."); + } - ConfigFileParser parser = new ConfigFileParser(); + ConfigFileParser parser = new ConfigFileParser(); - File[] files = directory == null ? new File[] {} : directory.listFiles(); + File[] files = directory == null ? new File[] {} : directory.listFiles(); - Map map = new HashMap<>(); - for (Exercise exercise : exercises) { - map.put(exercise, null); - for (File file : files) { - if (!this.matchesExercise(file, exercise)) { - continue; - } + Map map = new HashMap<>(); + for (Exercise exercise : exercises) { + map.put(exercise, null); + for (File file : files) { + if (!this.matchesExercise(file, exercise)) { + continue; + } - ExerciseConfig exerciseConfig = parser.parse(exercise, file); - map.put(exercise, exerciseConfig); - } - } + ExerciseConfig exerciseConfig = parser.parse(exercise, file); + map.put(exercise, exerciseConfig); + } + } - return map; - } + return map; + } - private boolean matchesExercise(File file, Exercise exercise) { - String fileName = file.getName().toLowerCase(); - String exerciseName = exercise.getShortName().toLowerCase(); - return fileName.contains(exerciseName); - } + private boolean matchesExercise(File file, Exercise exercise) { + String fileName = file.getName().toLowerCase(); + String exerciseName = exercise.getShortName().toLowerCase(); + return fileName.contains(exerciseName); + } } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/input/ConfigFileParser.java b/src/main/java/edu/kit/kastel/sdq/scorestats/input/ConfigFileParser.java index 0efc632..01c677e 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/input/ConfigFileParser.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/input/ConfigFileParser.java @@ -17,50 +17,49 @@ */ public class ConfigFileParser { - public ExerciseConfig parse(Exercise exercise, File file) throws ConfigFileParserException { + public ExerciseConfig parse(Exercise exercise, File file) throws ConfigFileParserException { - GradingConfig config = new JsonFileConfig(file); + GradingConfig config = new JsonFileConfig(file); - ExerciseConfig exerciseConfig; - try { - exerciseConfig = config.getExerciseConfig(exercise); - } catch (IOException e) { - throw new ConfigFileParserException(ConfigFileParserError.PARSING_FAILED, exercise, file); - } + ExerciseConfig exerciseConfig; + try { + exerciseConfig = config.getExerciseConfig(exercise); + } catch (IOException e) { + throw new ConfigFileParserException(ConfigFileParserError.PARSING_FAILED, exercise, file); + } - if (!exerciseConfig.getAllowedExercises().contains(exercise.getExerciseId())) { - throw new ConfigFileParserException(ConfigFileParserError.NOT_ALLOWED, exercise, file); - } + if (!exerciseConfig.getAllowedExercises().contains(exercise.getExerciseId())) { + throw new ConfigFileParserException(ConfigFileParserError.NOT_ALLOWED, exercise, file); + } - return exerciseConfig; - } + return exerciseConfig; + } - public class ConfigFileParserException extends Exception { - private ConfigFileParserError error; - private Exercise exercise; - private File file; + public static class ConfigFileParserException extends Exception { + private final ConfigFileParserError error; + private final Exercise exercise; + private final File file; - ConfigFileParserException(ConfigFileParserError error, Exercise exercise, File file) { - this.error = error; - this.exercise = exercise; - this.file = file; - } + ConfigFileParserException(ConfigFileParserError error, Exercise exercise, File file) { + this.error = error; + this.exercise = exercise; + this.file = file; + } - public ConfigFileParserError getError() { - return this.error; - } + public ConfigFileParserError getError() { + return this.error; + } - public Exercise getExercise() { - return this.exercise; - } + public Exercise getExercise() { + return this.exercise; + } - public File getFile() { - return this.file; - } - } + public File getFile() { + return this.file; + } + } - public enum ConfigFileParserError { - PARSING_FAILED, - NOT_ALLOWED; - } + public enum ConfigFileParserError { + PARSING_FAILED, NOT_ALLOWED; + } } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/output/FileWriter.java b/src/main/java/edu/kit/kastel/sdq/scorestats/output/FileWriter.java index 11d70fe..8f48cce 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/output/FileWriter.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/output/FileWriter.java @@ -13,19 +13,19 @@ */ public class FileWriter { - private static final String CHARSET = "UTF-8"; + private static final String CHARSET = "UTF-8"; - private Output output; - private File file; + private final Output output; + private final File file; - public FileWriter(Output output, File file) { - this.output = output; - this.file = file; - } + public FileWriter(Output output, File file) { + this.output = output; + this.file = file; + } - public void write() throws IOException { - BufferedWriter w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(this.file), CHARSET)); - w.write(this.output.print()); - w.close(); - } + public void write() throws IOException { + BufferedWriter w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(this.file), CHARSET)); + w.write(this.output.print()); + w.close(); + } } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/output/Output.java b/src/main/java/edu/kit/kastel/sdq/scorestats/output/Output.java index 663953f..91172c0 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/output/Output.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/output/Output.java @@ -7,17 +7,13 @@ */ public interface Output { - public static final String INDENTATION = " "; - public static final int INDENTATION_SIZE = 2; + String INDENTATION = " "; + int INDENTATION_SIZE = 2; - String print(); + String print(); - public static StringBuilder indent(StringBuilder builder, int indentationLevel) { - for (int i = 0; i < indentationLevel; i++) { - for (int j = 0; j < INDENTATION_SIZE; j++) { - builder.append(INDENTATION); - } - } - return builder; - } + static StringBuilder indent(StringBuilder builder, int indentationLevel) { + builder.append(INDENTATION.repeat(INDENTATION_SIZE).repeat(Math.max(0, indentationLevel))); + return builder; + } } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/output/layout/Divider.java b/src/main/java/edu/kit/kastel/sdq/scorestats/output/layout/Divider.java index 6802976..faee463 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/output/layout/Divider.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/output/layout/Divider.java @@ -9,26 +9,21 @@ */ public class Divider implements Output { - private static final int DEFAULT_WIDTH = 100; - private static final char CHARACTER = '-'; + private static final int DEFAULT_WIDTH = 100; + private static final char CHARACTER = '-'; - private final int width; + private final int width; - public Divider() { - this.width = DEFAULT_WIDTH; - } + public Divider() { + this.width = DEFAULT_WIDTH; + } - public Divider(int width) { - this.width = width; - } + public Divider(int width) { + this.width = width; + } - @Override - public String print() { - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < this.width; i++) { - builder.append(CHARACTER); - } - builder.append(System.lineSeparator()); - return builder.toString(); - } + @Override + public String print() { + return String.valueOf(CHARACTER).repeat(Math.max(0, this.width)) + System.lineSeparator(); + } } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/output/layout/Document.java b/src/main/java/edu/kit/kastel/sdq/scorestats/output/layout/Document.java index b64d0bc..32250e8 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/output/layout/Document.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/output/layout/Document.java @@ -13,29 +13,25 @@ */ public class Document implements Output { - private final List outputs; + private final List outputs; - public Document() { - this.outputs = new ArrayList<>(); - } + public Document(Output... outputs) { + this.outputs = new ArrayList<>(); + this.outputs.addAll(Arrays.asList(outputs)); + } - public Document(Output... outputs) { - this.outputs = new ArrayList<>(); - this.outputs.addAll(Arrays.asList(outputs)); - } + public void append(Output... output) { + this.outputs.addAll(Arrays.asList(output)); + } - public void append(Output... output) { - this.outputs.addAll(Arrays.asList(output)); - } + @Override + public String print() { + StringBuilder builder = new StringBuilder(); - @Override - public String print() { - StringBuilder builder = new StringBuilder(); + for (Output output : this.outputs) { + builder.append(output.print()); + } - for (Output output : this.outputs) { - builder.append(output.print()); - } - - return builder.toString(); - } + return builder.toString(); + } } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/output/layout/RightPad.java b/src/main/java/edu/kit/kastel/sdq/scorestats/output/layout/RightPad.java index 32172af..5b7f95f 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/output/layout/RightPad.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/output/layout/RightPad.java @@ -9,27 +9,25 @@ */ public class RightPad implements Output { - private final Output output; - private final int indentationLevel; - private final int width; + private final Output output; + private final int indentationLevel; + private final int width; - public RightPad(int indentationLevel, int width, Output output) { - this.indentationLevel = indentationLevel; - this.width = width; - this.output = output; - } + public RightPad(int indentationLevel, int width, Output output) { + this.indentationLevel = indentationLevel; + this.width = width; + this.output = output; + } - @Override - public String print() { - StringBuilder builder = new StringBuilder(); - Output.indent(builder, this.indentationLevel); + @Override + public String print() { + StringBuilder builder = new StringBuilder(); + Output.indent(builder, this.indentationLevel); - String s = this.output.print(); - builder.append(s); - int paddingWidth = this.width - s.length(); - for (int i = 0; i < paddingWidth; i++) { - builder.append(" "); - } - return builder.toString(); - } + String s = this.output.print(); + builder.append(s); + int paddingWidth = this.width - s.length(); + builder.append(" ".repeat(Math.max(0, paddingWidth))); + return builder.toString(); + } } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/output/ratio/PaddedPercentage.java b/src/main/java/edu/kit/kastel/sdq/scorestats/output/ratio/PaddedPercentage.java index 5df6ea7..015c818 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/output/ratio/PaddedPercentage.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/output/ratio/PaddedPercentage.java @@ -7,29 +7,25 @@ */ public class PaddedPercentage extends RatioOutput { - private static final int MAX_WIDTH = 4; + private static final int MAX_WIDTH = 4; - public PaddedPercentage(int numerator, int denominator) { - super(numerator, denominator, 0); - } + public PaddedPercentage(int numerator, int denominator) { + super(numerator, denominator, 0); + } - public PaddedPercentage(double numerator, int denominator) { - super(numerator, denominator, 0); - } + public PaddedPercentage(double numerator, int denominator) { + super(numerator, denominator, 0); + } - @Override - public String print() { - String output; - if (this.denominator < 1) { - output = "- %"; - } else { - output = Math.round(this.numerator / this.denominator * 100) + "%"; - } - int paddingWidth = MAX_WIDTH - output.length(); - String padding = ""; - for (int i = 0; i < paddingWidth; i++) { - padding += " "; - } - return output + padding; - } + @Override + public String print() { + String output; + if (this.denominator < 1) { + output = "- %"; + } else { + output = Math.round(this.numerator / this.denominator * 100) + "%"; + } + int paddingWidth = MAX_WIDTH - output.length(); + return output + " ".repeat(Math.max(0, paddingWidth)); + } } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/output/ratio/RatioOutput.java b/src/main/java/edu/kit/kastel/sdq/scorestats/output/ratio/RatioOutput.java index e3d4383..572974b 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/output/ratio/RatioOutput.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/output/ratio/RatioOutput.java @@ -9,32 +9,31 @@ */ public abstract class RatioOutput implements Output { - protected final double numerator; - protected final double denominator; - - protected int decimalPlaces; - - public RatioOutput(int numerator, int denominator) { - this.numerator = numerator; - this.denominator = denominator; - this.decimalPlaces = 0; - } - - public RatioOutput(double numerator, int denominator) { - this.numerator = numerator; - this.denominator = denominator; - this.decimalPlaces = 1; - } - - public RatioOutput(double numerator, int denominator, int decimalPlaces) { - this.numerator = numerator; - this.denominator = denominator; - this.decimalPlaces = decimalPlaces; - } - - public void setDecimalPlaces(int decimalPlaces) { - this.decimalPlaces = decimalPlaces; - } - - public abstract String print(); + protected final double numerator; + protected final double denominator; + + protected int decimalPlaces; + + protected RatioOutput(int numerator, int denominator) { + this.numerator = numerator; + this.denominator = denominator; + this.decimalPlaces = 0; + } + + protected RatioOutput(double numerator, int denominator) { + this.numerator = numerator; + this.denominator = denominator; + this.decimalPlaces = 1; + } + + protected RatioOutput(double numerator, int denominator, int decimalPlaces) { + this.numerator = numerator; + this.denominator = denominator; + this.decimalPlaces = decimalPlaces; + } + + public void setDecimalPlaces(int decimalPlaces) { + this.decimalPlaces = decimalPlaces; + } + } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/output/ratio/RatioRow.java b/src/main/java/edu/kit/kastel/sdq/scorestats/output/ratio/RatioRow.java index 8f72aa1..eb53f27 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/output/ratio/RatioRow.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/output/ratio/RatioRow.java @@ -9,34 +9,32 @@ */ public class RatioRow implements Output { - private static final String DELIMITER = " "; - - private PercentageBar percentageBar; - private PaddedPercentage paddedPercentage; - private SimpleRatio simpleRatio; - - public RatioRow(int numerator, int denominator) { - this.percentageBar = new PercentageBar(numerator, denominator); - this.paddedPercentage = new PaddedPercentage(numerator, denominator); - this.simpleRatio = new SimpleRatio(numerator, denominator); - } - - public RatioRow(double numerator, int denominator) { - this.percentageBar = new PercentageBar(numerator, denominator); - this.paddedPercentage = new PaddedPercentage(numerator, denominator); - this.simpleRatio = new SimpleRatio(numerator, denominator); - } - - public RatioRow(double numerator, int denominator, int decimalPlaces) { - this.percentageBar = new PercentageBar(numerator, denominator); - this.paddedPercentage = new PaddedPercentage(numerator, denominator); - this.simpleRatio = new SimpleRatio(numerator, denominator, decimalPlaces); - } - - @Override - public String print() { - return this.percentageBar.print() + DELIMITER + - this.paddedPercentage.print() + DELIMITER + - this.simpleRatio.print(); - } + private static final String DELIMITER = " "; + + private final PercentageBar percentageBar; + private final PaddedPercentage paddedPercentage; + private final SimpleRatio simpleRatio; + + public RatioRow(int numerator, int denominator) { + this.percentageBar = new PercentageBar(numerator, denominator); + this.paddedPercentage = new PaddedPercentage(numerator, denominator); + this.simpleRatio = new SimpleRatio(numerator, denominator); + } + + public RatioRow(double numerator, int denominator) { + this.percentageBar = new PercentageBar(numerator, denominator); + this.paddedPercentage = new PaddedPercentage(numerator, denominator); + this.simpleRatio = new SimpleRatio(numerator, denominator); + } + + public RatioRow(double numerator, int denominator, int decimalPlaces) { + this.percentageBar = new PercentageBar(numerator, denominator); + this.paddedPercentage = new PaddedPercentage(numerator, denominator); + this.simpleRatio = new SimpleRatio(numerator, denominator, decimalPlaces); + } + + @Override + public String print() { + return this.percentageBar.print() + DELIMITER + this.paddedPercentage.print() + DELIMITER + this.simpleRatio.print(); + } } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/output/report/CustomPenaltyList.java b/src/main/java/edu/kit/kastel/sdq/scorestats/output/report/CustomPenaltyList.java index 094bf62..056d9f2 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/output/report/CustomPenaltyList.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/output/report/CustomPenaltyList.java @@ -1,7 +1,6 @@ /* Licensed under EPL-2.0 2023. */ package edu.kit.kastel.sdq.scorestats.output.report; -import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Locale; @@ -15,40 +14,36 @@ */ public class CustomPenaltyList implements Output { - private static final String FORMAT = "%.1fP %s"; - - private final List annotations; - private final int itemsCount; - private final int indentationLevel; - - public CustomPenaltyList(int indentationLevel, List annotations) { - this.annotations = annotations; - this.itemsCount = annotations.size(); - this.indentationLevel = indentationLevel; - } - - public CustomPenaltyList(int indentationLevel, List annotations, int itemsCount) { - this.annotations = annotations; - this.itemsCount = itemsCount; - this.indentationLevel = indentationLevel; - } - - @Override - public String print() { - Collections.sort(this.annotations, - Comparator - .comparing((IAnnotation a) -> a.getCustomPenalty().get()) - .thenComparing((IAnnotation a) -> a.getCustomMessage().get())); - - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < this.itemsCount && i < this.annotations.size(); i++) { - IAnnotation annotation = this.annotations.get(i); - Output.indent(builder, this.indentationLevel); - builder.append(String.format(Locale.US, FORMAT, annotation.getCustomPenalty().get(), - annotation.getCustomMessage().get())); - builder.append(System.lineSeparator()); - } - return builder.toString(); - } + private static final String FORMAT = "%.1fP %s"; + + private final List annotations; + private final int itemsCount; + private final int indentationLevel; + + public CustomPenaltyList(int indentationLevel, List annotations) { + this.annotations = annotations; + this.itemsCount = annotations.size(); + this.indentationLevel = indentationLevel; + } + + public CustomPenaltyList(int indentationLevel, List annotations, int itemsCount) { + this.annotations = annotations; + this.itemsCount = itemsCount; + this.indentationLevel = indentationLevel; + } + + @Override + public String print() { + this.annotations.sort(Comparator.comparing((IAnnotation a) -> a.getCustomPenalty().get()).thenComparing((IAnnotation a) -> a.getCustomMessage().get())); + + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < this.itemsCount && i < this.annotations.size(); i++) { + IAnnotation annotation = this.annotations.get(i); + Output.indent(builder, this.indentationLevel); + builder.append(String.format(Locale.US, FORMAT, annotation.getCustomPenalty().get(), annotation.getCustomMessage().get())); + builder.append(System.lineSeparator()); + } + return builder.toString(); + } } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/output/report/FrequencyList.java b/src/main/java/edu/kit/kastel/sdq/scorestats/output/report/FrequencyList.java index 25528dd..bf7169b 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/output/report/FrequencyList.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/output/report/FrequencyList.java @@ -2,7 +2,6 @@ package edu.kit.kastel.sdq.scorestats.output.report; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; @@ -19,48 +18,45 @@ */ public abstract class FrequencyList implements Output { - private final FrequencyResult result; - private final int itemsCount; - private final int indentationLevel; - - public FrequencyList(int indentationLevel, FrequencyResult result) { - this.result = result; - this.itemsCount = result.values().size(); - this.indentationLevel = indentationLevel; - } - - public FrequencyList(int indentationLevel, FrequencyResult result, int itemsCount) { - this.result = result; - this.itemsCount = itemsCount == 0 ? result.values().size() : itemsCount; - this.indentationLevel = indentationLevel; - } - - @Override - public String print() { - List> items = this.getItems(); - int n = this.result.n(); - - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < this.itemsCount && i < items.size(); i++) { - U item = items.get(i).getKey(); - int count = items.get(i).getValue(); - - RightPad padding = new RightPad( - this.indentationLevel, - ReportOutput.COLUMN_WIDTH, - new RatioRow(count, n)); - - builder.append(padding.print() + this.getLabel(item) + System.lineSeparator()); - } - return builder.toString(); - } - - private List> getItems() { - List> items = new ArrayList<>(this.result.values().entrySet()); - Collections.sort(items, Comparator.comparing(Map.Entry::getValue).reversed()); - return items; - } - - protected abstract String getLabel(U item); + private final FrequencyResult result; + private final int itemsCount; + private final int indentationLevel; + + public FrequencyList(int indentationLevel, FrequencyResult result) { + this.result = result; + this.itemsCount = result.values().size(); + this.indentationLevel = indentationLevel; + } + + public FrequencyList(int indentationLevel, FrequencyResult result, int itemsCount) { + this.result = result; + this.itemsCount = itemsCount == 0 ? result.values().size() : itemsCount; + this.indentationLevel = indentationLevel; + } + + @Override + public String print() { + List> items = this.getItems(); + int n = this.result.n(); + + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < this.itemsCount && i < items.size(); i++) { + U item = items.get(i).getKey(); + int count = items.get(i).getValue(); + + RightPad padding = new RightPad(this.indentationLevel, ReportOutput.COLUMN_WIDTH, new RatioRow(count, n)); + + builder.append(padding.print()).append(this.getLabel(item)).append(System.lineSeparator()); + } + return builder.toString(); + } + + private List> getItems() { + List> items = new ArrayList<>(this.result.values().entrySet()); + items.sort(Comparator.comparing(Map.Entry::getValue).reversed()); + return items; + } + + protected abstract String getLabel(U item); } diff --git a/src/main/java/edu/kit/kastel/sdq/scorestats/output/report/MistakeTypeFrequencyList.java b/src/main/java/edu/kit/kastel/sdq/scorestats/output/report/MistakeTypeFrequencyList.java index 8208e44..1dd5607 100644 --- a/src/main/java/edu/kit/kastel/sdq/scorestats/output/report/MistakeTypeFrequencyList.java +++ b/src/main/java/edu/kit/kastel/sdq/scorestats/output/report/MistakeTypeFrequencyList.java @@ -10,18 +10,14 @@ */ public class MistakeTypeFrequencyList extends FrequencyList { - private static final String FORMAT = "%s [%s]"; + private static final String FORMAT = "%s [%s]"; - public MistakeTypeFrequencyList(int indentationLevel, FrequencyResult result) { - super(indentationLevel, result); - } + public MistakeTypeFrequencyList(int indentationLevel, FrequencyResult result, int itemsCount) { + super(indentationLevel, result, itemsCount); + } - public MistakeTypeFrequencyList(int indentationLevel, FrequencyResult result, int itemsCount) { - super(indentationLevel, result, itemsCount); - } - - @Override - protected String getLabel(IMistakeType item) { - return FORMAT.formatted(item.getButtonText(null), item.getIdentifier()); - } + @Override + protected String getLabel(IMistakeType item) { + return FORMAT.formatted(item.getButtonText(null), item.getIdentifier()); + } }