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